mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-24 09:05:48 -04: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".
|
* Alt+Return to emit "ESC \r".
|
||||||
* Trackpad sloooow scrolling to eventually scroll a line.
|
* Trackpad sloooow scrolling to eventually scroll a line.
|
||||||
* Memory leak in terminal reset.
|
* Memory leak in terminal reset.
|
||||||
|
* Translation of cursor coordinates on resize
|
||||||
|
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
|
||||||
128
csi.c
128
csi.c
|
|
@ -382,7 +382,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
/* VPA - vertical line position absolute */
|
/* VPA - vertical line position absolute */
|
||||||
int rel_row = vt_param_get(term, 0, 1) - 1;
|
int rel_row = vt_param_get(term, 0, 1) - 1;
|
||||||
int row = term_row_rel_to_abs(term, rel_row);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -411,13 +411,13 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
case 'E':
|
case 'E':
|
||||||
/* CNL - Cursor Next Line */
|
/* CNL - Cursor Next Line */
|
||||||
term_cursor_down(term, vt_param_get(term, 0, 1));
|
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;
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
/* CPL - Cursor Previous Line */
|
/* CPL - Cursor Previous Line */
|
||||||
term_cursor_up(term, vt_param_get(term, 0, 1));
|
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;
|
break;
|
||||||
|
|
||||||
case 'g': {
|
case 'g': {
|
||||||
|
|
@ -426,9 +426,9 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
case 0:
|
case 0:
|
||||||
/* Clear tab stop at *current* column */
|
/* Clear tab stop at *current* column */
|
||||||
tll_foreach(term->tab_stops, it) {
|
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);
|
tll_remove(term->tab_stops, it);
|
||||||
else if (it->item > term->cursor.point.col)
|
else if (it->item > term->grid->cursor.point.col)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,7 +450,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
case 'G': {
|
case 'G': {
|
||||||
/* Cursor horizontal absolute */
|
/* Cursor horizontal absolute */
|
||||||
int col = min(vt_param_get(term, 0, 1), term->cols) - 1;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -473,15 +473,15 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
/* From cursor to end of screen */
|
/* From cursor to end of screen */
|
||||||
term_erase(
|
term_erase(
|
||||||
term,
|
term,
|
||||||
&term->cursor.point,
|
&term->grid->cursor.point,
|
||||||
&(struct coord){term->cols - 1, term->rows - 1});
|
&(struct coord){term->cols - 1, term->rows - 1});
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
/* From start of screen to cursor */
|
/* From start of screen to cursor */
|
||||||
term_erase(term, &(struct coord){0, 0}, &term->cursor.point);
|
term_erase(term, &(struct coord){0, 0}, &term->grid->cursor.point);
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
|
@ -490,7 +490,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
term,
|
term,
|
||||||
&(struct coord){0, 0},
|
&(struct coord){0, 0},
|
||||||
&(struct coord){term->cols - 1, term->rows - 1});
|
&(struct coord){term->cols - 1, term->rows - 1});
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: {
|
case 3: {
|
||||||
|
|
@ -531,25 +531,25 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
/* From cursor to end of line */
|
/* From cursor to end of line */
|
||||||
term_erase(
|
term_erase(
|
||||||
term,
|
term,
|
||||||
&term->cursor.point,
|
&term->grid->cursor.point,
|
||||||
&(struct coord){term->cols - 1, term->cursor.point.row});
|
&(struct coord){term->cols - 1, term->grid->cursor.point.row});
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
/* From start of line to cursor */
|
/* From start of line to cursor */
|
||||||
term_erase(
|
term_erase(
|
||||||
term, &(struct coord){0, term->cursor.point.row}, &term->cursor.point);
|
term, &(struct coord){0, term->grid->cursor.point.row}, &term->grid->cursor.point);
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
/* Entire line */
|
/* Entire line */
|
||||||
term_erase(
|
term_erase(
|
||||||
term,
|
term,
|
||||||
&(struct coord){0, term->cursor.point.row},
|
&(struct coord){0, term->grid->cursor.point.row},
|
||||||
&(struct coord){term->cols - 1, term->cursor.point.row});
|
&(struct coord){term->cols - 1, term->grid->cursor.point.row});
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -561,36 +561,36 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'L': {
|
case 'L': {
|
||||||
if (term->cursor.point.row < term->scroll_region.start ||
|
if (term->grid->cursor.point.row < term->scroll_region.start ||
|
||||||
term->cursor.point.row >= term->scroll_region.end)
|
term->grid->cursor.point.row >= term->scroll_region.end)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int count = min(
|
int count = min(
|
||||||
vt_param_get(term, 0, 1),
|
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_scroll_reverse_partial(
|
||||||
term,
|
term,
|
||||||
(struct scroll_region){
|
(struct scroll_region){
|
||||||
.start = term->cursor.point.row,
|
.start = term->grid->cursor.point.row,
|
||||||
.end = term->scroll_region.end},
|
.end = term->scroll_region.end},
|
||||||
count);
|
count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'M': {
|
case 'M': {
|
||||||
if (term->cursor.point.row < term->scroll_region.start ||
|
if (term->grid->cursor.point.row < term->scroll_region.start ||
|
||||||
term->cursor.point.row >= term->scroll_region.end)
|
term->grid->cursor.point.row >= term->scroll_region.end)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int count = min(
|
int count = min(
|
||||||
vt_param_get(term, 0, 1),
|
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_scroll_partial(
|
||||||
term,
|
term,
|
||||||
(struct scroll_region){
|
(struct scroll_region){
|
||||||
.start = term->cursor.point.row,
|
.start = term->grid->cursor.point.row,
|
||||||
.end = term->scroll_region.end},
|
.end = term->scroll_region.end},
|
||||||
count);
|
count);
|
||||||
break;
|
break;
|
||||||
|
|
@ -601,26 +601,26 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
|
|
||||||
/* Number of characters to delete */
|
/* Number of characters to delete */
|
||||||
int count = min(
|
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) */
|
/* 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 */
|
/* 'Delete' characters by moving the remaining ones */
|
||||||
memmove(&term->grid->cur_row->cells[term->cursor.point.col],
|
memmove(&term->grid->cur_row->cells[term->grid->cursor.point.col],
|
||||||
&term->grid->cur_row->cells[term->cursor.point.col + count],
|
&term->grid->cur_row->cells[term->grid->cursor.point.col + count],
|
||||||
remaining * sizeof(term->grid->cur_row->cells[0]));
|
remaining * sizeof(term->grid->cur_row->cells[0]));
|
||||||
|
|
||||||
for (size_t c = 0; c < remaining; c++)
|
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;
|
term->grid->cur_row->dirty = true;
|
||||||
|
|
||||||
/* Erase the remainder of the line */
|
/* Erase the remainder of the line */
|
||||||
term_erase(
|
term_erase(
|
||||||
term,
|
term,
|
||||||
&(struct coord){term->cursor.point.col + remaining, term->cursor.point.row},
|
&(struct coord){term->grid->cursor.point.col + remaining, term->grid->cursor.point.row},
|
||||||
&(struct coord){term->cols - 1, term->cursor.point.row});
|
&(struct coord){term->cols - 1, term->grid->cursor.point.row});
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -629,25 +629,25 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
|
|
||||||
/* Number of characters to insert */
|
/* Number of characters to insert */
|
||||||
int count = min(
|
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 */
|
/* 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 */
|
/* Push existing characters */
|
||||||
memmove(&term->grid->cur_row->cells[term->cursor.point.col + count],
|
memmove(&term->grid->cur_row->cells[term->grid->cursor.point.col + count],
|
||||||
&term->grid->cur_row->cells[term->cursor.point.col],
|
&term->grid->cur_row->cells[term->grid->cursor.point.col],
|
||||||
remaining * sizeof(term->grid->cur_row->cells[0]));
|
remaining * sizeof(term->grid->cur_row->cells[0]));
|
||||||
for (size_t c = 0; c < remaining; c++)
|
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;
|
term->grid->cur_row->dirty = true;
|
||||||
|
|
||||||
/* Erase (insert space characters) */
|
/* Erase (insert space characters) */
|
||||||
term_erase(
|
term_erase(
|
||||||
term,
|
term,
|
||||||
&term->cursor.point,
|
&term->grid->cursor.point,
|
||||||
&(struct coord){term->cursor.point.col + count - 1, term->cursor.point.row});
|
&(struct coord){term->grid->cursor.point.col + count - 1, term->grid->cursor.point.row});
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -662,13 +662,13 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
case 'X': {
|
case 'X': {
|
||||||
/* Erase chars */
|
/* Erase chars */
|
||||||
int count = min(
|
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_erase(
|
||||||
term,
|
term,
|
||||||
&term->cursor.point,
|
&term->grid->cursor.point,
|
||||||
&(struct coord){term->cursor.point.col + count - 1, term->cursor.point.row});
|
&(struct coord){term->grid->cursor.point.col + count - 1, term->grid->cursor.point.row});
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
break;
|
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++) {
|
for (int i = 0; i < vt_param_get(term, 0, 1); i++) {
|
||||||
int new_col = term->cols - 1;
|
int new_col = term->cols - 1;
|
||||||
tll_foreach(term->tab_stops, it) {
|
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;
|
new_col = it->item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(new_col >= term->cursor.point.col);
|
assert(new_col >= term->grid->cursor.point.col);
|
||||||
term_cursor_right(term, new_col - term->cursor.point.col);
|
term_cursor_right(term, new_col - term->grid->cursor.point.col);
|
||||||
}
|
}
|
||||||
break;
|
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++) {
|
for (int i = 0; i < vt_param_get(term, 0, 1); i++) {
|
||||||
int new_col = 0;
|
int new_col = 0;
|
||||||
tll_rforeach(term->tab_stops, it) {
|
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;
|
new_col = it->item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(term->cursor.point.col >= new_col);
|
assert(term->grid->cursor.point.col >= new_col);
|
||||||
term_cursor_left(term, term->cursor.point.col - new_col);
|
term_cursor_left(term, term->grid->cursor.point.col - new_col);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -757,11 +757,11 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
term->saved_cursor = term->cursor;
|
term->grid->saved_cursor = term->grid->cursor;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
term_restore_cursor(term, &term->saved_cursor);
|
term_restore_cursor(term, &term->grid->saved_cursor);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't': {
|
case 't': {
|
||||||
|
|
@ -861,15 +861,15 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
/* u7 - cursor position query */
|
/* u7 - cursor position query */
|
||||||
|
|
||||||
int row = term->origin == ORIGIN_ABSOLUTE
|
int row = term->origin == ORIGIN_ABSOLUTE
|
||||||
? term->cursor.point.row
|
? term->grid->cursor.point.row
|
||||||
: term->cursor.point.row - term->scroll_region.start;
|
: term->grid->cursor.point.row - term->scroll_region.start;
|
||||||
|
|
||||||
/* TODO: we use 0-based position, while the xterm
|
/* TODO: we use 0-based position, while the xterm
|
||||||
* terminfo says the receiver of the reply should
|
* terminfo says the receiver of the reply should
|
||||||
* decrement, hence we must add 1 */
|
* decrement, hence we must add 1 */
|
||||||
char reply[64];
|
char reply[64];
|
||||||
snprintf(reply, sizeof(reply), "\x1b[%d;%dR",
|
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));
|
term_to_slave(term, reply, strlen(reply));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1014,9 +1014,11 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
selection_cancel(term);
|
selection_cancel(term);
|
||||||
|
|
||||||
term->grid = &term->alt;
|
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.damage);
|
||||||
tll_free(term->alt.scroll_damage);
|
tll_free(term->alt.scroll_damage);
|
||||||
|
|
@ -1137,7 +1139,11 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
selection_cancel(term);
|
selection_cancel(term);
|
||||||
|
|
||||||
term->grid = &term->normal;
|
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.damage);
|
||||||
tll_free(term->alt.scroll_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);
|
free(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
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;
|
struct row *const *old_grid = grid->rows;
|
||||||
const int old_rows = grid->num_rows;
|
const int old_rows = grid->num_rows;
|
||||||
const int old_cols = grid->num_cols;
|
const int old_cols = grid->num_cols;
|
||||||
|
|
||||||
//assert(old_rows != new_rows || old_cols != new_cols);
|
|
||||||
|
|
||||||
int new_col_idx = 0;
|
int new_col_idx = 0;
|
||||||
int new_row_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();
|
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
|
* Walk the old grid
|
||||||
*/
|
*/
|
||||||
for (int r = 0; r < old_rows; r++) {
|
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 */
|
/* 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)
|
if (old_row == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -102,7 +120,7 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
||||||
* the "real" sixel list.
|
* the "real" sixel list.
|
||||||
*/
|
*/
|
||||||
tll_foreach(grid->sixel_images, it) {
|
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;
|
struct sixel six = it->item;
|
||||||
six.pos.row = new_row_idx;
|
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
|
* 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,
|
* 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 */
|
/* Walk current line of the old grid */
|
||||||
for (int c = 0; c < old_cols; c++) {
|
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++;
|
empty_count++;
|
||||||
continue;
|
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 old_cols_left = old_cols - c;
|
||||||
int cols_needed = empty_count + old_cols_left;
|
int cols_needed = empty_count + old_cols_left;
|
||||||
int new_cols_left = new_cols - new_col_idx;
|
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? */
|
/* Out of columns on current row in new grid? */
|
||||||
if (new_col_idx >= new_cols) {
|
if (new_col_idx >= new_cols) {
|
||||||
|
#if 0
|
||||||
/*
|
/*
|
||||||
* If last cell on last row and first cell on new
|
* If last cell on last row and first cell on new
|
||||||
* row are non-empty, wrap the line, otherwise
|
* 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_row->linebreak = true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
new_col_idx = 0;
|
line_wrap();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(new_row != NULL);
|
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] = *old_cell;
|
||||||
new_row->cells[new_col_idx].attrs.clean = 1;
|
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++;
|
new_col_idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,19 +223,10 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
|
||||||
|
|
||||||
if (old_row->linebreak) {
|
if (old_row->linebreak) {
|
||||||
new_row->linebreak = true;
|
new_row->linebreak = true;
|
||||||
|
line_wrap();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef line_wrap
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set offset such that the last reflowed row is at the bottom */
|
/* 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]);
|
grid_row_free(old_grid[r]);
|
||||||
free(grid->rows);
|
free(grid->rows);
|
||||||
|
|
||||||
grid->cur_row = new_grid[new_row_idx];
|
grid->cur_row = new_grid[cursor.row];
|
||||||
grid->rows = new_grid;
|
grid->rows = new_grid;
|
||||||
grid->num_rows = new_rows;
|
grid->num_rows = new_rows;
|
||||||
grid->num_cols = new_cols;
|
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 */
|
/* Destroy any non-moved sixels */
|
||||||
tll_foreach(grid->sixel_images, it)
|
tll_foreach(grid->sixel_images, it)
|
||||||
sixel_destroy(&it->item);
|
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_push_back(grid->sixel_images, it->item);
|
||||||
tll_free(new_sixels);
|
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);
|
void grid_swap_row(struct grid *grid, int row_a, int row_b, bool initialize);
|
||||||
struct row *grid_row_alloc(int cols, bool initialize);
|
struct row *grid_row_alloc(int cols, bool initialize);
|
||||||
void grid_row_free(struct row *row);
|
void grid_row_free(struct row *row);
|
||||||
int grid_reflow(
|
void grid_reflow(
|
||||||
struct grid *grid, int new_rows, int new_cols,
|
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
|
static inline int
|
||||||
grid_row_absolute(const struct grid *grid, int row_no)
|
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;
|
bool cursor_is_visible = false;
|
||||||
int view_end = (term->grid->view + term->rows - 1) & (term->grid->num_rows - 1);
|
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) {
|
if (view_end >= term->grid->view) {
|
||||||
/* Not wrapped */
|
/* Not wrapped */
|
||||||
if (cursor_row >= term->grid->view && cursor_row <= view_end)
|
if (cursor_row >= term->grid->view && cursor_row <= view_end)
|
||||||
|
|
@ -1401,21 +1401,21 @@ grid_render(struct terminal *term)
|
||||||
int view_aligned_row
|
int view_aligned_row
|
||||||
= (cursor_row - term->grid->view + term->grid->num_rows) & (term->grid->num_rows - 1);
|
= (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->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 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;
|
cell->attrs.clean = 0;
|
||||||
term->render.last_cursor.cell = cell;
|
term->render.last_cursor.cell = cell;
|
||||||
int cols_updated = render_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(
|
wl_surface_damage_buffer(
|
||||||
term->window->surface,
|
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,
|
term->margins.top + view_aligned_row * term->cell_height,
|
||||||
cols_updated * term->cell_width, 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)
|
if (!force && width == term->width && height == term->height && scale == term->scale)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
selection_cancel(term);
|
|
||||||
|
|
||||||
/* Cancel an application initiated "Synchronized Update" */
|
/* Cancel an application initiated "Synchronized Update" */
|
||||||
term_disable_app_sync_updates(term);
|
term_disable_app_sync_updates(term);
|
||||||
|
|
||||||
|
|
@ -1754,10 +1752,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reflow grids */
|
/* Reflow grids */
|
||||||
int last_normal_row = grid_reflow(
|
grid_reflow(&term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows, 0, NULL);
|
||||||
&term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows);
|
grid_reflow(&term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows, 0, NULL);
|
||||||
int last_alt_row = grid_reflow(
|
|
||||||
&term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows);
|
|
||||||
|
|
||||||
/* Reset tab stops */
|
/* Reset tab stops */
|
||||||
tll_free(term->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)
|
if (term->scroll_region.end >= old_rows)
|
||||||
term->scroll_region.end = term->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;
|
term->render.last_cursor.cell = NULL;
|
||||||
|
|
||||||
damage_view:
|
damage_view:
|
||||||
|
|
@ -1846,6 +1812,12 @@ damage_view:
|
||||||
term->height / term->scale + title_height);
|
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->normal.scroll_damage);
|
||||||
tll_free(term->alt.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
|
void
|
||||||
sixel_delete_at_cursor(struct terminal *term)
|
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
|
void
|
||||||
|
|
@ -142,8 +142,8 @@ sixel_unhook(struct terminal *term)
|
||||||
.height = term->sixel.image.height,
|
.height = term->sixel.image.height,
|
||||||
.rows = (term->sixel.image.height + term->cell_height - 1) / term->cell_height,
|
.rows = (term->sixel.image.height + term->cell_height - 1) / term->cell_height,
|
||||||
.pos = (struct coord){
|
.pos = (struct coord){
|
||||||
term->cursor.point.col,
|
term->grid->cursor.point.col,
|
||||||
(term->grid->offset + term->cursor.point.row) & (term->grid->num_rows - 1)},
|
(term->grid->offset + term->grid->cursor.point.row) & (term->grid->num_rows - 1)},
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_DBG("generating %dx%d pixman image", image.width, image.height);
|
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
|
static void
|
||||||
cursor_refresh(struct terminal *term)
|
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;
|
term->grid->cur_row->dirty = true;
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
}
|
}
|
||||||
|
|
@ -1163,7 +1163,6 @@ term_reset(struct terminal *term, bool hard)
|
||||||
|
|
||||||
if (term->grid == &term->alt) {
|
if (term->grid == &term->alt) {
|
||||||
term->grid = &term->normal;
|
term->grid = &term->normal;
|
||||||
term_restore_cursor(term, &term->alt_saved_cursor);
|
|
||||||
selection_cancel(term);
|
selection_cancel(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1188,10 +1187,12 @@ term_reset(struct terminal *term, bool hard)
|
||||||
for (size_t i = 0; i < 256; i++)
|
for (size_t i = 0; i < 256; i++)
|
||||||
term->colors.table[i] = term->colors.default_table[i];
|
term->colors.table[i] = term->colors.default_table[i];
|
||||||
term->origin = ORIGIN_ABSOLUTE;
|
term->origin = ORIGIN_ABSOLUTE;
|
||||||
term->cursor.lcf = false;
|
term->normal.cursor.lcf = false;
|
||||||
term->cursor = (struct cursor){.point = {0, 0}};
|
term->alt.cursor.lcf = false;
|
||||||
term->saved_cursor = (struct cursor){.point = {0, 0}};
|
term->normal.cursor = (struct cursor){.point = {0, 0}};
|
||||||
term->alt_saved_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_style = term->default_cursor_style;
|
||||||
term_cursor_blink_disable(term);
|
term_cursor_blink_disable(term);
|
||||||
term->cursor_color.text = term->default_cursor_color.text;
|
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(row < term->rows);
|
||||||
assert(col < term->cols);
|
assert(col < term->cols);
|
||||||
|
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
|
|
||||||
term->cursor.point.col = col;
|
term->grid->cursor.point.col = col;
|
||||||
term->cursor.point.row = row;
|
term->grid->cursor.point.row = row;
|
||||||
|
|
||||||
term->grid->cur_row = grid_row(term->grid, row);
|
term->grid->cur_row = grid_row(term->grid, row);
|
||||||
}
|
}
|
||||||
|
|
@ -1448,39 +1449,39 @@ term_cursor_home(struct terminal *term)
|
||||||
void
|
void
|
||||||
term_cursor_left(struct terminal *term, int count)
|
term_cursor_left(struct terminal *term, int count)
|
||||||
{
|
{
|
||||||
int move_amount = min(term->cursor.point.col, count);
|
int move_amount = min(term->grid->cursor.point.col, count);
|
||||||
term->cursor.point.col -= move_amount;
|
term->grid->cursor.point.col -= move_amount;
|
||||||
assert(term->cursor.point.col >= 0);
|
assert(term->grid->cursor.point.col >= 0);
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
term_cursor_right(struct terminal *term, int count)
|
term_cursor_right(struct terminal *term, int count)
|
||||||
{
|
{
|
||||||
int move_amount = min(term->cols - term->cursor.point.col - 1, count);
|
int move_amount = min(term->cols - term->grid->cursor.point.col - 1, count);
|
||||||
term->cursor.point.col += move_amount;
|
term->grid->cursor.point.col += move_amount;
|
||||||
assert(term->cursor.point.col < term->cols);
|
assert(term->grid->cursor.point.col < term->cols);
|
||||||
term->cursor.lcf = false;
|
term->grid->cursor.lcf = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
term_cursor_up(struct terminal *term, int count)
|
term_cursor_up(struct terminal *term, int count)
|
||||||
{
|
{
|
||||||
int top = term->origin == ORIGIN_ABSOLUTE ? 0 : term->scroll_region.start;
|
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);
|
int move_amount = min(term->grid->cursor.point.row - top, count);
|
||||||
term_cursor_to(term, term->cursor.point.row - move_amount, term->cursor.point.col);
|
term_cursor_to(term, term->grid->cursor.point.row - move_amount, term->grid->cursor.point.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
term_cursor_down(struct terminal *term, int count)
|
term_cursor_down(struct terminal *term, int count)
|
||||||
{
|
{
|
||||||
int bottom = term->origin == ORIGIN_ABSOLUTE ? term->rows : term->scroll_region.end;
|
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);
|
int move_amount = min(bottom - term->grid->cursor.point.row - 1, count);
|
||||||
term_cursor_to(term, term->cursor.point.row + move_amount, term->cursor.point.col);
|
term_cursor_to(term, term->grid->cursor.point.row + move_amount, term->grid->cursor.point.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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);
|
sixel_delete_in_range(term, max(region.end - rows, region.start), region.end - 1);
|
||||||
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
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
|
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);
|
sixel_delete_in_range(term, region.start, min(region.start + rows, region.end) - 1);
|
||||||
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
|
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
|
void
|
||||||
|
|
@ -1634,14 +1635,14 @@ term_scroll_reverse(struct terminal *term, int rows)
|
||||||
void
|
void
|
||||||
term_formfeed(struct terminal *term)
|
term_formfeed(struct terminal *term)
|
||||||
{
|
{
|
||||||
term_cursor_left(term, term->cursor.point.col);
|
term_cursor_left(term, term->grid->cursor.point.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
term_linefeed(struct terminal *term)
|
term_linefeed(struct terminal *term)
|
||||||
{
|
{
|
||||||
term->grid->cur_row->linebreak = true;
|
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);
|
term_scroll(term, 1);
|
||||||
else
|
else
|
||||||
term_cursor_down(term, 1);
|
term_cursor_down(term, 1);
|
||||||
|
|
@ -1650,7 +1651,7 @@ term_linefeed(struct terminal *term)
|
||||||
void
|
void
|
||||||
term_reverse_index(struct terminal *term)
|
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);
|
term_scroll_reverse(term, 1);
|
||||||
else
|
else
|
||||||
term_cursor_up(term, 1);
|
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 row = min(cursor->point.row, term->rows - 1);
|
||||||
int col = min(cursor->point.col, term->cols - 1);
|
int col = min(cursor->point.col, term->cols - 1);
|
||||||
term_cursor_to(term, row, col);
|
term_cursor_to(term, row, col);
|
||||||
term->cursor.lcf = cursor->lcf;
|
term->grid->cursor.lcf = cursor->lcf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2095,7 +2096,7 @@ term_disable_app_sync_updates(struct terminal *term)
|
||||||
static inline void
|
static inline void
|
||||||
print_linewrap(struct terminal *term)
|
print_linewrap(struct terminal *term)
|
||||||
{
|
{
|
||||||
if (likely(!term->cursor.lcf)) {
|
if (likely(!term->grid->cursor.lcf)) {
|
||||||
/* Not and end of line */
|
/* Not and end of line */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2105,11 +2106,11 @@ print_linewrap(struct terminal *term)
|
||||||
return;
|
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_scroll(term, 1);
|
||||||
term_cursor_to(term, term->cursor.point.row, 0);
|
term_cursor_to(term, term->grid->cursor.point.row, 0);
|
||||||
} else
|
} 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
|
static inline void
|
||||||
|
|
@ -2119,15 +2120,15 @@ print_insert(struct terminal *term, int width)
|
||||||
|
|
||||||
if (unlikely(term->insert_mode)) {
|
if (unlikely(term->insert_mode)) {
|
||||||
struct row *row = term->grid->cur_row;
|
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(
|
memmove(
|
||||||
&row->cells[term->cursor.point.col + width],
|
&row->cells[term->grid->cursor.point.col + width],
|
||||||
&row->cells[term->cursor.point.col],
|
&row->cells[term->grid->cursor.point.col],
|
||||||
move_count * sizeof(struct cell));
|
move_count * sizeof(struct cell));
|
||||||
|
|
||||||
/* Mark moved cells as dirty */
|
/* 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;
|
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 */
|
/* *Must* get current cell *after* linewrap+insert */
|
||||||
struct row *row = term->grid->cur_row;
|
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->wc = term->vt.last_printed = wc;
|
||||||
cell->attrs = term->vt.attrs;
|
cell->attrs = term->vt.attrs;
|
||||||
|
|
@ -2154,20 +2155,20 @@ term_print(struct terminal *term, wchar_t wc, int width)
|
||||||
cell->attrs.clean = 0;
|
cell->attrs.clean = 0;
|
||||||
|
|
||||||
/* Advance cursor the 'additional' columns while dirty:ing the cells */
|
/* 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);
|
term_cursor_right(term, 1);
|
||||||
|
|
||||||
assert(term->cursor.point.col < term->cols);
|
assert(term->grid->cursor.point.col < term->cols);
|
||||||
struct cell *cell = &row->cells[term->cursor.point.col];
|
struct cell *cell = &row->cells[term->grid->cursor.point.col];
|
||||||
cell->wc = 0;
|
cell->wc = 0;
|
||||||
cell->attrs.clean = 0;
|
cell->attrs.clean = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance cursor */
|
/* Advance cursor */
|
||||||
if (term->cursor.point.col < term->cols - 1)
|
if (term->grid->cursor.point.col < term->cols - 1)
|
||||||
term_cursor_right(term, 1);
|
term_cursor_right(term, 1);
|
||||||
else
|
else
|
||||||
term->cursor.lcf = true;
|
term->grid->cursor.lcf = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum term_surface
|
enum term_surface
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,9 @@ struct grid {
|
||||||
int offset;
|
int offset;
|
||||||
int view;
|
int view;
|
||||||
|
|
||||||
|
struct cursor cursor;
|
||||||
|
struct cursor saved_cursor;
|
||||||
|
|
||||||
struct row **rows;
|
struct row **rows;
|
||||||
struct row *cur_row;
|
struct row *cur_row;
|
||||||
|
|
||||||
|
|
@ -278,9 +281,6 @@ struct terminal {
|
||||||
} colors;
|
} colors;
|
||||||
|
|
||||||
enum cursor_origin origin;
|
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 default_cursor_style;
|
||||||
enum cursor_style cursor_style;
|
enum cursor_style cursor_style;
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
16
vt.c
16
vt.c
|
|
@ -146,13 +146,13 @@ action_execute(struct terminal *term, uint8_t c)
|
||||||
/* HT - horizontal tab */
|
/* HT - horizontal tab */
|
||||||
int new_col = term->cols - 1;
|
int new_col = term->cols - 1;
|
||||||
tll_foreach(term->tab_stops, it) {
|
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;
|
new_col = it->item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(new_col >= term->cursor.point.col);
|
assert(new_col >= term->grid->cursor.point.col);
|
||||||
term_cursor_right(term, new_col - term->cursor.point.col);
|
term_cursor_right(term, new_col - term->grid->cursor.point.col);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -341,13 +341,13 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
||||||
case 0:
|
case 0:
|
||||||
switch (final) {
|
switch (final) {
|
||||||
case '7':
|
case '7':
|
||||||
term->saved_cursor = term->cursor;
|
term->grid->saved_cursor = term->grid->cursor;
|
||||||
term->vt.saved_attrs = term->vt.attrs;
|
term->vt.saved_attrs = term->vt.attrs;
|
||||||
term->saved_charsets = term->charsets;
|
term->saved_charsets = term->charsets;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '8':
|
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->vt.attrs = term->vt.saved_attrs;
|
||||||
term->charsets = term->saved_charsets;
|
term->charsets = term->saved_charsets;
|
||||||
break;
|
break;
|
||||||
|
|
@ -367,13 +367,13 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
||||||
|
|
||||||
case 'H':
|
case 'H':
|
||||||
tll_foreach(term->tab_stops, it) {
|
tll_foreach(term->tab_stops, it) {
|
||||||
if (it->item >= term->cursor.point.col) {
|
if (it->item >= term->grid->cursor.point.col) {
|
||||||
tll_insert_before(term->tab_stops, it, term->cursor.point.col);
|
tll_insert_before(term->tab_stops, it, term->grid->cursor.point.col);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tll_push_back(term->tab_stops, term->cursor.point.col);
|
tll_push_back(term->tab_stops, term->grid->cursor.point.col);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'M':
|
case 'M':
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue