grid: change default value of linebreak to true

This way, all lines are treated as having a hard linebreak, until it's
cleared when we do an auto-wrap.

This change alone causes issues when reflowing text, as now all
trailing lines in an otherwise empty window are treated as hard
linebreaks, causing the new grid to insert lots of unwanted, empty
lines.

Fix by doing two things:

* *clear* the linebreak flag when we pull in new lines for the new
  grid. We only want to set it explicitly, when an old row has its
  linebreak flag set.
* Coalesce empty lines with linebreak=true, and only "emit" them as
  new liens in the new grid if they are followed by non-empty lines.
This commit is contained in:
Daniel Eklöf 2025-03-04 08:34:18 +01:00
parent a80b32d006
commit 7b6efcf19a
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 61 additions and 28 deletions

87
grid.c
View file

@ -439,7 +439,7 @@ grid_row_alloc(int cols, bool initialize)
{
struct row *row = xmalloc(sizeof(*row));
row->dirty = false;
row->linebreak = false;
row->linebreak = true;
row->extra = NULL;
row->shell_integration.prompt_marker = false;
row->shell_integration.cmd_start = -1;
@ -709,14 +709,21 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row,
/* Scrollback not yet full, allocate a completely new row */
new_row = grid_row_alloc(col_count, false);
new_grid[*row_idx] = new_row;
/* *clear* linebreak, since we only want to set it when we
reach the end of an old row, with linebreak=true */
new_row->linebreak = false;
} else {
/* Scrollback is full, need to reuse a row */
grid_row_reset_extra(new_row);
new_row->linebreak = false;
new_row->shell_integration.prompt_marker = false;
new_row->shell_integration.cmd_start = -1;
new_row->shell_integration.cmd_end = -1;
/* *clear* linebreak, since we only want to set it when we
reach the end of an old row, with linebreak=true */
new_row->linebreak = false;
tll_foreach(old_grid->sixel_images, it) {
if (it->item.pos.row == *row_idx) {
sixel_destroy(&it->item);
@ -894,6 +901,8 @@ grid_resize_and_reflow(
i, tracking_points[i]->row, tracking_points[i]->col);
}
int coalesced_linebreaks = 0;
/*
* Walk the old grid
*/
@ -984,6 +993,20 @@ grid_resize_and_reflow(
} else
underline_range = underline_range_terminator = NULL;
if (unlikely(col_count > 0 && coalesced_linebreaks > 0)) {
for (size_t apa = 0; apa < coalesced_linebreaks; apa++) {
/* Erase the remaining cells */
memset(&new_row->cells[new_col_idx], 0,
(new_cols - new_col_idx) * sizeof(new_row->cells[0]));
new_row->linebreak = true;
if (r + 1 < old_rows)
line_wrap();
}
coalesced_linebreaks = 0;
}
for (int c = 0; c < col_count;) {
const struct cell *old = &old_row->cells[c];
@ -1095,33 +1118,43 @@ grid_resize_and_reflow(
}
if (old_row->linebreak) {
/* Erase the remaining cells */
memset(&new_row->cells[new_col_idx], 0,
(new_cols - new_col_idx) * sizeof(new_row->cells[0]));
new_row->linebreak = true;
if (r + 1 < old_rows)
line_wrap();
else if (new_row->extra != NULL) {
if (new_row->extra->uri_ranges.count > 0) {
/*
* line_wrap() "closes" still-open URIs. Since
* this is the *last* row, and since we're
* line-breaking due to a hard line-break (rather
* than running out of cells in the "new_row"),
* there shouldn't be an open URI (it would have
* been closed when we reached the end of the URI
* while reflowing the last "old" row).
*/
int last_idx = new_row->extra->uri_ranges.count - 1;
xassert(new_row->extra->uri_ranges.v[last_idx].end >= 0);
}
if (new_row->extra->underline_ranges.count > 0) {
int last_idx = new_row->extra->underline_ranges.count - 1;
xassert(new_row->extra->underline_ranges.v[last_idx].end >= 0);
if (col_count > 0) {
/* Erase the remaining cells */
memset(&new_row->cells[new_col_idx], 0,
(new_cols - new_col_idx) * sizeof(new_row->cells[0]));
new_row->linebreak = true;
if (r + 1 < old_rows) {
/* Not the last (old) row */
line_wrap();
} else if (new_row->extra != NULL) {
if (new_row->extra->uri_ranges.count > 0) {
/*
* line_wrap() "closes" still-open URIs. Since
* this is the *last* row, and since we're
* line-breaking due to a hard line-break (rather
* than running out of cells in the "new_row"),
* there shouldn't be an open URI (it would have
* been closed when we reached the end of the URI
* while reflowing the last "old" row).
*/
int last_idx = new_row->extra->uri_ranges.count - 1;
xassert(new_row->extra->uri_ranges.v[last_idx].end >= 0);
}
if (new_row->extra->underline_ranges.count > 0) {
int last_idx = new_row->extra->underline_ranges.count - 1;
xassert(new_row->extra->underline_ranges.v[last_idx].end >= 0);
}
}
} else {
/*
* rows have linebreak=true by default. But we don't
* want trailing empty lines to result in actual lines
* in the new grid (think: empty window with prompt at
* the top)
*/
coalesced_linebreaks++;
}
}

View file

@ -2057,7 +2057,7 @@ static inline void
erase_line(struct terminal *term, struct row *row)
{
erase_cell_range(term, row, 0, term->cols - 1);
row->linebreak = false;
row->linebreak = true;
row->shell_integration.prompt_marker = false;
row->shell_integration.cmd_start = -1;
row->shell_integration.cmd_end = -1;