mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
Merge branch 'translate-cursor-coords-when-reflowing'
This commit is contained in:
commit
a9af8290ab
9 changed files with 236 additions and 195 deletions
|
|
@ -50,6 +50,7 @@
|
|||
* Alt+Return to emit "ESC \r".
|
||||
* Trackpad sloooow scrolling to eventually scroll a line.
|
||||
* Memory leak in terminal reset.
|
||||
* Translation of cursor coordinates on resize
|
||||
|
||||
|
||||
### Security
|
||||
|
|
|
|||
128
csi.c
128
csi.c
|
|
@ -382,7 +382,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
/* VPA - vertical line position absolute */
|
||||
int rel_row = vt_param_get(term, 0, 1) - 1;
|
||||
int row = term_row_rel_to_abs(term, rel_row);
|
||||
term_cursor_to(term, row, term->cursor.point.col);
|
||||
term_cursor_to(term, row, term->grid->cursor.point.col);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -411,13 +411,13 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
case 'E':
|
||||
/* CNL - Cursor Next Line */
|
||||
term_cursor_down(term, vt_param_get(term, 0, 1));
|
||||
term_cursor_left(term, term->cursor.point.col);
|
||||
term_cursor_left(term, term->grid->cursor.point.col);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
/* CPL - Cursor Previous Line */
|
||||
term_cursor_up(term, vt_param_get(term, 0, 1));
|
||||
term_cursor_left(term, term->cursor.point.col);
|
||||
term_cursor_left(term, term->grid->cursor.point.col);
|
||||
break;
|
||||
|
||||
case 'g': {
|
||||
|
|
@ -426,9 +426,9 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
case 0:
|
||||
/* Clear tab stop at *current* column */
|
||||
tll_foreach(term->tab_stops, it) {
|
||||
if (it->item == term->cursor.point.col)
|
||||
if (it->item == term->grid->cursor.point.col)
|
||||
tll_remove(term->tab_stops, it);
|
||||
else if (it->item > term->cursor.point.col)
|
||||
else if (it->item > term->grid->cursor.point.col)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -450,7 +450,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
case 'G': {
|
||||
/* Cursor horizontal absolute */
|
||||
int col = min(vt_param_get(term, 0, 1), term->cols) - 1;
|
||||
term_cursor_to(term, term->cursor.point.row, col);
|
||||
term_cursor_to(term, term->grid->cursor.point.row, col);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -473,15 +473,15 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
/* From cursor to end of screen */
|
||||
term_erase(
|
||||
term,
|
||||
&term->cursor.point,
|
||||
&term->grid->cursor.point,
|
||||
&(struct coord){term->cols - 1, term->rows - 1});
|
||||
term->cursor.lcf = false;
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* From start of screen to cursor */
|
||||
term_erase(term, &(struct coord){0, 0}, &term->cursor.point);
|
||||
term->cursor.lcf = false;
|
||||
term_erase(term, &(struct coord){0, 0}, &term->grid->cursor.point);
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
|
@ -490,7 +490,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
term,
|
||||
&(struct coord){0, 0},
|
||||
&(struct coord){term->cols - 1, term->rows - 1});
|
||||
term->cursor.lcf = false;
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
|
||||
case 3: {
|
||||
|
|
@ -531,25 +531,25 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
/* From cursor to end of line */
|
||||
term_erase(
|
||||
term,
|
||||
&term->cursor.point,
|
||||
&(struct coord){term->cols - 1, term->cursor.point.row});
|
||||
term->cursor.lcf = false;
|
||||
&term->grid->cursor.point,
|
||||
&(struct coord){term->cols - 1, term->grid->cursor.point.row});
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* From start of line to cursor */
|
||||
term_erase(
|
||||
term, &(struct coord){0, term->cursor.point.row}, &term->cursor.point);
|
||||
term->cursor.lcf = false;
|
||||
term, &(struct coord){0, term->grid->cursor.point.row}, &term->grid->cursor.point);
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Entire line */
|
||||
term_erase(
|
||||
term,
|
||||
&(struct coord){0, term->cursor.point.row},
|
||||
&(struct coord){term->cols - 1, term->cursor.point.row});
|
||||
term->cursor.lcf = false;
|
||||
&(struct coord){0, term->grid->cursor.point.row},
|
||||
&(struct coord){term->cols - 1, term->grid->cursor.point.row});
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -561,36 +561,36 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
}
|
||||
|
||||
case 'L': {
|
||||
if (term->cursor.point.row < term->scroll_region.start ||
|
||||
term->cursor.point.row >= term->scroll_region.end)
|
||||
if (term->grid->cursor.point.row < term->scroll_region.start ||
|
||||
term->grid->cursor.point.row >= term->scroll_region.end)
|
||||
break;
|
||||
|
||||
int count = min(
|
||||
vt_param_get(term, 0, 1),
|
||||
term->scroll_region.end - term->cursor.point.row);
|
||||
term->scroll_region.end - term->grid->cursor.point.row);
|
||||
|
||||
term_scroll_reverse_partial(
|
||||
term,
|
||||
(struct scroll_region){
|
||||
.start = term->cursor.point.row,
|
||||
.start = term->grid->cursor.point.row,
|
||||
.end = term->scroll_region.end},
|
||||
count);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'M': {
|
||||
if (term->cursor.point.row < term->scroll_region.start ||
|
||||
term->cursor.point.row >= term->scroll_region.end)
|
||||
if (term->grid->cursor.point.row < term->scroll_region.start ||
|
||||
term->grid->cursor.point.row >= term->scroll_region.end)
|
||||
break;
|
||||
|
||||
int count = min(
|
||||
vt_param_get(term, 0, 1),
|
||||
term->scroll_region.end - term->cursor.point.row);
|
||||
term->scroll_region.end - term->grid->cursor.point.row);
|
||||
|
||||
term_scroll_partial(
|
||||
term,
|
||||
(struct scroll_region){
|
||||
.start = term->cursor.point.row,
|
||||
.start = term->grid->cursor.point.row,
|
||||
.end = term->scroll_region.end},
|
||||
count);
|
||||
break;
|
||||
|
|
@ -601,26 +601,26 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
|
||||
/* Number of characters to delete */
|
||||
int count = min(
|
||||
vt_param_get(term, 0, 1), term->cols - term->cursor.point.col);
|
||||
vt_param_get(term, 0, 1), term->cols - term->grid->cursor.point.col);
|
||||
|
||||
/* Number of characters left after deletion (on current line) */
|
||||
int remaining = term->cols - (term->cursor.point.col + count);
|
||||
int remaining = term->cols - (term->grid->cursor.point.col + count);
|
||||
|
||||
/* 'Delete' characters by moving the remaining ones */
|
||||
memmove(&term->grid->cur_row->cells[term->cursor.point.col],
|
||||
&term->grid->cur_row->cells[term->cursor.point.col + count],
|
||||
memmove(&term->grid->cur_row->cells[term->grid->cursor.point.col],
|
||||
&term->grid->cur_row->cells[term->grid->cursor.point.col + count],
|
||||
remaining * sizeof(term->grid->cur_row->cells[0]));
|
||||
|
||||
for (size_t c = 0; c < remaining; c++)
|
||||
term->grid->cur_row->cells[term->cursor.point.col + c].attrs.clean = 0;
|
||||
term->grid->cur_row->cells[term->grid->cursor.point.col + c].attrs.clean = 0;
|
||||
term->grid->cur_row->dirty = true;
|
||||
|
||||
/* Erase the remainder of the line */
|
||||
term_erase(
|
||||
term,
|
||||
&(struct coord){term->cursor.point.col + remaining, term->cursor.point.row},
|
||||
&(struct coord){term->cols - 1, term->cursor.point.row});
|
||||
term->cursor.lcf = false;
|
||||
&(struct coord){term->grid->cursor.point.col + remaining, term->grid->cursor.point.row},
|
||||
&(struct coord){term->cols - 1, term->grid->cursor.point.row});
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -629,25 +629,25 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
|
||||
/* Number of characters to insert */
|
||||
int count = min(
|
||||
vt_param_get(term, 0, 1), term->cols - term->cursor.point.col);
|
||||
vt_param_get(term, 0, 1), term->cols - term->grid->cursor.point.col);
|
||||
|
||||
/* Characters to move */
|
||||
int remaining = term->cols - (term->cursor.point.col + count);
|
||||
int remaining = term->cols - (term->grid->cursor.point.col + count);
|
||||
|
||||
/* Push existing characters */
|
||||
memmove(&term->grid->cur_row->cells[term->cursor.point.col + count],
|
||||
&term->grid->cur_row->cells[term->cursor.point.col],
|
||||
memmove(&term->grid->cur_row->cells[term->grid->cursor.point.col + count],
|
||||
&term->grid->cur_row->cells[term->grid->cursor.point.col],
|
||||
remaining * sizeof(term->grid->cur_row->cells[0]));
|
||||
for (size_t c = 0; c < remaining; c++)
|
||||
term->grid->cur_row->cells[term->cursor.point.col + count + c].attrs.clean = 0;
|
||||
term->grid->cur_row->cells[term->grid->cursor.point.col + count + c].attrs.clean = 0;
|
||||
term->grid->cur_row->dirty = true;
|
||||
|
||||
/* Erase (insert space characters) */
|
||||
term_erase(
|
||||
term,
|
||||
&term->cursor.point,
|
||||
&(struct coord){term->cursor.point.col + count - 1, term->cursor.point.row});
|
||||
term->cursor.lcf = false;
|
||||
&term->grid->cursor.point,
|
||||
&(struct coord){term->grid->cursor.point.col + count - 1, term->grid->cursor.point.row});
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -662,13 +662,13 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
case 'X': {
|
||||
/* Erase chars */
|
||||
int count = min(
|
||||
vt_param_get(term, 0, 1), term->cols - term->cursor.point.col);
|
||||
vt_param_get(term, 0, 1), term->cols - term->grid->cursor.point.col);
|
||||
|
||||
term_erase(
|
||||
term,
|
||||
&term->cursor.point,
|
||||
&(struct coord){term->cursor.point.col + count - 1, term->cursor.point.row});
|
||||
term->cursor.lcf = false;
|
||||
&term->grid->cursor.point,
|
||||
&(struct coord){term->grid->cursor.point.col + count - 1, term->grid->cursor.point.row});
|
||||
term->grid->cursor.lcf = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -677,13 +677,13 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
for (int i = 0; i < vt_param_get(term, 0, 1); i++) {
|
||||
int new_col = term->cols - 1;
|
||||
tll_foreach(term->tab_stops, it) {
|
||||
if (it->item > term->cursor.point.col) {
|
||||
if (it->item > term->grid->cursor.point.col) {
|
||||
new_col = it->item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(new_col >= term->cursor.point.col);
|
||||
term_cursor_right(term, new_col - term->cursor.point.col);
|
||||
assert(new_col >= term->grid->cursor.point.col);
|
||||
term_cursor_right(term, new_col - term->grid->cursor.point.col);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -693,13 +693,13 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
for (int i = 0; i < vt_param_get(term, 0, 1); i++) {
|
||||
int new_col = 0;
|
||||
tll_rforeach(term->tab_stops, it) {
|
||||
if (it->item < term->cursor.point.col) {
|
||||
if (it->item < term->grid->cursor.point.col) {
|
||||
new_col = it->item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(term->cursor.point.col >= new_col);
|
||||
term_cursor_left(term, term->cursor.point.col - new_col);
|
||||
assert(term->grid->cursor.point.col >= new_col);
|
||||
term_cursor_left(term, term->grid->cursor.point.col - new_col);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -757,11 +757,11 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
}
|
||||
|
||||
case 's':
|
||||
term->saved_cursor = term->cursor;
|
||||
term->grid->saved_cursor = term->grid->cursor;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
term_restore_cursor(term, &term->saved_cursor);
|
||||
term_restore_cursor(term, &term->grid->saved_cursor);
|
||||
break;
|
||||
|
||||
case 't': {
|
||||
|
|
@ -861,15 +861,15 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
/* u7 - cursor position query */
|
||||
|
||||
int row = term->origin == ORIGIN_ABSOLUTE
|
||||
? term->cursor.point.row
|
||||
: term->cursor.point.row - term->scroll_region.start;
|
||||
? term->grid->cursor.point.row
|
||||
: term->grid->cursor.point.row - term->scroll_region.start;
|
||||
|
||||
/* TODO: we use 0-based position, while the xterm
|
||||
* terminfo says the receiver of the reply should
|
||||
* decrement, hence we must add 1 */
|
||||
char reply[64];
|
||||
snprintf(reply, sizeof(reply), "\x1b[%d;%dR",
|
||||
row + 1, term->cursor.point.col + 1);
|
||||
row + 1, term->grid->cursor.point.col + 1);
|
||||
term_to_slave(term, reply, strlen(reply));
|
||||
break;
|
||||
}
|
||||
|
|
@ -1014,9 +1014,11 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
selection_cancel(term);
|
||||
|
||||
term->grid = &term->alt;
|
||||
term->alt_saved_cursor = term->cursor;
|
||||
|
||||
term_cursor_to(term, term->cursor.point.row, term->cursor.point.col);
|
||||
term_cursor_to(
|
||||
term,
|
||||
min(term->grid->cursor.point.row, term->rows - 1),
|
||||
min(term->grid->cursor.point.col, term->cols - 1));
|
||||
|
||||
tll_free(term->alt.damage);
|
||||
tll_free(term->alt.scroll_damage);
|
||||
|
|
@ -1137,7 +1139,11 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
selection_cancel(term);
|
||||
|
||||
term->grid = &term->normal;
|
||||
term_restore_cursor(term, &term->alt_saved_cursor);
|
||||
|
||||
term_cursor_to(
|
||||
term,
|
||||
min(term->grid->cursor.point.row, term->rows - 1),
|
||||
min(term->grid->cursor.point.col, term->cols - 1));
|
||||
|
||||
tll_free(term->alt.damage);
|
||||
tll_free(term->alt.scroll_damage);
|
||||
|
|
|
|||
125
grid.c
125
grid.c
|
|
@ -53,16 +53,16 @@ grid_row_free(struct row *row)
|
|||
free(row);
|
||||
}
|
||||
|
||||
int
|
||||
void
|
||||
grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
||||
int old_screen_rows, int new_screen_rows)
|
||||
int old_screen_rows, int new_screen_rows,
|
||||
size_t tracking_points_count,
|
||||
struct coord *_tracking_points[static tracking_points_count])
|
||||
{
|
||||
struct row *const *old_grid = grid->rows;
|
||||
const int old_rows = grid->num_rows;
|
||||
const int old_cols = grid->num_cols;
|
||||
|
||||
//assert(old_rows != new_rows || old_cols != new_cols);
|
||||
|
||||
int new_col_idx = 0;
|
||||
int new_row_idx = 0;
|
||||
|
||||
|
|
@ -79,13 +79,31 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
|
||||
tll(struct sixel) new_sixels = tll_init();
|
||||
|
||||
/* Turn cursor coordinates into grid absolute coordinates */
|
||||
struct coord cursor = grid->cursor.point;
|
||||
cursor.row += grid->offset;
|
||||
cursor.row &= old_rows - 1;
|
||||
|
||||
struct coord saved_cursor = grid->saved_cursor.point;
|
||||
saved_cursor.row += grid->offset;
|
||||
saved_cursor.row &= old_rows - 1;
|
||||
|
||||
tll(struct coord *) tracking_points = tll_init();
|
||||
tll_push_back(tracking_points, &cursor);
|
||||
tll_push_back(tracking_points, &saved_cursor);
|
||||
|
||||
for (size_t i = 0; i < tracking_points_count; i++)
|
||||
tll_push_back(tracking_points, _tracking_points[i]);
|
||||
|
||||
/*
|
||||
* Walk the old grid
|
||||
*/
|
||||
for (int r = 0; r < old_rows; r++) {
|
||||
|
||||
const size_t old_row_idx = (offset + r) & (old_rows - 1);
|
||||
|
||||
/* Unallocated (empty) rows we can simply skip */
|
||||
const struct row *old_row = old_grid[(offset + r) & (old_rows - 1)];
|
||||
const struct row *old_row = old_grid[old_row_idx];
|
||||
if (old_row == NULL)
|
||||
continue;
|
||||
|
||||
|
|
@ -102,7 +120,7 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
* the "real" sixel list.
|
||||
*/
|
||||
tll_foreach(grid->sixel_images, it) {
|
||||
if (it->item.pos.row == ((offset + r) & (old_rows - 1))) {
|
||||
if (it->item.pos.row == old_row_idx) {
|
||||
struct sixel six = it->item;
|
||||
six.pos.row = new_row_idx;
|
||||
|
||||
|
|
@ -111,6 +129,21 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
}
|
||||
}
|
||||
|
||||
#define line_wrap() \
|
||||
do { \
|
||||
new_col_idx = 0; \
|
||||
new_row_idx = (new_row_idx + 1) & (new_rows - 1); \
|
||||
\
|
||||
new_row = new_grid[new_row_idx]; \
|
||||
if (new_row == NULL) { \
|
||||
new_row = grid_row_alloc(new_cols, true); \
|
||||
new_grid[new_row_idx] = new_row; \
|
||||
} else { \
|
||||
memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); \
|
||||
new_row->linebreak = false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* Keep track of empty cells. If the old line ends with a
|
||||
* string of empty cells, we don't need to, nor do we want to,
|
||||
|
|
@ -122,11 +155,23 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
|
||||
/* Walk current line of the old grid */
|
||||
for (int c = 0; c < old_cols; c++) {
|
||||
if (old_row->cells[c].wc == 0) {
|
||||
|
||||
/* Check if this cell is one of the tracked cells */
|
||||
bool is_tracking_point = false;
|
||||
tll_foreach(tracking_points, it) {
|
||||
if (it->item->row == old_row_idx && it->item->col == c) {
|
||||
is_tracking_point = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_row->cells[c].wc == 0 && !is_tracking_point) {
|
||||
empty_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Allow left-adjusted and right-adjusted text, with empty
|
||||
* cells in between, to be "pushed together" */
|
||||
int old_cols_left = old_cols - c;
|
||||
int cols_needed = empty_count + old_cols_left;
|
||||
int new_cols_left = new_cols - new_col_idx;
|
||||
|
|
@ -138,6 +183,7 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
|
||||
/* Out of columns on current row in new grid? */
|
||||
if (new_col_idx >= new_cols) {
|
||||
#if 0
|
||||
/*
|
||||
* If last cell on last row and first cell on new
|
||||
* row are non-empty, wrap the line, otherwise
|
||||
|
|
@ -148,18 +194,8 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
{
|
||||
new_row->linebreak = true;
|
||||
}
|
||||
|
||||
new_col_idx = 0;
|
||||
new_row_idx = (new_row_idx + 1) & (new_rows - 1);
|
||||
|
||||
new_row = new_grid[new_row_idx];
|
||||
if (new_row == NULL) {
|
||||
new_row = grid_row_alloc(new_cols, true);
|
||||
new_grid[new_row_idx] = new_row;
|
||||
} else {
|
||||
memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0]));
|
||||
new_row->linebreak = false;
|
||||
}
|
||||
#endif
|
||||
line_wrap();
|
||||
}
|
||||
|
||||
assert(new_row != NULL);
|
||||
|
|
@ -168,6 +204,17 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
|
||||
new_row->cells[new_col_idx] = *old_cell;
|
||||
new_row->cells[new_col_idx].attrs.clean = 1;
|
||||
|
||||
/* Translate tracking point(s) */
|
||||
if (is_tracking_point && i >= empty_count) {
|
||||
tll_foreach(tracking_points, it) {
|
||||
if (it->item->row == old_row_idx && it->item->col == c) {
|
||||
it->item->row = new_row_idx;
|
||||
it->item->col = new_col_idx;
|
||||
tll_remove(tracking_points, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
new_col_idx++;
|
||||
}
|
||||
|
||||
|
|
@ -176,19 +223,10 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
|
||||
if (old_row->linebreak) {
|
||||
new_row->linebreak = true;
|
||||
|
||||
new_col_idx = 0;
|
||||
new_row_idx = (new_row_idx + 1) & (new_rows - 1);
|
||||
|
||||
new_row = new_grid[new_row_idx];
|
||||
if (new_row == NULL) {
|
||||
new_row = grid_row_alloc(new_cols, true);
|
||||
new_grid[new_row_idx] = new_row;
|
||||
} else {
|
||||
memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0]));
|
||||
new_row->linebreak = false;
|
||||
}
|
||||
line_wrap();
|
||||
}
|
||||
|
||||
#undef line_wrap
|
||||
}
|
||||
|
||||
/* Set offset such that the last reflowed row is at the bottom */
|
||||
|
|
@ -211,11 +249,32 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
grid_row_free(old_grid[r]);
|
||||
free(grid->rows);
|
||||
|
||||
grid->cur_row = new_grid[new_row_idx];
|
||||
grid->cur_row = new_grid[cursor.row];
|
||||
grid->rows = new_grid;
|
||||
grid->num_rows = new_rows;
|
||||
grid->num_cols = new_cols;
|
||||
|
||||
/* Convert absolute coordinates to screen relative */
|
||||
cursor.row -= grid->offset;
|
||||
while (cursor.row < 0)
|
||||
cursor.row += grid->num_rows;
|
||||
|
||||
assert(cursor.row >= 0);
|
||||
assert(cursor.row < grid->num_rows);
|
||||
|
||||
saved_cursor.row -= grid->offset;
|
||||
while (saved_cursor.row < 0)
|
||||
saved_cursor.row += grid->num_rows;
|
||||
|
||||
assert(saved_cursor.row >= 0);
|
||||
assert(saved_cursor.row < grid->num_rows);
|
||||
|
||||
grid->cursor.point = cursor;
|
||||
grid->saved_cursor.point = saved_cursor;
|
||||
|
||||
grid->cursor.lcf = false;
|
||||
grid->saved_cursor.lcf = false;
|
||||
|
||||
/* Destroy any non-moved sixels */
|
||||
tll_foreach(grid->sixel_images, it)
|
||||
sixel_destroy(&it->item);
|
||||
|
|
@ -226,5 +285,5 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
|||
tll_push_back(grid->sixel_images, it->item);
|
||||
tll_free(new_sixels);
|
||||
|
||||
return new_row_idx;
|
||||
tll_free(tracking_points);
|
||||
}
|
||||
|
|
|
|||
6
grid.h
6
grid.h
|
|
@ -6,9 +6,11 @@
|
|||
void grid_swap_row(struct grid *grid, int row_a, int row_b, bool initialize);
|
||||
struct row *grid_row_alloc(int cols, bool initialize);
|
||||
void grid_row_free(struct row *row);
|
||||
int grid_reflow(
|
||||
void grid_reflow(
|
||||
struct grid *grid, int new_rows, int new_cols,
|
||||
int old_screen_rows, int new_screen_rows);
|
||||
int old_screen_rows, int new_screen_rows,
|
||||
size_t tracking_points_count,
|
||||
struct coord *tracking_points[static tracking_points_count]);
|
||||
|
||||
static inline int
|
||||
grid_row_absolute(const struct grid *grid, int row_no)
|
||||
|
|
|
|||
56
render.c
56
render.c
|
|
@ -1373,7 +1373,7 @@ grid_render(struct terminal *term)
|
|||
*/
|
||||
bool cursor_is_visible = false;
|
||||
int view_end = (term->grid->view + term->rows - 1) & (term->grid->num_rows - 1);
|
||||
int cursor_row = (term->grid->offset + term->cursor.point.row) & (term->grid->num_rows - 1);
|
||||
int cursor_row = (term->grid->offset + term->grid->cursor.point.row) & (term->grid->num_rows - 1);
|
||||
if (view_end >= term->grid->view) {
|
||||
/* Not wrapped */
|
||||
if (cursor_row >= term->grid->view && cursor_row <= view_end)
|
||||
|
|
@ -1401,21 +1401,21 @@ grid_render(struct terminal *term)
|
|||
int view_aligned_row
|
||||
= (cursor_row - term->grid->view + term->grid->num_rows) & (term->grid->num_rows - 1);
|
||||
|
||||
term->render.last_cursor.actual = term->cursor.point;
|
||||
term->render.last_cursor.actual = term->grid->cursor.point;
|
||||
term->render.last_cursor.in_view = (struct coord) {
|
||||
term->cursor.point.col, view_aligned_row};
|
||||
term->grid->cursor.point.col, view_aligned_row};
|
||||
|
||||
struct row *row = grid_row_in_view(term->grid, view_aligned_row);
|
||||
struct cell *cell = &row->cells[term->cursor.point.col];
|
||||
struct cell *cell = &row->cells[term->grid->cursor.point.col];
|
||||
|
||||
cell->attrs.clean = 0;
|
||||
term->render.last_cursor.cell = cell;
|
||||
int cols_updated = render_cell(
|
||||
term, buf->pix, cell, term->cursor.point.col, view_aligned_row, true);
|
||||
term, buf->pix, cell, term->grid->cursor.point.col, view_aligned_row, true);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window->surface,
|
||||
term->margins.left + term->cursor.point.col * term->cell_width,
|
||||
term->margins.left + term->grid->cursor.point.col * term->cell_width,
|
||||
term->margins.top + view_aligned_row * term->cell_height,
|
||||
cols_updated * term->cell_width, term->cell_height);
|
||||
}
|
||||
|
|
@ -1711,8 +1711,6 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
|||
if (!force && width == term->width && height == term->height && scale == term->scale)
|
||||
return false;
|
||||
|
||||
selection_cancel(term);
|
||||
|
||||
/* Cancel an application initiated "Synchronized Update" */
|
||||
term_disable_app_sync_updates(term);
|
||||
|
||||
|
|
@ -1754,10 +1752,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
|||
}
|
||||
|
||||
/* Reflow grids */
|
||||
int last_normal_row = grid_reflow(
|
||||
&term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows);
|
||||
int last_alt_row = grid_reflow(
|
||||
&term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows);
|
||||
grid_reflow(&term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows, 0, NULL);
|
||||
grid_reflow(&term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows, 0, NULL);
|
||||
|
||||
/* Reset tab stops */
|
||||
tll_free(term->tab_stops);
|
||||
|
|
@ -1789,36 +1785,6 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
|||
if (term->scroll_region.end >= old_rows)
|
||||
term->scroll_region.end = term->rows;
|
||||
|
||||
/* Position cursor at the last copied row */
|
||||
/* TODO: can we do better? */
|
||||
int cursor_row = term->grid == &term->normal
|
||||
? last_normal_row - term->normal.offset
|
||||
: last_alt_row - term->alt.offset;
|
||||
|
||||
while (cursor_row < 0)
|
||||
cursor_row += term->grid->num_rows;
|
||||
|
||||
assert(cursor_row >= 0);
|
||||
assert(cursor_row < term->rows);
|
||||
|
||||
term_cursor_to(
|
||||
term,
|
||||
cursor_row,
|
||||
min(term->cursor.point.col, term->cols - 1));
|
||||
|
||||
/* If in alt screen, update the saved 'normal' cursor too */
|
||||
if (term->grid == &term->alt) {
|
||||
int cursor_row = last_normal_row - term->normal.offset;
|
||||
|
||||
while (cursor_row < 0)
|
||||
cursor_row += term->grid->num_rows;
|
||||
|
||||
term->alt_saved_cursor.lcf = false;
|
||||
term->alt_saved_cursor.point.row = cursor_row;
|
||||
term->alt_saved_cursor.point.col = min(
|
||||
term->alt_saved_cursor.point.col, term->cols - 1);
|
||||
}
|
||||
|
||||
term->render.last_cursor.cell = NULL;
|
||||
|
||||
damage_view:
|
||||
|
|
@ -1846,6 +1812,12 @@ damage_view:
|
|||
term->height / term->scale + title_height);
|
||||
}
|
||||
|
||||
/* Make sure selection is within bounds */
|
||||
term->selection.start.row = min(term->selection.start.row, term->rows - 1);
|
||||
term->selection.start.col = min(term->selection.start.col, term->cols - 1);
|
||||
term->selection.end.row = min(term->selection.end.row, term->rows - 1);
|
||||
term->selection.end.col = min(term->selection.end.col, term->cols - 1);
|
||||
|
||||
tll_free(term->normal.scroll_damage);
|
||||
tll_free(term->alt.scroll_damage);
|
||||
|
||||
|
|
|
|||
6
sixel.c
6
sixel.c
|
|
@ -125,7 +125,7 @@ sixel_delete_in_range(struct terminal *term, int _start, int _end)
|
|||
void
|
||||
sixel_delete_at_cursor(struct terminal *term)
|
||||
{
|
||||
sixel_delete_at_row(term, term->cursor.point.row);
|
||||
sixel_delete_at_row(term, term->grid->cursor.point.row);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -142,8 +142,8 @@ sixel_unhook(struct terminal *term)
|
|||
.height = term->sixel.image.height,
|
||||
.rows = (term->sixel.image.height + term->cell_height - 1) / term->cell_height,
|
||||
.pos = (struct coord){
|
||||
term->cursor.point.col,
|
||||
(term->grid->offset + term->cursor.point.row) & (term->grid->num_rows - 1)},
|
||||
term->grid->cursor.point.col,
|
||||
(term->grid->offset + term->grid->cursor.point.row) & (term->grid->num_rows - 1)},
|
||||
};
|
||||
|
||||
LOG_DBG("generating %dx%d pixman image", image.width, image.height);
|
||||
|
|
|
|||
87
terminal.c
87
terminal.c
|
|
@ -354,7 +354,7 @@ term_arm_blink_timer(struct terminal *term)
|
|||
static void
|
||||
cursor_refresh(struct terminal *term)
|
||||
{
|
||||
term->grid->cur_row->cells[term->cursor.point.col].attrs.clean = 0;
|
||||
term->grid->cur_row->cells[term->grid->cursor.point.col].attrs.clean = 0;
|
||||
term->grid->cur_row->dirty = true;
|
||||
render_refresh(term);
|
||||
}
|
||||
|
|
@ -1163,7 +1163,6 @@ term_reset(struct terminal *term, bool hard)
|
|||
|
||||
if (term->grid == &term->alt) {
|
||||
term->grid = &term->normal;
|
||||
term_restore_cursor(term, &term->alt_saved_cursor);
|
||||
selection_cancel(term);
|
||||
}
|
||||
|
||||
|
|
@ -1188,10 +1187,12 @@ term_reset(struct terminal *term, bool hard)
|
|||
for (size_t i = 0; i < 256; i++)
|
||||
term->colors.table[i] = term->colors.default_table[i];
|
||||
term->origin = ORIGIN_ABSOLUTE;
|
||||
term->cursor.lcf = false;
|
||||
term->cursor = (struct cursor){.point = {0, 0}};
|
||||
term->saved_cursor = (struct cursor){.point = {0, 0}};
|
||||
term->alt_saved_cursor = (struct cursor){.point = {0, 0}};
|
||||
term->normal.cursor.lcf = false;
|
||||
term->alt.cursor.lcf = false;
|
||||
term->normal.cursor = (struct cursor){.point = {0, 0}};
|
||||
term->normal.saved_cursor = (struct cursor){.point = {0, 0}};
|
||||
term->alt.cursor = (struct cursor){.point = {0, 0}};
|
||||
term->alt.saved_cursor = (struct cursor){.point = {0, 0}};
|
||||
term->cursor_style = term->default_cursor_style;
|
||||
term_cursor_blink_disable(term);
|
||||
term->cursor_color.text = term->default_cursor_color.text;
|
||||
|
|
@ -1431,10 +1432,10 @@ term_cursor_to(struct terminal *term, int row, int col)
|
|||
assert(row < term->rows);
|
||||
assert(col < term->cols);
|
||||
|
||||
term->cursor.lcf = false;
|
||||
term->grid->cursor.lcf = false;
|
||||
|
||||
term->cursor.point.col = col;
|
||||
term->cursor.point.row = row;
|
||||
term->grid->cursor.point.col = col;
|
||||
term->grid->cursor.point.row = row;
|
||||
|
||||
term->grid->cur_row = grid_row(term->grid, row);
|
||||
}
|
||||
|
|
@ -1448,39 +1449,39 @@ term_cursor_home(struct terminal *term)
|
|||
void
|
||||
term_cursor_left(struct terminal *term, int count)
|
||||
{
|
||||
int move_amount = min(term->cursor.point.col, count);
|
||||
term->cursor.point.col -= move_amount;
|
||||
assert(term->cursor.point.col >= 0);
|
||||
term->cursor.lcf = false;
|
||||
int move_amount = min(term->grid->cursor.point.col, count);
|
||||
term->grid->cursor.point.col -= move_amount;
|
||||
assert(term->grid->cursor.point.col >= 0);
|
||||
term->grid->cursor.lcf = false;
|
||||
}
|
||||
|
||||
void
|
||||
term_cursor_right(struct terminal *term, int count)
|
||||
{
|
||||
int move_amount = min(term->cols - term->cursor.point.col - 1, count);
|
||||
term->cursor.point.col += move_amount;
|
||||
assert(term->cursor.point.col < term->cols);
|
||||
term->cursor.lcf = false;
|
||||
int move_amount = min(term->cols - term->grid->cursor.point.col - 1, count);
|
||||
term->grid->cursor.point.col += move_amount;
|
||||
assert(term->grid->cursor.point.col < term->cols);
|
||||
term->grid->cursor.lcf = false;
|
||||
}
|
||||
|
||||
void
|
||||
term_cursor_up(struct terminal *term, int count)
|
||||
{
|
||||
int top = term->origin == ORIGIN_ABSOLUTE ? 0 : term->scroll_region.start;
|
||||
assert(term->cursor.point.row >= top);
|
||||
assert(term->grid->cursor.point.row >= top);
|
||||
|
||||
int move_amount = min(term->cursor.point.row - top, count);
|
||||
term_cursor_to(term, term->cursor.point.row - move_amount, term->cursor.point.col);
|
||||
int move_amount = min(term->grid->cursor.point.row - top, count);
|
||||
term_cursor_to(term, term->grid->cursor.point.row - move_amount, term->grid->cursor.point.col);
|
||||
}
|
||||
|
||||
void
|
||||
term_cursor_down(struct terminal *term, int count)
|
||||
{
|
||||
int bottom = term->origin == ORIGIN_ABSOLUTE ? term->rows : term->scroll_region.end;
|
||||
assert(bottom >= term->cursor.point.row);
|
||||
assert(bottom >= term->grid->cursor.point.row);
|
||||
|
||||
int move_amount = min(bottom - term->cursor.point.row - 1, count);
|
||||
term_cursor_to(term, term->cursor.point.row + move_amount, term->cursor.point.col);
|
||||
int move_amount = min(bottom - term->grid->cursor.point.row - 1, count);
|
||||
term_cursor_to(term, term->grid->cursor.point.row + move_amount, term->grid->cursor.point.col);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -1569,7 +1570,7 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
|
|||
|
||||
sixel_delete_in_range(term, max(region.end - rows, region.start), region.end - 1);
|
||||
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
||||
term->grid->cur_row = grid_row(term->grid, term->cursor.point.row);
|
||||
term->grid->cur_row = grid_row(term->grid, term->grid->cursor.point.row);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1622,7 +1623,7 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
|
||||
sixel_delete_in_range(term, region.start, min(region.start + rows, region.end) - 1);
|
||||
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
|
||||
term->grid->cur_row = grid_row(term->grid, term->cursor.point.row);
|
||||
term->grid->cur_row = grid_row(term->grid, term->grid->cursor.point.row);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1634,14 +1635,14 @@ term_scroll_reverse(struct terminal *term, int rows)
|
|||
void
|
||||
term_formfeed(struct terminal *term)
|
||||
{
|
||||
term_cursor_left(term, term->cursor.point.col);
|
||||
term_cursor_left(term, term->grid->cursor.point.col);
|
||||
}
|
||||
|
||||
void
|
||||
term_linefeed(struct terminal *term)
|
||||
{
|
||||
term->grid->cur_row->linebreak = true;
|
||||
if (term->cursor.point.row == term->scroll_region.end - 1)
|
||||
if (term->grid->cursor.point.row == term->scroll_region.end - 1)
|
||||
term_scroll(term, 1);
|
||||
else
|
||||
term_cursor_down(term, 1);
|
||||
|
|
@ -1650,7 +1651,7 @@ term_linefeed(struct terminal *term)
|
|||
void
|
||||
term_reverse_index(struct terminal *term)
|
||||
{
|
||||
if (term->cursor.point.row == term->scroll_region.start)
|
||||
if (term->grid->cursor.point.row == term->scroll_region.start)
|
||||
term_scroll_reverse(term, 1);
|
||||
else
|
||||
term_cursor_up(term, 1);
|
||||
|
|
@ -1672,7 +1673,7 @@ term_restore_cursor(struct terminal *term, const struct cursor *cursor)
|
|||
int row = min(cursor->point.row, term->rows - 1);
|
||||
int col = min(cursor->point.col, term->cols - 1);
|
||||
term_cursor_to(term, row, col);
|
||||
term->cursor.lcf = cursor->lcf;
|
||||
term->grid->cursor.lcf = cursor->lcf;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2095,7 +2096,7 @@ term_disable_app_sync_updates(struct terminal *term)
|
|||
static inline void
|
||||
print_linewrap(struct terminal *term)
|
||||
{
|
||||
if (likely(!term->cursor.lcf)) {
|
||||
if (likely(!term->grid->cursor.lcf)) {
|
||||
/* Not and end of line */
|
||||
return;
|
||||
}
|
||||
|
|
@ -2105,11 +2106,11 @@ print_linewrap(struct terminal *term)
|
|||
return;
|
||||
}
|
||||
|
||||
if (term->cursor.point.row == term->scroll_region.end - 1) {
|
||||
if (term->grid->cursor.point.row == term->scroll_region.end - 1) {
|
||||
term_scroll(term, 1);
|
||||
term_cursor_to(term, term->cursor.point.row, 0);
|
||||
term_cursor_to(term, term->grid->cursor.point.row, 0);
|
||||
} else
|
||||
term_cursor_to(term, min(term->cursor.point.row + 1, term->rows - 1), 0);
|
||||
term_cursor_to(term, min(term->grid->cursor.point.row + 1, term->rows - 1), 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -2119,15 +2120,15 @@ print_insert(struct terminal *term, int width)
|
|||
|
||||
if (unlikely(term->insert_mode)) {
|
||||
struct row *row = term->grid->cur_row;
|
||||
const size_t move_count = max(0, term->cols - term->cursor.point.col - width);
|
||||
const size_t move_count = max(0, term->cols - term->grid->cursor.point.col - width);
|
||||
|
||||
memmove(
|
||||
&row->cells[term->cursor.point.col + width],
|
||||
&row->cells[term->cursor.point.col],
|
||||
&row->cells[term->grid->cursor.point.col + width],
|
||||
&row->cells[term->grid->cursor.point.col],
|
||||
move_count * sizeof(struct cell));
|
||||
|
||||
/* Mark moved cells as dirty */
|
||||
for (size_t i = term->cursor.point.col + width; i < term->cols; i++)
|
||||
for (size_t i = term->grid->cursor.point.col + width; i < term->cols; i++)
|
||||
row->cells[i].attrs.clean = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -2145,7 +2146,7 @@ term_print(struct terminal *term, wchar_t wc, int width)
|
|||
|
||||
/* *Must* get current cell *after* linewrap+insert */
|
||||
struct row *row = term->grid->cur_row;
|
||||
struct cell *cell = &row->cells[term->cursor.point.col];
|
||||
struct cell *cell = &row->cells[term->grid->cursor.point.col];
|
||||
|
||||
cell->wc = term->vt.last_printed = wc;
|
||||
cell->attrs = term->vt.attrs;
|
||||
|
|
@ -2154,20 +2155,20 @@ term_print(struct terminal *term, wchar_t wc, int width)
|
|||
cell->attrs.clean = 0;
|
||||
|
||||
/* Advance cursor the 'additional' columns while dirty:ing the cells */
|
||||
for (int i = 1; i < width && term->cursor.point.col < term->cols - 1; i++) {
|
||||
for (int i = 1; i < width && term->grid->cursor.point.col < term->cols - 1; i++) {
|
||||
term_cursor_right(term, 1);
|
||||
|
||||
assert(term->cursor.point.col < term->cols);
|
||||
struct cell *cell = &row->cells[term->cursor.point.col];
|
||||
assert(term->grid->cursor.point.col < term->cols);
|
||||
struct cell *cell = &row->cells[term->grid->cursor.point.col];
|
||||
cell->wc = 0;
|
||||
cell->attrs.clean = 0;
|
||||
}
|
||||
|
||||
/* Advance cursor */
|
||||
if (term->cursor.point.col < term->cols - 1)
|
||||
if (term->grid->cursor.point.col < term->cols - 1)
|
||||
term_cursor_right(term, 1);
|
||||
else
|
||||
term->cursor.lcf = true;
|
||||
term->grid->cursor.lcf = true;
|
||||
}
|
||||
|
||||
enum term_surface
|
||||
|
|
|
|||
|
|
@ -101,6 +101,9 @@ struct grid {
|
|||
int offset;
|
||||
int view;
|
||||
|
||||
struct cursor cursor;
|
||||
struct cursor saved_cursor;
|
||||
|
||||
struct row **rows;
|
||||
struct row *cur_row;
|
||||
|
||||
|
|
@ -278,9 +281,6 @@ struct terminal {
|
|||
} colors;
|
||||
|
||||
enum cursor_origin origin;
|
||||
struct cursor cursor;
|
||||
struct cursor saved_cursor;
|
||||
struct cursor alt_saved_cursor;
|
||||
enum cursor_style default_cursor_style;
|
||||
enum cursor_style cursor_style;
|
||||
struct {
|
||||
|
|
|
|||
16
vt.c
16
vt.c
|
|
@ -146,13 +146,13 @@ action_execute(struct terminal *term, uint8_t c)
|
|||
/* HT - horizontal tab */
|
||||
int new_col = term->cols - 1;
|
||||
tll_foreach(term->tab_stops, it) {
|
||||
if (it->item > term->cursor.point.col) {
|
||||
if (it->item > term->grid->cursor.point.col) {
|
||||
new_col = it->item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(new_col >= term->cursor.point.col);
|
||||
term_cursor_right(term, new_col - term->cursor.point.col);
|
||||
assert(new_col >= term->grid->cursor.point.col);
|
||||
term_cursor_right(term, new_col - term->grid->cursor.point.col);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -341,13 +341,13 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
|||
case 0:
|
||||
switch (final) {
|
||||
case '7':
|
||||
term->saved_cursor = term->cursor;
|
||||
term->grid->saved_cursor = term->grid->cursor;
|
||||
term->vt.saved_attrs = term->vt.attrs;
|
||||
term->saved_charsets = term->charsets;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
term_restore_cursor(term, &term->saved_cursor);
|
||||
term_restore_cursor(term, &term->grid->saved_cursor);
|
||||
term->vt.attrs = term->vt.saved_attrs;
|
||||
term->charsets = term->saved_charsets;
|
||||
break;
|
||||
|
|
@ -367,13 +367,13 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
|||
|
||||
case 'H':
|
||||
tll_foreach(term->tab_stops, it) {
|
||||
if (it->item >= term->cursor.point.col) {
|
||||
tll_insert_before(term->tab_stops, it, term->cursor.point.col);
|
||||
if (it->item >= term->grid->cursor.point.col) {
|
||||
tll_insert_before(term->tab_stops, it, term->grid->cursor.point.col);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tll_push_back(term->tab_stops, term->cursor.point.col);
|
||||
tll_push_back(term->tab_stops, term->grid->cursor.point.col);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue