term: convert cell 'linefeed' attribute to a row 'linebreak' property

To do text reflow, we only need to know if a line has been explicitly
linebreaked or not. If not, that means it wrapped, and that we
should *not* insert a linebreak when reflowing text.

When reflowing text, when reaching the end of a row in the old grid,
only insert a linebreak in the new grid if the old row had been
explicitly linebreaked.

Furthermore, when reflowing text and wrapping a row in the new grid,
mark the previous row as linebreaked if either the last cell was
(the last column in the last row) empty, or the current cell (the
first column in the new row) is empty. If both are non-empty, then we
assume a linewrap.
This commit is contained in:
Daniel Eklöf 2020-02-14 22:39:26 +01:00
parent 60056fdd61
commit ce8005545d
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
5 changed files with 30 additions and 42 deletions

1
grid.c
View file

@ -28,6 +28,7 @@ grid_row_alloc(int cols, bool initialize)
{ {
struct row *row = malloc(sizeof(*row)); struct row *row = malloc(sizeof(*row));
row->dirty = false; row->dirty = false;
row->linebreak = false;
if (initialize) { if (initialize) {
row->cells = calloc(cols, sizeof(row->cells[0])); row->cells = calloc(cols, sizeof(row->cells[0]));

View file

@ -1009,17 +1009,16 @@ reflow(struct terminal *term, struct row **new_grid, int new_cols, int new_rows,
/* 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++) {
const struct cell *old_cell = &old_row->cells[c]; if (old_row->cells[c].wc == 0) {
if (old_cell->wc == 0) {
empty_count++; empty_count++;
continue; continue;
} }
assert(old_cell->wc != 0); int old_cols_left = old_cols - c;
int cols_needed = empty_count + old_cols_left;
/* Non-empty cell. Emit preceeding string of empty cells, int new_cols_left = new_cols - new_col_idx;
* and possibly line break for current cell */ if (new_cols_left < cols_needed && new_cols_left >= old_cols_left)
empty_count = max(0, empty_count - (cols_needed - new_cols_left));
for (int i = 0; i < empty_count + 1; i++) { for (int i = 0; i < empty_count + 1; i++) {
if (new_col_idx >= new_cols) { if (new_col_idx >= new_cols) {
@ -1036,32 +1035,30 @@ reflow(struct terminal *term, struct row **new_grid, int new_cols, int new_rows,
new_row->dirty = true; new_row->dirty = true;
} }
assert(new_row != NULL);
assert(new_col_idx >= 0);
assert(new_col_idx < new_cols);
const struct cell *old_cell = &old_row->cells[c - empty_count + i];
if (new_col_idx == 0 && new_row_idx > 0 &&
(new_grid[new_row_idx - 1]->cells[new_cols - 1].wc == 0 ||
old_cell->wc == 0))
{
new_grid[new_row_idx - 1]->linebreak = true;
}
new_row->cells[new_col_idx] = *old_cell;
new_row->cells[new_col_idx].attrs.clean = 1;
new_col_idx++; new_col_idx++;
} }
empty_count = 0; empty_count = 0;
new_col_idx--;
assert(new_row != NULL);
assert(new_col_idx >= 0);
assert(new_col_idx < new_cols);
/* Copy current cell */
new_row->cells[new_col_idx].attrs.clean = 1;
new_row->cells[new_col_idx++] = *old_cell;
} }
/* if (old_row->linebreak) {
* If last cell of the old grid's line is empty, then we new_row->linebreak = true;
* insert a linebreak in the new grid's line too. Unless, the
* *entire* old line was empty.
*/
if (empty_count < old_cols &&
//r < old_rows - 1 &&
(old_row->cells[old_cols - 1].wc == 0 ||
old_row->cells[old_cols - 1].attrs.linefeed))
{
new_col_idx = 0; new_col_idx = 0;
new_row_idx = (new_row_idx + 1) & (new_rows - 1); new_row_idx = (new_row_idx + 1) & (new_rows - 1);
@ -1237,19 +1234,12 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
while (cursor_row < 0) while (cursor_row < 0)
cursor_row += term->grid->num_rows; cursor_row += term->grid->num_rows;
/* Heuristic to prevent a new prompt from being printed a new line */
bool do_linefeed = false;
if (term->cursor.point.col > 0)
cursor_row--;
else if (cursor_row >= term->rows)
do_linefeed = true;
term_cursor_to( term_cursor_to(
term, term,
min(max(cursor_row, 0), term->rows - 1), min(max(cursor_row, 0), term->rows - 1),
min(term->cursor.point.col, term->cols - 1)); min(term->cursor.point.col, term->cols - 1));
if (do_linefeed) if (cursor_row >= term->rows)
term_linefeed(term); term_linefeed(term);
term->render.last_cursor.cell = NULL; term->render.last_cursor.cell = NULL;

View file

@ -213,7 +213,7 @@ extract_one(struct terminal *term, struct row *row, struct cell *cell,
if (ctx->last_row != NULL && row != ctx->last_row && if (ctx->last_row != NULL && row != ctx->last_row &&
((term->selection.kind == SELECTION_NORMAL && ((term->selection.kind == SELECTION_NORMAL &&
(ctx->last_cell->wc == 0 || ctx->last_cell->attrs.linefeed)) || ctx->last_row->linebreak) ||
term->selection.kind == SELECTION_BLOCK)) term->selection.kind == SELECTION_BLOCK))
{ {
/* Last cell was the last column in the selection */ /* Last cell was the last column in the selection */

View file

@ -1253,6 +1253,7 @@ static inline void
erase_line(struct terminal *term, struct row *row) erase_line(struct terminal *term, struct row *row)
{ {
erase_cell_range(term, row, 0, term->cols - 1); erase_cell_range(term, row, 0, term->cols - 1);
row->linebreak = false;
} }
void void
@ -1498,17 +1499,13 @@ term_scroll_reverse(struct terminal *term, int rows)
void void
term_formfeed(struct terminal *term) term_formfeed(struct terminal *term)
{ {
int col = term->cursor.point.col;
if (!term->cursor.lcf)
col--;
if (col >= 0)
term->grid->cur_row->cells[col].attrs.linefeed = 1;
term_cursor_left(term, term->cursor.point.col); term_cursor_left(term, term->cursor.point.col);
} }
void void
term_linefeed(struct terminal *term) term_linefeed(struct terminal *term)
{ {
term->grid->cur_row->linebreak = true;
if (term->cursor.point.row == term->scroll_region.end - 1) if (term->cursor.point.row == term->scroll_region.end - 1)
term_scroll(term, 1); term_scroll(term, 1);
else else

View file

@ -42,8 +42,7 @@ struct attributes {
uint32_t have_fg:1; uint32_t have_fg:1;
uint32_t have_bg:1; uint32_t have_bg:1;
uint32_t selected:2; uint32_t selected:2;
uint32_t linefeed:1; uint32_t reserved:3;
uint32_t reserved:2;
uint32_t bg:24; uint32_t bg:24;
}; };
static_assert(sizeof(struct attributes) == 8, "bad size"); static_assert(sizeof(struct attributes) == 8, "bad size");
@ -84,6 +83,7 @@ struct damage {
struct row { struct row {
struct cell *cells; struct cell *cells;
bool dirty; bool dirty;
bool linebreak;
}; };
struct grid { struct grid {