mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-11 05:33:55 -04:00
Merge branch 'multi-column-special-spacer-value'
This commit is contained in:
commit
6b0b3ddccc
6 changed files with 69 additions and 55 deletions
27
grid.c
27
grid.c
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
8
render.c
8
render.c
|
|
@ -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);
|
||||||
|
|
|
||||||
30
selection.c
30
selection.c
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
41
terminal.c
41
terminal.c
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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
12
vt.c
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue