diff --git a/src/shared/shl_dlist.h b/src/shared/shl_dlist.h new file mode 100644 index 0000000..53b29f9 --- /dev/null +++ b/src/shared/shl_dlist.h @@ -0,0 +1,129 @@ +/* + * shl - Double Linked List + * + * Copyright (c) 2011-2012 David Herrmann + * Copyright (c) 2011 University of Tuebingen + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * A simple double linked list implementation + */ + +#ifndef SHL_DLIST_H +#define SHL_DLIST_H + +#include +#include +#include +#include + +/* miscellaneous */ + +#define shl_offsetof(pointer, type, member) \ + ({ \ + const typeof(((type *)0)->member) *__ptr = (pointer); \ + (type *)(((char *)__ptr) - offsetof(type, member)); \ + }) + +/* double linked list */ + +struct shl_dlist { + struct shl_dlist *next; + struct shl_dlist *prev; +}; + +#define SHL_DLIST_INIT(head) {&(head), &(head)} + +static inline void shl_dlist_init(struct shl_dlist *list) +{ + list->next = list; + list->prev = list; +} + +static inline void shl_dlist__link(struct shl_dlist *prev, struct shl_dlist *next, + struct shl_dlist *n) +{ + next->prev = n; + n->next = next; + n->prev = prev; + prev->next = n; +} + +static inline void shl_dlist_link(struct shl_dlist *head, struct shl_dlist *n) +{ + return shl_dlist__link(head, head->next, n); +} + +static inline void shl_dlist_link_tail(struct shl_dlist *head, struct shl_dlist *n) +{ + return shl_dlist__link(head->prev, head, n); +} + +static inline void shl_dlist__unlink(struct shl_dlist *prev, struct shl_dlist *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void shl_dlist_unlink(struct shl_dlist *e) +{ + shl_dlist__unlink(e->prev, e->next); + e->prev = NULL; + e->next = NULL; +} + +static inline bool shl_dlist_empty(struct shl_dlist *head) +{ + return head->next == head; +} + +#define shl_dlist_entry(ptr, type, member) shl_offsetof((ptr), type, member) + +#define shl_dlist_first(head, type, member) shl_dlist_entry((head)->next, type, member) + +#define shl_dlist_last(head, type, member) shl_dlist_entry((head)->prev, type, member) + +#define shl_dlist_next(iter, head, member) \ + ((iter)->member.next == (head) ? NULL : shl_dlist_entry((iter)->member.next, typeof(*iter), list)) + +#define shl_dlist_for_each(iter, head) for (iter = (head)->next; iter != (head); iter = iter->next) + +#define shl_dlist_for_each_but_one(iter, start, head) \ + for (iter = ((start)->next == (head)) ? (start)->next->next : (start)->next; \ + iter != (start); \ + iter = (iter->next == (head) && (start) != (head)) ? iter->next->next : iter->next) + +#define shl_dlist_for_each_safe(iter, tmp, head) \ + for (iter = (head)->next, tmp = iter->next; iter != (head); iter = tmp, tmp = iter->next) + +#define shl_dlist_for_each_reverse(iter, head) \ + for (iter = (head)->prev; iter != (head); iter = iter->prev) + +#define shl_dlist_for_each_reverse_but_one(iter, start, head) \ + for (iter = ((start)->prev == (head)) ? (start)->prev->prev : (start)->prev; \ + iter != (start); \ + iter = (iter->prev == (head) && (start) != (head)) ? iter->prev->prev : iter->prev) + +#define shl_dlist_for_each_reverse_safe(iter, tmp, head) \ + for (iter = (head)->prev, tmp = iter->prev; iter != (head); iter = tmp, tmp = iter->prev) + +#endif /* SHL_DLIST_H */ diff --git a/src/tsm/libtsm-int.h b/src/tsm/libtsm-int.h index 668ba4a..f167158 100644 --- a/src/tsm/libtsm-int.h +++ b/src/tsm/libtsm-int.h @@ -32,6 +32,7 @@ #include #include #include "libtsm.h" +#include "shl_dlist.h" #include "shl-llog.h" #define SHL_EXPORT __attribute__((visibility("default"))) @@ -87,20 +88,26 @@ struct cell { }; struct line { - struct line *next; /* next line (NULL if not sb) */ - struct line *prev; /* prev line (NULL if not sb) */ - + struct shl_dlist list; /* list node, next/prev are NULL if not in sb */ unsigned int size; /* real width */ struct cell *cells; /* actuall cells */ - uint64_t sb_id; /* sb ID */ + uint64_t sb_id; /* sb ID, 0 if not in sb */ tsm_age_t age; /* age of the whole line */ }; -#define SELECTION_TOP -1 struct selection_pos { - struct line *line; - unsigned int x; - int y; + unsigned int x; /* x offset from the start of the line */ + struct line *line; /* line the selection is on */ +}; + +struct tsm_scrollback { + /* scroll-back buffer */ + unsigned int count; /* number of lines in sb */ + struct shl_dlist list; /* list of lines in sb */ + unsigned int max; /* max-limit of lines in sb */ + struct line *pos; /* current position in sb or NULL */ + unsigned int pos_num; /* current numeric position in sb */ + uint64_t last_id; /* last id given to sb-line */ }; struct tsm_screen { @@ -134,14 +141,7 @@ struct tsm_screen { struct line **alt_lines; /* real alternative lines */ tsm_age_t age; /* whole screen age */ - /* scroll-back buffer */ - unsigned int sb_count; /* number of lines in sb */ - struct line *sb_first; /* first line; was moved first */ - struct line *sb_last; /* last line; was moved last*/ - unsigned int sb_max; /* max-limit of lines in sb */ - struct line *sb_pos; /* current position in sb or NULL */ - unsigned int sb_pos_num; /* current numeric position in sb */ - uint64_t sb_last_id; /* last id given to sb-line */ + struct tsm_scrollback sb; /* cursor: positions are always in-bound, but cursor_x might be * bigger than size_x if new-line is pending */ @@ -172,6 +172,10 @@ static inline void screen_inc_age(struct tsm_screen *con) } } +static inline bool is_in_scrollback(struct selection_pos *sel) { + return (sel->line && sel->line->sb_id); +} + /* available character sets */ typedef tsm_symbol_t tsm_vte_charset[96]; diff --git a/src/tsm/tsm-render.c b/src/tsm/tsm-render.c index 88ad847..0429e7d 100644 --- a/src/tsm/tsm-render.c +++ b/src/tsm/tsm-render.c @@ -38,6 +38,7 @@ #include "libtsm.h" #include "libtsm-int.h" #include "shl-llog.h" +#include "shl_dlist.h" #define LLOG_SUBSYSTEM "tsm-render" @@ -47,7 +48,7 @@ tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, { unsigned int cur_x, cur_y; unsigned int i, j, k; - struct line *iter, *line = NULL; + struct line *line, *next_line = NULL; struct cell *cell, empty; struct tsm_screen_attr attr; int ret, warned = 0; @@ -71,47 +72,41 @@ tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, cur_y = con->size_y - 1; /* push each character into rendering pipeline */ - - iter = con->sb_pos; k = 0; + next_line = con->sb.pos; if (con->sel_active) { - if (!con->sel_start.line && con->sel_start.y == SELECTION_TOP) + if (!con->sel_start.line) in_sel = !in_sel; - if (!con->sel_end.line && con->sel_end.y == SELECTION_TOP) + if (!con->sel_end.line) in_sel = !in_sel; - if (con->sel_start.line && - (!iter || con->sel_start.line->sb_id < iter->sb_id)) + if (is_in_scrollback(&con->sel_start) && + (!con->sb.pos || con->sel_start.line->sb_id < con->sb.pos->sb_id)) in_sel = !in_sel; - if (con->sel_end.line && - (!iter || con->sel_end.line->sb_id < iter->sb_id)) + if (is_in_scrollback(&con->sel_end) && + (!con->sb.pos || con->sel_end.line->sb_id < con->sb.pos->sb_id)) in_sel = !in_sel; } for (i = 0; i < con->size_y; ++i) { - if (iter) { - line = iter; - iter = iter->next; + if (next_line) { + line = next_line; + next_line = shl_dlist_next(next_line, &con->sb.list, list); } else { line = con->lines[k]; k++; } if (con->sel_active) { - if (con->sel_start.line == line || - (!con->sel_start.line && - con->sel_start.y == k - 1)) + if (con->sel_start.line == line) sel_start = true; else sel_start = false; - if (con->sel_end.line == line || - (!con->sel_end.line && - con->sel_end.y == k - 1)) + if (con->sel_end.line == line) sel_end = true; else sel_end = false; - was_sel = false; } diff --git a/src/tsm/tsm-screen.c b/src/tsm/tsm-screen.c index 3c8dd7f..80f3686 100644 --- a/src/tsm/tsm-screen.c +++ b/src/tsm/tsm-screen.c @@ -64,6 +64,7 @@ #include "libtsm.h" #include "libtsm-int.h" #include "shl-llog.h" +#include "shl_dlist.h" #define LLOG_SUBSYSTEM "tsm-screen" @@ -110,7 +111,7 @@ static void move_cursor(struct tsm_screen *con, unsigned int x, unsigned int y) c->age = con->age_cnt; } -void screen_cell_init_generic(struct tsm_screen *con, struct cell *cell, struct tsm_screen_attr *attr) +static void screen_cell_init_generic(struct tsm_screen *con, struct cell *cell, struct tsm_screen_attr *attr) { cell->ch = 0; cell->width = 1; @@ -136,8 +137,9 @@ static int line_new(struct tsm_screen *con, struct line **out, line = malloc(sizeof(*line)); if (!line) return -ENOMEM; - line->next = NULL; - line->prev = NULL; + line->list.next = NULL; + line->list.prev = NULL; + line->sb_id = 0; line->size = width; line->age = con->age_cnt; @@ -184,6 +186,16 @@ static int line_resize(struct tsm_screen *con, struct line *line, return 0; } +static void clear_selection_on_line(struct tsm_screen *con, struct line *line) +{ + if (!con->sel_active) + return; + if (con->sel_start.line == line) + con->sel_start.line = NULL; + if (con->sel_end.line == line) + con->sel_end.line = NULL; +} + /* This links the given line into the scrollback-buffer */ static void link_to_scrollback(struct tsm_screen *con, struct line *line) { @@ -192,81 +204,34 @@ static void link_to_scrollback(struct tsm_screen *con, struct line *line) /* TODO: more sophisticated ageing */ con->age = con->age_cnt; - if (con->sb_max == 0) { - if (con->sel_active) { - if (con->sel_start.line == line) { - con->sel_start.line = NULL; - con->sel_start.y = SELECTION_TOP; - } - if (con->sel_end.line == line) { - con->sel_end.line = NULL; - con->sel_end.y = SELECTION_TOP; - } - } + if (con->sb.max == 0) { + clear_selection_on_line(con, line); line_free(line); return; } /* Remove a line from the scrollback buffer if it reaches its maximum. * We must take care to correctly keep the current position as the new - * line is linked in after we remove the top-most line here. - * sb_max == 0 is tested earlier so we can assume sb_max > 0 here. In - * other words, buf->sb_first is a valid line if sb_count >= sb_max. */ - if (con->sb_count >= con->sb_max) { - tmp = con->sb_first; - con->sb_first = tmp->next; - if (tmp->next) - tmp->next->prev = NULL; - else - con->sb_last = NULL; - --con->sb_count; - - /* (position == tmp && !next) means we have sb_max=1 so set - * position to the new line. Otherwise, set to new first line. - * If position!=tmp and we have a fixed-position then nothing - * needs to be done because we can stay at the same line. If we - * have no fixed-position, we need to set the position to the - * next inserted line, which can be "line", too. */ - if (con->sb_pos) { - if (con->sb_pos == tmp || - !(con->flags & TSM_SCREEN_FIXED_POS)) { - if (con->sb_pos->next) { - con->sb_pos = con->sb_pos->next; - ++con->sb_pos_num; - } else { - con->sb_pos = line; - con->sb_pos_num = 0; - } - } - } - - if (con->sel_active) { - if (con->sel_start.line == tmp) { - con->sel_start.line = NULL; - con->sel_start.y = SELECTION_TOP; - } - if (con->sel_end.line == tmp) { - con->sel_end.line = NULL; - con->sel_end.y = SELECTION_TOP; - } + * line is linked in after we remove the top-most line here. */ + if (con->sb.count >= con->sb.max) { + tmp = shl_dlist_first(&con->sb.list, struct line, list); + shl_dlist_unlink(&tmp->list); + --con->sb.count; + + /* Only consider sb.max > 1, so there is always another line in sb. */ + if (con->sb.pos == tmp) { + con->sb.pos = shl_dlist_first(&con->sb.list, struct line, list); + ++con->sb.pos_num; } + clear_selection_on_line(con, tmp); line_free(tmp); } - line->sb_id = ++con->sb_last_id; - line->next = NULL; - line->prev = con->sb_last; - if (con->sb_last) { - con->sb_last->next = line; - } else { - con->sb_first = line; - } - con->sb_last = line; - ++con->sb_count; - - if (con->sb_pos == NULL) { - con->sb_pos_num = con->sb_count; - } + line->sb_id = ++con->sb.last_id; + shl_dlist_link_tail(&con->sb.list, &line->list); + ++con->sb.count; + if (con->sb.pos == NULL) + con->sb.pos_num = con->sb.count; } /* Remove num lines from scroll back to current buffer */ @@ -277,33 +242,27 @@ static void remove_from_sb(struct tsm_screen *con, unsigned int num) /* TODO: more sophisticated ageing */ con->age = con->age_cnt; - if (!con->sb_max || !con->sb_count || !con->sb_last) + if (!con->sb.max || !con->sb.count || shl_dlist_empty(&con->sb.list)) return; - if (num > con->sb_count) - num = con->sb_count; + if (num > con->sb.count) + num = con->sb.count; while (num--) { - tmp = con->sb_last; - con->sb_last = tmp->prev; - - if (tmp->prev) - tmp->prev->next = NULL; - else - con->sb_first = NULL; - --con->sb_count; + tmp = shl_dlist_last(&con->sb.list, struct line, list); + shl_dlist_unlink(&tmp->list); + --con->sb.count; - tmp->next = NULL; - tmp->prev = NULL; - tmp->sb_id = 0; - - if (con->sb_pos == tmp) { - con->sb_pos_num = 0; - con->sb_pos = NULL; + if (con->sb.pos == tmp) { + con->sb.pos_num = con->sb.count; + con->sb.pos = NULL; } + tmp->sb_id = 0; memcpy(con->lines[num], tmp, sizeof(*tmp)); free(tmp); } + if (!con->sb.pos) + con->sb.pos_num = con->sb.count; } static void screen_scroll_up(struct tsm_screen *con, unsigned int num) @@ -356,27 +315,6 @@ static void screen_scroll_up(struct tsm_screen *con, unsigned int num) memcpy(&con->lines[con->margin_top + (max - num)], cache, num * sizeof(struct line*)); - - if (con->sel_active) { - if (!con->sel_start.line && con->sel_start.y >= 0) { - con->sel_start.y -= num; - if (con->sel_start.y < 0) { - con->sel_start.line = con->sb_last; - while (con->sel_start.line && ++con->sel_start.y < 0) - con->sel_start.line = con->sel_start.line->prev; - con->sel_start.y = SELECTION_TOP; - } - } - if (!con->sel_end.line && con->sel_end.y >= 0) { - con->sel_end.y -= num; - if (con->sel_end.y < 0) { - con->sel_end.line = con->sb_last; - while (con->sel_end.line && ++con->sel_end.y < 0) - con->sel_end.line = con->sel_end.line->prev; - con->sel_end.y = SELECTION_TOP; - } - } - } } static void screen_scroll_down(struct tsm_screen *con, unsigned int num) @@ -414,13 +352,6 @@ static void screen_scroll_down(struct tsm_screen *con, unsigned int num) memcpy(&con->lines[con->margin_top], cache, num * sizeof(struct line*)); - - if (con->sel_active) { - if (!con->sel_start.line && con->sel_start.y >= 0) - con->sel_start.y += num; - if (!con->sel_end.line && con->sel_end.y >= 0) - con->sel_end.y += num; - } } static void screen_write(struct tsm_screen *con, unsigned int x, @@ -510,6 +441,12 @@ static inline unsigned int to_abs_y(struct tsm_screen *con, unsigned int y) return con->margin_top + y; } +static void reset_scrollback_position(struct tsm_screen *con) +{ + con->sb.pos = NULL; + con->sb.pos_num = con->sb.count; +} + SHL_EXPORT int tsm_screen_new(struct tsm_screen **out, tsm_log_t log, void *log_data) { @@ -533,6 +470,7 @@ int tsm_screen_new(struct tsm_screen **out, tsm_log_t log, void *log_data) con->def_attr.fr = 255; con->def_attr.fg = 255; con->def_attr.fb = 255; + shl_dlist_init(&con->sb.list); ret = tsm_symbol_table_new(&con->sym_table); if (ret) @@ -578,17 +516,16 @@ void tsm_screen_unref(struct tsm_screen *con) return; llog_debug(con, "destroying screen"); + tsm_screen_clear_sb(con); for (i = 0; i < con->line_num; ++i) { line_free(con->main_lines[i]); line_free(con->alt_lines[i]); } - free(con->main_lines); free(con->alt_lines); free(con->tab_ruler); tsm_symbol_table_unref(con->sym_table); - tsm_screen_clear_sb(con); free(con); } @@ -767,7 +704,7 @@ int tsm_screen_resize(struct tsm_screen *con, unsigned int x, /* scroll buffer if screen height shrinks */ if (y < con->size_y) { diff = con->size_y - y; - if (!con->sb_last || (con->flags & TSM_SCREEN_ALTERNATE)) { + if (shl_dlist_empty(&con->sb.list) || (con->flags & TSM_SCREEN_ALTERNATE)) { /* If there is nothing in the scrollback buffer, * Only scroll up if the cursor would go off-screen */ if (con->cursor_y >= y) { @@ -784,8 +721,8 @@ int tsm_screen_resize(struct tsm_screen *con, unsigned int x, } } else if (y > con->size_y) { diff = y - con->size_y; - if (diff > con->sb_count) - diff = con->sb_count; + if (diff > con->sb.count) + diff = con->sb.count; /* * When increasing the terminal number of rows, we can move some * lines from the scrollback buffer to the main buffer. @@ -835,7 +772,7 @@ int tsm_screen_set_margins(struct tsm_screen *con, return 0; } -/* set maximum scrollback buffer size */ +/* set maximum scrollback buffer size in number of lines*/ SHL_EXPORT void tsm_screen_set_max_sb(struct tsm_screen *con, unsigned int max) @@ -845,45 +782,37 @@ void tsm_screen_set_max_sb(struct tsm_screen *con, if (!con) return; + // Don't allow only one line in the scrollback buffer, this simplifies + // the code, and is not a useful usecase. + if (max == 1) + max = 2; + screen_inc_age(con); /* TODO: more sophisticated ageing */ con->age = con->age_cnt; - while (con->sb_count > max) { - line = con->sb_first; - con->sb_first = line->next; - if (line->next) - line->next->prev = NULL; - else - con->sb_last = NULL; - con->sb_count--; + while (con->sb.count > max) { + line = shl_dlist_first(&con->sb.list, struct line, list); + shl_dlist_unlink(&line->list); + --con->sb.count; /* We treat fixed/unfixed position the same here because we * remove lines from the TOP of the scrollback buffer. */ - if (con->sb_pos == line) - con->sb_pos = con->sb_first; + if (con->sb.pos == line) + con->sb.pos = shl_dlist_first(&con->sb.list, struct line, list); - if (con->sel_active) { - if (con->sel_start.line == line) { - con->sel_start.line = NULL; - con->sel_start.y = SELECTION_TOP; - } - if (con->sel_end.line == line) { - con->sel_end.line = NULL; - con->sel_end.y = SELECTION_TOP; - } - } + clear_selection_on_line(con, line); line_free(line); } - - con->sb_max = max; + con->sb.max = max; } /* clear scrollback buffer */ SHL_EXPORT void tsm_screen_clear_sb(struct tsm_screen *con) { - struct line *iter, *tmp; + struct shl_dlist *iter, *safe; + struct line *tmp; if (!con) return; @@ -892,28 +821,20 @@ void tsm_screen_clear_sb(struct tsm_screen *con) /* TODO: more sophisticated ageing */ con->age = con->age_cnt; - for (iter = con->sb_first; iter; ) { - tmp = iter; - iter = iter->next; - line_free(tmp); - } - - con->sb_first = NULL; - con->sb_last = NULL; - con->sb_count = 0; - con->sb_pos = NULL; - con->sb_pos_num = 0; - if (con->sel_active) { - if (con->sel_start.line) { + if (con->sel_start.line && is_in_scrollback(&con->sel_start)) con->sel_start.line = NULL; - con->sel_start.y = SELECTION_TOP; - } - if (con->sel_end.line) { + if (con->sel_end.line && is_in_scrollback(&con->sel_end)) con->sel_end.line = NULL; - con->sel_end.y = SELECTION_TOP; - } } + shl_dlist_for_each_safe(iter, safe, &con->sb.list) { + tmp = shl_dlist_entry(iter, struct line, list); + shl_dlist_unlink(&tmp->list); + line_free(tmp); + } + con->sb.count = 0; + con->sb.pos = NULL; + con->sb.pos_num = 0; } SHL_EXPORT @@ -926,18 +847,19 @@ void tsm_screen_sb_up(struct tsm_screen *con, unsigned int num) /* TODO: more sophisticated ageing */ con->age = con->age_cnt; + if (shl_dlist_empty(&con->sb.list)) + return; + while (num--) { - if (con->sb_pos) { - if (!con->sb_pos->prev) + if (con->sb.pos) { + if (con->sb.pos_num == 0) return; - con->sb_pos = con->sb_pos->prev; - --con->sb_pos_num; - } else if (!con->sb_last) { - return; + con->sb.pos = shl_dlist_last(&con->sb.pos->list, struct line, list); + --con->sb.pos_num; } else { - con->sb_pos = con->sb_last; - con->sb_pos_num = con->sb_count - 1; + con->sb.pos = shl_dlist_last(&con->sb.list, struct line, list); + con->sb.pos_num = con->sb.count - 1; } } } @@ -952,14 +874,12 @@ void tsm_screen_sb_down(struct tsm_screen *con, unsigned int num) /* TODO: more sophisticated ageing */ con->age = con->age_cnt; - while (num--) { - if (con->sb_pos) { - con->sb_pos = con->sb_pos->next; - ++con->sb_pos_num; - } - else - return; + while (num-- && con->sb.pos && con->sb.pos_num < con->sb.count) { + con->sb.pos = shl_dlist_next(con->sb.pos, &con->sb.list, list); + ++con->sb.pos_num; } + if (con->sb.pos_num == con->sb.count) + con->sb.pos = NULL; } SHL_EXPORT @@ -985,15 +905,15 @@ void tsm_screen_sb_page_down(struct tsm_screen *con, unsigned int num) SHL_EXPORT void tsm_screen_sb_reset(struct tsm_screen *con) { - if (!con || !con->sb_pos) + if (!con || !con->sb.pos) return; screen_inc_age(con); /* TODO: more sophisticated ageing */ con->age = con->age_cnt; - con->sb_pos = NULL; - con->sb_pos_num = con->sb_count; + con->sb.pos = NULL; + con->sb.pos_num = con->sb.count; } unsigned int tsm_screen_sb_get_line_count(struct tsm_screen *con) @@ -1002,7 +922,7 @@ unsigned int tsm_screen_sb_get_line_count(struct tsm_screen *con) return 0; } - return con->sb_count; + return con->sb.count; } unsigned int tsm_screen_sb_get_line_pos(struct tsm_screen *con) @@ -1011,7 +931,7 @@ unsigned int tsm_screen_sb_get_line_pos(struct tsm_screen *con) return 0; } - return con->sb_pos_num; + return con->sb.pos_num; } SHL_EXPORT @@ -1045,6 +965,8 @@ void tsm_screen_reset(struct tsm_screen *con) else con->tab_ruler[i] = false; } + tsm_screen_selection_reset(con); + reset_scrollback_position(con); } SHL_EXPORT @@ -1064,6 +986,8 @@ void tsm_screen_set_flags(struct tsm_screen *con, unsigned int flags) if (!(old & TSM_SCREEN_ALTERNATE) && (flags & TSM_SCREEN_ALTERNATE)) { con->age = con->age_cnt; con->lines = con->alt_lines; + tsm_screen_selection_reset(con); + reset_scrollback_position(con); /* save attributes of main screen when we switch to alt screen */ memcpy(&con->def_attr_main, &con->def_attr, sizeof(con->def_attr)); @@ -1096,6 +1020,8 @@ void tsm_screen_reset_flags(struct tsm_screen *con, unsigned int flags) if ((old & TSM_SCREEN_ALTERNATE) && (flags & TSM_SCREEN_ALTERNATE)) { con->age = con->age_cnt; con->lines = con->main_lines; + tsm_screen_selection_reset(con); + reset_scrollback_position(con); } if ((old & TSM_SCREEN_HIDE_CURSOR) && diff --git a/src/tsm/tsm-selection.c b/src/tsm/tsm-selection.c index 26047c7..51c70e6 100644 --- a/src/tsm/tsm-selection.c +++ b/src/tsm/tsm-selection.c @@ -58,27 +58,30 @@ #include "libtsm.h" #include "libtsm-int.h" #include "shl-llog.h" +#include "shl_dlist.h" #define LLOG_SUBSYSTEM "tsm-selection" static void selection_set(struct tsm_screen *con, struct selection_pos *sel, unsigned int x, unsigned int y) { - struct line *pos; + struct line *line; - sel->line = NULL; - pos = con->sb_pos; + sel->x = x; - while (y && pos) { - --y; - pos = pos->next; + if (!con->sb.pos) { + sel->line = con->lines[y]; + return; } - - if (pos) - sel->line = pos; - - sel->x = x; - sel->y = y; + if (con->sb.pos_num + y >= con->sb.count) { + y -= con->sb.count - con->sb.pos_num; + sel->line = con->lines[y]; + return; + } + line = con->sb.pos; + while (y--) + line = shl_dlist_next(line, &con->sb.list, list); + sel->line = line; } static void word_select(struct tsm_screen *con, @@ -90,10 +93,7 @@ static void word_select(struct tsm_screen *con, selection_set(con, &con->sel_start, posx, posy); - if (con->sel_start.line) - line = con->sel_start.line; - else - line = con->lines[con->sel_start.y]; + line = con->sel_start.line; if (!line || line->cells[posx].ch == ' ') return; @@ -115,7 +115,8 @@ static void word_select(struct tsm_screen *con, } } con->sel_start.x = start; - selection_set(con, &con->sel_end, end, posy); + con->sel_end.x = end; + con->sel_end.line = line; con->sel_active = true; } @@ -130,110 +131,57 @@ void tsm_screen_selection_reset(struct tsm_screen *con) con->age = con->age_cnt; con->sel_active = false; -} - -SHL_EXPORT -void tsm_screen_selection_start(struct tsm_screen *con, - unsigned int posx, - unsigned int posy) -{ - if (!con) - return; - - screen_inc_age(con); - /* TODO: more sophisticated ageing */ - con->age = con->age_cnt; - - con->sel_active = true; - selection_set(con, &con->sel_start, posx, posy); - memcpy(&con->sel_end, &con->sel_start, sizeof(con->sel_end)); -} - -SHL_EXPORT -void tsm_screen_selection_target(struct tsm_screen *con, - unsigned int posx, - unsigned int posy) -{ - if (!con || !con->sel_active) - return; - - screen_inc_age(con); - /* TODO: more sophisticated ageing */ - con->age = con->age_cnt; - - selection_set(con, &con->sel_end, posx, posy); -} - -SHL_EXPORT -void tsm_screen_selection_word(struct tsm_screen *con, - unsigned int posx, - unsigned int posy) -{ - if (!con) - return; - - screen_inc_age(con); - /* TODO: more sophisticated ageing */ - con->age = con->age_cnt; - - word_select(con, posx, posy); + con->sel_start.line = NULL; + con->sel_end.line = NULL; } /* calculates the line length from the beginning to the last non zero character */ static unsigned int calc_line_len(struct line *line) { - unsigned int line_len = 0; int i; - for (i = 0; i < line->size; i++) { - if (line->cells[i].ch != 0) { - line_len = i + 1; - } - } - - return line_len; + for (i = line->size - 1; i >= 0; i--) + if (line->cells[i].ch != 0) + return i + 1; + return 0; } /* TODO: tsm_ucs4_to_utf8 expects UCS4 characters, but a cell contains a * tsm-symbol (which can contain multiple UCS4 chars). Fix this when introducing * support for combining characters. */ -static unsigned int copy_line(struct line *line, char *buf, - unsigned int start, unsigned int len) +static unsigned int copy_line(struct tsm_screen *con, struct line *line, char *buf) { - unsigned int i, end; + unsigned int i, start, end; char *pos = buf; int line_len; line_len = calc_line_len(line); - if (start > line_len) { - return 0; - } + start = (con->sel_start.line == line) ? con->sel_start.x : 0; + end = (con->sel_end.line == line) ? con->sel_end.x + 1 : con->size_x; - end = start + len; + if (start > line_len) + return 0; - if (end > line_len) { + if (end > line_len) end = line_len; - } - for (i = start; i < line->size && i < end; ++i) { - if (i < line->size || !line->cells[i].ch) + for (i = start; i < end; i++) { + if (line->cells[i].ch) pos += tsm_ucs4_to_utf8(line->cells[i].ch, pos); else pos += tsm_ucs4_to_utf8(' ', pos); } - pos += tsm_ucs4_to_utf8('\n', pos); - return pos - buf; } -static void swap_selections(struct selection_pos **a, struct selection_pos **b) +static void swap_selections(struct tsm_screen *con) { - struct selection_pos *c; + struct selection_pos c; - c = *a; - *a = *b; - *b = c; + c = con->sel_start; + con->sel_start = con->sel_end; + con->sel_end = c; } /* @@ -241,158 +189,141 @@ static void swap_selections(struct selection_pos **a, struct selection_pos **b) * * Start must always point to the top left and end to the bottom right cell */ -static void norm_selection(struct tsm_screen *con, struct selection_pos **start, struct selection_pos **end) +static void norm_selection(struct tsm_screen *con) { - struct line *iter; + int i; + struct selection_pos *start, *end; - if ((*end)->line == NULL && (*end)->y == SELECTION_TOP) { - swap_selections(start, end); + start = &con->sel_start; + end = &con->sel_end; + if (start->line == end->line) { + if (con->sel_start.x > con->sel_end.x) + swap_selections(con); return; } - if ((*start)->line && (*end)->line) { - /* single line selection */ - if ((*start)->line == (*end)->line) { - if ((*start)->x > (*end)->x) { - swap_selections(start, end); - } - - return; - } - - /* - * multi line selection - * - * search from end->line to con->sb_last - * if we find start->line on the way we - * need to change start and end - */ - iter = (*end)->line; - while (iter && iter != con->sb_last) { - if (iter == (*start)->line) { - swap_selections(start, end); - } - - iter = iter->next; - } - + if (is_in_scrollback(&con->sel_start) != is_in_scrollback(&con->sel_end)) { + if (is_in_scrollback(&con->sel_end)) + swap_selections(con); return; } - /* end is in scroll back buffer and start on screen */ - if (!(*start)->line && (*end)->line) { - swap_selections(start, end); + if (is_in_scrollback(&con->sel_start) && is_in_scrollback(&con->sel_end)) { + if (con->sel_start.line->sb_id > con->sel_end.line->sb_id) + swap_selections(con); return; } - /* reorder one-line selection if selection was created right to left */ - if ((*start)->y == (*end)->y) { - if ((*start)->x > (*end)->x) { - swap_selections(start, end); + /* so both are not in scroll back buffer and can't be equal */ + for (i = 0; i < con->size_y; i++) { + if (con->lines[i] == con->sel_end.line) { + swap_selections(con); + return; } + if (con->lines[i] == con->sel_start.line) + return; + } +} +SHL_EXPORT +void tsm_screen_selection_start(struct tsm_screen *con, + unsigned int posx, + unsigned int posy) +{ + if (!con || posx >= con->size_x || posy >= con->size_y) return; - } - /* reorder multi-line selection if selection was created bottom to top */ - if ((*start)->y > (*end)->y) { - swap_selections(start, end); - } + screen_inc_age(con); + /* TODO: more sophisticated ageing */ + con->age = con->age_cnt; + + con->sel_active = true; + selection_set(con, &con->sel_start, posx, posy); + memcpy(&con->sel_end, &con->sel_start, sizeof(con->sel_end)); } -/* - * Counts the lines a normalized selection selects on the scroll back buffer - * - * Does not count the lines selected on the screen - */ -static int selection_count_lines_sb(struct tsm_screen *con, struct selection_pos *start, struct selection_pos *end) +SHL_EXPORT +void tsm_screen_selection_target(struct tsm_screen *con, + unsigned int posx, + unsigned int posy) { - struct line *iter; - int count = 0; + if (!con || !con->sel_active || posx >= con->size_x || posy >= con->size_y) + return; - /* Single line selection */ - if (start->line && (start->line == end->line)) { - return 1; - } + screen_inc_age(con); + /* TODO: more sophisticated ageing */ + con->age = con->age_cnt; - iter = start->line; - while (iter) { - count++; + selection_set(con, &con->sel_end, posx, posy); + /* always normalize the selection */ + norm_selection(con); +} - if (iter == con->sb_last) { - break; - } +SHL_EXPORT +void tsm_screen_selection_word(struct tsm_screen *con, + unsigned int posx, + unsigned int posy) +{ + if (!con || posx >= con->size_x || posy >= con->size_y) + return; - iter = iter->next; - } + screen_inc_age(con); + /* TODO: more sophisticated ageing */ + con->age = con->age_cnt; - return count; + word_select(con, posx, posy); } /* - * Counts the lines a normalized selection selects on the screen + * Get the index of a line in the screen * - * Does not count the lines selected in the scroll back buffer + * If the line is in the scroll back buffer, return 0 + * Otherwise, return the index of the line in the screen */ -static int selection_count_lines(struct selection_pos *start, struct selection_pos *end) +static unsigned int get_line_index(struct tsm_screen *con, struct line *line) { - /* Selection only spans lines of the scroll back buffer */ - if (start->line && end->line) { + unsigned int i = 0; + + if (line->sb_id) return 0; - } - return end->y - start->y + 1; + for (i = 0; i < con->size_y; i++) { + if (con->lines[i] == line) + return i; + } + return 0; } -/* - * Calculate the number of selected cells in a line - */ -static int calc_selection_line_len_sb(struct tsm_screen *con, struct selection_pos *start, struct selection_pos *end, struct line *line) +static struct line *get_next_line(struct tsm_screen *con, struct line *line, unsigned int *index) { - /* one-line selection */ - if (start->line == end->line) { - return end->x - start->x + 1; - } - - /* first line of a multi-line selection */ - if (line == start->line) { - return con->size_x - start->x; - } - - /* last line of a multi-line selection */ - if (line == end->line) { - return end->x + 1; + struct line *next; + + if (line->sb_id) { + next = shl_dlist_next(line, &con->sb.list, list); + if (next) + return next; + *index = 0; + return con->lines[0]; + } else if (*index < con->size_y) { + (*index)++; + return con->lines[*index]; } - - /* every other selection */ - return con->size_x; + return NULL; } -/* - * Calculate the number of selected cells in a line - */ -static int calc_selection_line_len(struct tsm_screen *con, struct selection_pos *start, struct selection_pos *end, int line_num) +static int selection_count_lines(struct tsm_screen *con, struct selection_pos *start, struct selection_pos *end) { - if (!start->line) { - /* one-line selection */ - if (start->y == end->y) { - return end->x - start->x + 1; - } - - /* first line of a multi-line selection */ - if (line_num == start->y) { - return con->size_x - start->x; - } - } + int count = 1; + unsigned int index = get_line_index(con, start->line); + struct line *iter; - /* last line of a multi-line selection */ - if (line_num == end->y) { - return end->x + 1; + iter = start->line; + while (iter && iter != end->line) { + count++; + iter = get_next_line(con, iter, &index); } - - /* every other selection */ - return con->size_x; + return count; } /* @@ -404,69 +335,26 @@ static unsigned int calc_line_copy_buffer(struct tsm_screen *con, unsigned int n return con->size_x * num_lines * 4 + 1; } -/* - * Copy all selected lines from the scroll back buffer - */ -static int copy_lines_sb(struct tsm_screen *con, struct selection_pos *start, struct selection_pos *end, char *buf, int pos) +static int copy_lines(struct tsm_screen *con, struct selection_pos *start, struct selection_pos *end, char *buf, int pos) { + unsigned int index = get_line_index(con, start->line); struct line *iter; - int line_x, line_len; - - if (!start->line) { - return pos; - } iter = start->line; while (iter) { - line_x = 0; - if (iter == start->line) { - line_x = start->x; - } - - line_len = calc_selection_line_len_sb(con, start, end, iter); - pos += copy_line(iter, &(buf[pos]), line_x, line_len); - - if (iter == con->sb_last || iter == end->line) { + pos += copy_line(con, iter, &(buf[pos])); + if (iter == end->line) break; - } - - iter = iter->next; + iter = get_next_line(con, iter, &index); } - - return pos; -} - -/* - * Copy all selected lines from the regular screen - */ -static int copy_lines(struct tsm_screen *con, struct selection_pos *start, struct selection_pos *end, char *buf, int pos) -{ - int line_len, line_x, i; - - /* selection is scroll back buffer only */ - if (end->line) { - return pos; - } - - for (i = start->y; i <= end->y; i++) { - line_len = calc_selection_line_len(con, start, end, i); - - line_x = 0; - if (!start->line && i == start->y) { - line_x = start->x; - } - - pos += copy_line(con->lines[i], &(buf[pos]), line_x, line_len); - } - return pos; } SHL_EXPORT int tsm_screen_selection_copy(struct tsm_screen *con, char **out) { - struct selection_pos *start, *end; - struct selection_pos start_copy, end_copy; + struct selection_pos *start = &con->sel_start; + struct selection_pos *end = &con->sel_end; int buf_size = 0; int pos = 0; int total_lines; @@ -479,36 +367,21 @@ int tsm_screen_selection_copy(struct tsm_screen *con, char **out) return -ENOENT; } - /* - * copy the selection start and end so we can modify it without affecting - * the screen in any way - */ - memcpy(&start_copy, &con->sel_start, sizeof(con->sel_start)); - memcpy(&end_copy, &con->sel_end, sizeof(con->sel_end)); - start = &start_copy; - end = &end_copy; - /* invalid selection */ - if (start->y == SELECTION_TOP && start->line == NULL && - end->y == SELECTION_TOP && end->line == NULL) { + if (start->line == NULL && end->line == NULL) { *out = strdup(""); return 0; } - norm_selection(con, &start, &end); - - if (start->line == NULL && start->y == SELECTION_TOP) { - if (con->sb_first != NULL) { - start->line = con->sb_first; - start->x = 0; - } else { - start->y = 0; - start->x = 0; - } + if (start->line == NULL) { + if (!shl_dlist_empty(&con->sb.list)) + start->line = shl_dlist_first(&con->sb.list, struct line, list); + else + start->line = con->lines[0]; + start->x = 0; } - total_lines = selection_count_lines_sb(con, start, end); - total_lines += selection_count_lines(start, end); + total_lines = selection_count_lines(con, start, end); buf_size = calc_line_copy_buffer(con, total_lines); *out = calloc(buf_size, 1); @@ -516,7 +389,6 @@ int tsm_screen_selection_copy(struct tsm_screen *con, char **out) return -ENOMEM; } - pos = copy_lines_sb(con, start, end, *out, pos); pos = copy_lines(con, start, end, *out, pos); /* remove last line break */ diff --git a/test/test_selection.c b/test/test_selection.c index 1ee6ab0..a2e310d 100644 --- a/test/test_selection.c +++ b/test/test_selection.c @@ -203,9 +203,7 @@ START_TEST(test_screen_copy_line_scrolled) tsm_screen_selection_target(screen, 14, 39); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 39); ck_assert_int_eq(screen->sel_end.x, 14); - ck_assert_int_eq(screen->sel_end.y, 39); /* force the selected text to scroll up */ tsm_screen_newline(screen); @@ -217,9 +215,7 @@ START_TEST(test_screen_copy_line_scrolled) tsm_screen_newline(screen); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 32); ck_assert_int_eq(screen->sel_end.x, 14); - ck_assert_int_eq(screen->sel_end.y, 32); r = tsm_screen_selection_copy(screen, &str); ck_assert_ptr_ne(NULL, str); @@ -267,7 +263,6 @@ START_TEST(test_screen_copy_lines) str = NULL; /* Select "This is a copy test\nfor a selection" from top left and to bottom right copy it */ - tsm_screen_reset(screen); tsm_screen_selection_start(screen, 0, 2); tsm_screen_selection_target(screen, 14, 3); @@ -278,7 +273,6 @@ START_TEST(test_screen_copy_lines) str = NULL; /* Select all text excluding the first 3 spaces and the trailing '-' chars from bottom right to top left and copy it */ - tsm_screen_reset(screen); tsm_screen_selection_start(screen, 41, 4); tsm_screen_selection_target(screen, 3, 1); @@ -321,9 +315,7 @@ START_TEST(test_screen_copy_lines_scrolled) tsm_screen_selection_target(screen, 5, 39); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 37); ck_assert_int_eq(screen->sel_end.x, 5); - ck_assert_int_eq(screen->sel_end.y, 39); /* force the selected text to scroll up */ tsm_screen_newline(screen); @@ -335,9 +327,7 @@ START_TEST(test_screen_copy_lines_scrolled) tsm_screen_newline(screen); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 30); ck_assert_int_eq(screen->sel_end.x, 5); - ck_assert_int_eq(screen->sel_end.y, 32); r = tsm_screen_selection_copy(screen, &str); ck_assert_ptr_ne(NULL, str); @@ -462,9 +452,7 @@ START_TEST(test_screen_copy_line_sb_scrolled) tsm_screen_selection_target(screen, 14, 0); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 0); ck_assert_int_eq(screen->sel_end.x, 14); - ck_assert_int_eq(screen->sel_end.y, 0); /* force the selected text to scroll up */ for (int i = 0; i < 40; i++) { @@ -472,10 +460,8 @@ START_TEST(test_screen_copy_line_sb_scrolled) } ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, -1); ck_assert_ptr_ne(screen->sel_start.line, NULL); ck_assert_int_eq(screen->sel_end.x, 14); - ck_assert_int_eq(screen->sel_end.y, -1); ck_assert_ptr_ne(screen->sel_end.line, NULL); r = tsm_screen_selection_copy(screen, &str); @@ -496,10 +482,8 @@ START_TEST(test_screen_copy_line_sb_scrolled) tsm_screen_selection_target(screen, 14, 0); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 0); ck_assert_ptr_ne(screen->sel_start.line, NULL); ck_assert_int_eq(screen->sel_end.x, 14); - ck_assert_int_eq(screen->sel_end.y, 0); ck_assert_ptr_ne(screen->sel_end.line, NULL); tsm_screen_newline(screen); @@ -507,10 +491,8 @@ START_TEST(test_screen_copy_line_sb_scrolled) tsm_screen_newline(screen); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 0); ck_assert_ptr_ne(screen->sel_start.line, NULL); ck_assert_int_eq(screen->sel_end.x, 14); - ck_assert_int_eq(screen->sel_end.y, 0); ck_assert_ptr_ne(screen->sel_end.line, NULL); r = tsm_screen_selection_copy(screen, &str); @@ -549,26 +531,16 @@ START_TEST(test_screen_copy_line_sb_scrolled_invalid) tsm_screen_selection_target(screen, 14, 0); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 0); ck_assert_int_eq(screen->sel_end.x, 14); - ck_assert_int_eq(screen->sel_end.y, 0); /* force the selected text to scroll up */ for (i = 0; i < 40; i++) { tsm_screen_newline(screen); } - /* - * sel_start.y == -1, sel_start.line == NULL - * sel_end.y == -1, sel_end.line == NULL - * - * => Invalid selection - */ ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, -1); ck_assert_ptr_eq(screen->sel_start.line, NULL); ck_assert_int_eq(screen->sel_end.x, 14); - ck_assert_int_eq(screen->sel_end.y, -1); ck_assert_ptr_eq(screen->sel_end.line, NULL); r = tsm_screen_selection_copy(screen, &str); @@ -630,7 +602,6 @@ START_TEST(test_screen_copy_lines_sb) str = NULL; /* Select "This is a copy test\nfor a selection" from top left and to bottom right copy it */ - tsm_screen_reset(screen); tsm_screen_selection_start(screen, 0, 2); tsm_screen_selection_target(screen, 14, 3); @@ -641,10 +612,12 @@ START_TEST(test_screen_copy_lines_sb) str = NULL; /* Select all text excluding the first 3 spaces and the trailing '-' chars from bottom right to top left and copy it */ - tsm_screen_reset(screen); tsm_screen_selection_start(screen, 41, 4); tsm_screen_selection_target(screen, 3, 1); + ck_assert_int_eq(screen->sel_start.x, 3); + ck_assert_int_eq(screen->sel_end.x, 41); + r = tsm_screen_selection_copy(screen, &str); ck_assert_ptr_ne(NULL, str); ck_assert_str_eq("Hello World!\nThis is a copy test\nfor a selection with multiple lines.\nAll of them are on screen (not in the sb).", str); @@ -652,7 +625,6 @@ START_TEST(test_screen_copy_lines_sb) str = NULL; /* Select from scroll back buffer and the screen from top left to bottom right and copy it */ - tsm_screen_reset(screen); tsm_screen_selection_start(screen, 0, 4); tsm_screen_selection_target(screen, 18, 6); @@ -663,10 +635,12 @@ START_TEST(test_screen_copy_lines_sb) str = NULL; /* Select from scroll back buffer and the screen from bottom right to top left and copy it */ - tsm_screen_reset(screen); tsm_screen_selection_start(screen, 18, 6); tsm_screen_selection_target(screen, 0, 4); + ck_assert_int_eq(screen->sel_start.x, 0); + ck_assert_int_eq(screen->sel_end.x, 18); + r = tsm_screen_selection_copy(screen, &str); ck_assert_ptr_ne(NULL, str); ck_assert_str_eq("All of them are on screen (not in the sb).------\nText not in SB\nMore Text not in SB", str); @@ -674,7 +648,6 @@ START_TEST(test_screen_copy_lines_sb) str = NULL; /* Select from scroll back buffer and the screen from bottom right to top left and copy it */ - tsm_screen_reset(screen); tsm_screen_selection_start(screen, 8, 6); tsm_screen_selection_target(screen, 7, 4); @@ -719,9 +692,7 @@ START_TEST(test_screen_copy_lines_sb_scrolled) tsm_screen_selection_target(screen, 5, 2); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 0); ck_assert_int_eq(screen->sel_end.x, 5); - ck_assert_int_eq(screen->sel_end.y, 2); /* force the selected text to scroll into the sb */ for (i = 0; i < 40; i++) { @@ -729,10 +700,8 @@ START_TEST(test_screen_copy_lines_sb_scrolled) } ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, -1); ck_assert_ptr_ne(screen->sel_start.line, NULL); ck_assert_int_eq(screen->sel_end.x, 5); - ck_assert_int_eq(screen->sel_end.y, -1); ck_assert_ptr_ne(screen->sel_end.line, NULL); ck_assert_ptr_ne(screen->sel_start.line, screen->sel_end.line); @@ -754,19 +723,15 @@ START_TEST(test_screen_copy_lines_sb_scrolled) tsm_screen_selection_target(screen, 5, 2); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 0); ck_assert_int_eq(screen->sel_end.x, 5); - ck_assert_int_eq(screen->sel_end.y, 0); tsm_screen_newline(screen); tsm_screen_newline(screen); tsm_screen_newline(screen); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 0); ck_assert_ptr_ne(screen->sel_start.line, NULL); ck_assert_int_eq(screen->sel_end.x, 5); - ck_assert_int_eq(screen->sel_end.y, 0); ck_assert_ptr_ne(screen->sel_end.line, NULL); ck_assert_ptr_ne(screen->sel_start.line, screen->sel_end.line); @@ -810,9 +775,7 @@ START_TEST(test_screen_copy_lines_sb_scrolled_cut_off) tsm_screen_selection_target(screen, 5, 2); ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, 0); ck_assert_int_eq(screen->sel_end.x, 5); - ck_assert_int_eq(screen->sel_end.y, 2); /* force the selected text to scroll up */ for (i = 0; i < 39; i++) { @@ -820,11 +783,9 @@ START_TEST(test_screen_copy_lines_sb_scrolled_cut_off) } ck_assert_int_eq(screen->sel_start.x, 3); - ck_assert_int_eq(screen->sel_start.y, -1); - ck_assert_ptr_eq(screen->sel_start.line, NULL); + ck_assert(!is_in_scrollback(&screen->sel_start)); ck_assert_int_eq(screen->sel_end.x, 5); - ck_assert_int_eq(screen->sel_end.y, 0); - ck_assert_ptr_eq(screen->sel_end.line, NULL); + ck_assert(!is_in_scrollback(&screen->sel_end)); r = tsm_screen_selection_copy(screen, &str); ck_assert_ptr_ne(NULL, str);