Merge branch 'multi-column-special-spacer-value'

This commit is contained in:
Daniel Eklöf 2020-07-15 08:20:10 +02:00
commit 6b0b3ddccc
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
6 changed files with 69 additions and 55 deletions

27
grid.c
View file

@ -183,6 +183,13 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
} \ } \
} while(0) } while(0)
#define print_spacer() \
do { \
new_row->cells[new_col_idx].wc = CELL_MULT_COL_SPACER; \
new_row->cells[new_col_idx].attrs = old_cell->attrs; \
new_row->cells[new_col_idx].attrs.clean = 1; \
} 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,
@ -222,12 +229,19 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
/* Multi-column characters are never cut in half */ /* Multi-column characters are never cut in half */
assert(c + width <= old_cols); assert(c + width <= old_cols);
for (int i = 0; i < empty_count + width; i++) { for (int i = 0; i < empty_count + 1; i++) {
const struct cell *old_cell = &old_row->cells[c - empty_count + i]; const struct cell *old_cell = &old_row->cells[c - empty_count + i];
if (old_cell->wc == CELL_MULT_COL_SPACER)
continue;
/* Out of columns on current row in new grid? */ /* Out of columns on current row in new grid? */
if (new_col_idx + max(1, wcwidth(old_cell->wc)) > new_cols) if (new_col_idx + max(1, wcwidth(old_cell->wc)) > new_cols) {
/* Pad to end-of-line with spacers, then line-wrap */
for (;new_col_idx < new_cols; new_col_idx++)
print_spacer();
line_wrap(); line_wrap();
}
assert(new_row != NULL); assert(new_row != NULL);
assert(new_col_idx >= 0); assert(new_col_idx >= 0);
@ -247,6 +261,14 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
} }
} }
new_col_idx++; new_col_idx++;
/* For multi-column characters, insert spacers in the
* subsequent cells */
for (size_t i = 0; i < width - 1; i++) {
assert(new_col_idx < new_cols);
print_spacer();
new_col_idx++;
}
} }
c += width - 1; c += width - 1;
@ -258,6 +280,7 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
line_wrap(); line_wrap();
} }
#undef print_spacer
#undef line_wrap #undef line_wrap
} }

View file

@ -408,10 +408,10 @@ render_cell(struct terminal *term, pixman_image_t *pix,
if (cell->wc != 0) { if (cell->wc != 0) {
wchar_t base = cell->wc; wchar_t base = cell->wc;
if (base >= COMB_CHARS_LO && if (base >= CELL_COMB_CHARS_LO &&
base < (COMB_CHARS_LO + term->composed_count)) base < (CELL_COMB_CHARS_LO + term->composed_count))
{ {
composed = &term->composed[base - COMB_CHARS_LO]; composed = &term->composed[base - CELL_COMB_CHARS_LO];
base = composed->base; base = composed->base;
} }
@ -438,7 +438,7 @@ render_cell(struct terminal *term, pixman_image_t *pix,
if (has_cursor && term->cursor_style == CURSOR_BLOCK && term->kbd_focus) if (has_cursor && term->cursor_style == CURSOR_BLOCK && term->kbd_focus)
draw_cursor(term, cell, font, pix, &fg, &bg, x, y, cell_cols); draw_cursor(term, cell, font, pix, &fg, &bg, x, y, cell_cols);
if (cell->wc == 0 || cell->attrs.conceal) if (cell->wc == 0 || cell->wc == CELL_MULT_COL_SPACER || cell->attrs.conceal)
goto draw_cursor; goto draw_cursor;
pixman_image_t *clr_pix = pixman_image_create_solid_fill(&fg); pixman_image_t *clr_pix = pixman_image_create_solid_fill(&fg);

View file

@ -134,9 +134,9 @@ foreach_selected_normal(
c <= (r == end_row ? end_col : term->cols - 1); c <= (r == end_row ? end_col : term->cols - 1);
c++) c++)
{ {
if (row->cells[c].wc == CELL_MULT_COL_SPACER)
continue;
cb(term, row, &row->cells[c], c, data); cb(term, row, &row->cells[c], c, data);
c += max(1, wcwidth(row->cells[c].wc)) - 1;
assert(c < term->cols);
} }
start_col = 0; start_col = 0;
@ -168,9 +168,9 @@ foreach_selected_block(
assert(row != NULL); assert(row != NULL);
for (int c = top_left.col; c <= bottom_right.col; c++) { for (int c = top_left.col; c <= bottom_right.col; c++) {
if (row->cells[c].wc == CELL_MULT_COL_SPACER)
continue;
cb(term, row, &row->cells[c], c, data); cb(term, row, &row->cells[c], c, data);
c += max(1, wcwidth(row->cells[c].wc)) - 1;
assert(c < term->cols);
} }
} }
} }
@ -273,22 +273,7 @@ extract_one(struct terminal *term, struct row *row, struct cell *cell,
/* New row - determine if we should insert a newline or not */ /* New row - determine if we should insert a newline or not */
if (term->selection.kind == SELECTION_NORMAL) { if (term->selection.kind == SELECTION_NORMAL) {
int width = max(1, wcwidth(cell->wc)); if (ctx->last_row->linebreak ||
if (width > 1) {
/* Heuristict to handle force-wrapped multi-column
* characters */
/*
* TODO: maybe we should print a placeholder value to
* the empty cells at the end of the line when
* force-wrapping? Then extract() could simply skip
* those cells
*/
ctx->empty_count -= min(width, ctx->empty_count);
}
else if (ctx->last_row->linebreak ||
ctx->empty_count > 0 || ctx->empty_count > 0 ||
cell->wc == 0) cell->wc == 0)
{ {
@ -321,8 +306,9 @@ extract_one(struct terminal *term, struct row *row, struct cell *cell,
assert(ctx->idx + 1 <= ctx->size); assert(ctx->idx + 1 <= ctx->size);
if (cell->wc >= COMB_CHARS_LO && cell->wc < (COMB_CHARS_LO + term->composed_count)) { if (cell->wc >= CELL_COMB_CHARS_LO &&
const struct composed *composed = &term->composed[cell->wc - COMB_CHARS_LO]; cell->wc < (CELL_COMB_CHARS_LO + term->composed_count)) {
const struct composed *composed = &term->composed[cell->wc - CELL_COMB_CHARS_LO];
ctx->buf[ctx->idx++] = composed->base; ctx->buf[ctx->idx++] = composed->base;

View file

@ -2387,33 +2387,39 @@ print_insert(struct terminal *term, int width)
row->cells[i].attrs.clean = 0; row->cells[i].attrs.clean = 0;
} }
static void
print_spacer(struct terminal *term, int col)
{
struct row *row = term->grid->cur_row;
struct cell *cell = &row->cells[col];
cell->wc = CELL_MULT_COL_SPACER;
cell->attrs = term->vt.attrs;
cell->attrs.clean = 0;
}
void void
term_print(struct terminal *term, wchar_t wc, int width) term_print(struct terminal *term, wchar_t wc, int width)
{ {
if (unlikely(width <= 0)) if (unlikely(width <= 0))
return; return;
if (unlikely(width > 1) && print_linewrap(term);
print_insert(term, width);
if (unlikely(width > 1) && likely(term->auto_margin) &&
term->grid->cursor.point.col + width > term->cols) term->grid->cursor.point.col + width > term->cols)
{ {
/* Multi-column character that doesn't fit on current line - /* Multi-column character that doesn't fit on current line -
* force a line wrap */ * pad with spacers */
for (size_t i = term->grid->cursor.point.col; i < term->cols; i++)
print_spacer(term, i);
/* And force a line-wrap */
term->grid->cursor.lcf = 1; term->grid->cursor.lcf = 1;
print_linewrap(term);
/*
* TODO: should we insert place holder values in the remaining
* cells? This would allow e.g. text extraction to simply
* skip these, instead of trying to recognize a sequence of
* empty cells at the end of the line followed by a
* multi-column character...
*
* Might also make text reflow easier, or even more correct.
*/
} }
print_linewrap(term);
print_insert(term, width);
sixel_overwrite_at_cursor(term, width); sixel_overwrite_at_cursor(term, width);
/* *Must* get current cell *after* linewrap+insert */ /* *Must* get current cell *after* linewrap+insert */
@ -2429,10 +2435,7 @@ term_print(struct terminal *term, wchar_t wc, int width)
/* 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->grid->cursor.point.col < term->cols - 1; i++) { for (int i = 1; i < width && term->grid->cursor.point.col < term->cols - 1; i++) {
term->grid->cursor.point.col++; term->grid->cursor.point.col++;
print_spacer(term, term->grid->cursor.point.col);
struct cell *cell = &row->cells[term->grid->cursor.point.col];
cell->wc = 0;
cell->attrs.clean = 0;
} }
/* Advance cursor */ /* Advance cursor */

View file

@ -48,6 +48,10 @@ struct attributes {
}; };
static_assert(sizeof(struct attributes) == 8, "bad size"); static_assert(sizeof(struct attributes) == 8, "bad size");
#define CELL_COMB_CHARS_LO 0x40000000ul
#define CELL_COMB_CHARS_HI 0x400ffffful
#define CELL_MULT_COL_SPACER 0x40100000ul
struct cell { struct cell {
wchar_t wc; wchar_t wc;
struct attributes attrs; struct attributes attrs;
@ -216,8 +220,6 @@ struct terminal {
struct grid alt; struct grid alt;
struct grid *grid; struct grid *grid;
#define COMB_CHARS_LO 0x40000000ul
#define COMB_CHARS_HI 0x400ffffful
size_t composed_count; size_t composed_count;
struct composed *composed; struct composed *composed;

12
vt.c
View file

@ -550,9 +550,9 @@ action_utf8_print(struct terminal *term, wchar_t wc)
} }
const struct composed *composed = const struct composed *composed =
(base >= COMB_CHARS_LO && (base >= CELL_COMB_CHARS_LO &&
base < (COMB_CHARS_LO + term->composed_count)) base < (CELL_COMB_CHARS_LO + term->composed_count))
? &term->composed[base - COMB_CHARS_LO] ? &term->composed[base - CELL_COMB_CHARS_LO]
: NULL; : NULL;
if (composed != NULL) if (composed != NULL)
@ -635,7 +635,7 @@ action_utf8_print(struct terminal *term, wchar_t wc)
if (cc->combining[wanted_count - 1] != wc) if (cc->combining[wanted_count - 1] != wc)
continue; continue;
term_print(term, COMB_CHARS_LO + i, base_width); term_print(term, CELL_COMB_CHARS_LO + i, base_width);
return; return;
} }
@ -648,12 +648,12 @@ action_utf8_print(struct terminal *term, wchar_t wc)
new_cc.combining[i] = composed->combining[i]; new_cc.combining[i] = composed->combining[i];
new_cc.combining[wanted_count - 1] = wc; new_cc.combining[wanted_count - 1] = wc;
if (term->composed_count < COMB_CHARS_HI) { if (term->composed_count < CELL_COMB_CHARS_HI) {
term->composed_count++; term->composed_count++;
term->composed = realloc(term->composed, term->composed_count * sizeof(term->composed[0])); term->composed = realloc(term->composed, term->composed_count * sizeof(term->composed[0]));
term->composed[term->composed_count - 1] = new_cc; term->composed[term->composed_count - 1] = new_cc;
term_print(term, COMB_CHARS_LO + term->composed_count - 1, base_width); term_print(term, CELL_COMB_CHARS_LO + term->composed_count - 1, base_width);
return; return;
} else { } else {
/* We reached our maximum number of allowed composed /* We reached our maximum number of allowed composed