mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-07 04:06:07 -05:00
Merge branch 'text-reflow'
This commit is contained in:
commit
335bf2e5b4
8 changed files with 173 additions and 51 deletions
|
|
@ -52,8 +52,6 @@ This is a list of known, but probably not all, issues:
|
|||
|
||||
Examples: á (`LATIN SMALL LETTER A` + `COMBINING ACUTE ACCENT`)
|
||||
|
||||
* Reflow text on window resize
|
||||
|
||||
* GNOME; might work, but without window decorations.
|
||||
|
||||
Strictly speaking, foot is at fault here; all Wayland applications
|
||||
|
|
@ -108,13 +106,13 @@ is **not** possible to define new key bindings.
|
|||
<kbd>ctrl</kbd>+<kbd>shift</kbd>+<kbd>r</kbd>
|
||||
: Start a scrollback search
|
||||
|
||||
<kbd>ctrl</kbd>+<kbd>+</kbd>
|
||||
<kbd>ctrl</kbd>+<kbd>+</kbd>, <kbd>ctrl</kbd>+<kbd>=</kbd>
|
||||
: Increase font size by 1pt
|
||||
|
||||
<kbd>ctrl</kbd>+<kbd>-</kbd>
|
||||
: Decrease font size by 1pt
|
||||
|
||||
<kbd>ctrl</kbd>+<kbd>0</kbd>, <kbd>ctrl</kbd>+<kbd>=</kbd>
|
||||
<kbd>ctrl</kbd>+<kbd>0</kbd>
|
||||
: Reset font size
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -112,13 +112,13 @@ be changed.
|
|||
*ctrl*+*shift*+*r*
|
||||
Start a scrollback search
|
||||
|
||||
*ctrl*+*+*
|
||||
*ctrl*+*+*, *ctrl*+*=*
|
||||
Increase font size by 1pt
|
||||
|
||||
*ctrl*+*-*
|
||||
Decrease font size by 1pt
|
||||
|
||||
*ctrl*+*0*, *ctrl*+*=*
|
||||
*ctrl*+*0*
|
||||
Reset font size
|
||||
|
||||
## SCROLLBACK SEARCH
|
||||
|
|
|
|||
4
input.c
4
input.c
|
|
@ -386,7 +386,7 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
}
|
||||
|
||||
else if (effective_mods == ctrl) {
|
||||
if (sym == XKB_KEY_plus || sym == XKB_KEY_KP_Add) {
|
||||
if (sym == XKB_KEY_equal || sym == XKB_KEY_plus || sym == XKB_KEY_KP_Add) {
|
||||
term_font_size_increase(term);
|
||||
goto maybe_repeat;
|
||||
}
|
||||
|
|
@ -396,7 +396,7 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
goto maybe_repeat;
|
||||
}
|
||||
|
||||
else if (sym == XKB_KEY_0 || sym == XKB_KEY_equal || sym == XKB_KEY_KP_Equal || sym == XKB_KEY_KP_0) {
|
||||
else if (sym == XKB_KEY_0 || sym == XKB_KEY_KP_Equal || sym == XKB_KEY_KP_0) {
|
||||
term_font_size_reset(term);
|
||||
goto maybe_repeat;
|
||||
}
|
||||
|
|
|
|||
187
render.c
187
render.c
|
|
@ -970,28 +970,109 @@ render_search_box(struct terminal *term)
|
|||
wl_surface_commit(term->window->search_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
reflow(struct row **new_grid, int new_cols, int new_rows,
|
||||
struct row *const *old_grid, int old_cols, int old_rows)
|
||||
static int
|
||||
reflow(struct terminal *term, struct row **new_grid, int new_cols, int new_rows,
|
||||
struct row *const *old_grid, int old_cols, int old_rows, int offset)
|
||||
{
|
||||
/* TODO: actually reflow */
|
||||
for (int r = 0; r < min(new_rows, old_rows); r++) {
|
||||
size_t copy_cols = min(new_cols, old_cols);
|
||||
size_t clear_cols = new_cols - copy_cols;
|
||||
int new_col_idx = 0;
|
||||
int new_row_idx = 0;
|
||||
|
||||
if (old_grid[r] == NULL)
|
||||
struct row *new_row = new_grid[new_row_idx];
|
||||
|
||||
assert(new_row == NULL);
|
||||
new_row = grid_row_alloc(new_cols, true);
|
||||
new_row->dirty = true;
|
||||
new_grid[new_row_idx] = new_row;
|
||||
|
||||
/* Start at the beginning of the old grid's scrollback. That is,
|
||||
* at the output that is *oldest* */
|
||||
offset += term->rows;
|
||||
|
||||
/*
|
||||
* Walk the old grid
|
||||
*/
|
||||
for (int r = 0; r < old_rows; r++) {
|
||||
|
||||
/* Unallocated (empty) rows we can simply skip */
|
||||
const struct row *old_row = old_grid[(offset + r) & (old_rows - 1)];
|
||||
if (old_row == NULL)
|
||||
continue;
|
||||
|
||||
if (new_grid[r] == NULL)
|
||||
new_grid[r] = grid_row_alloc(new_cols, false);
|
||||
/*
|
||||
* 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,
|
||||
* add those to the new line. However, if there are non-empty
|
||||
* cells *after* the string of empty cells, we need to emit
|
||||
* the empty cells too. And that may trigger linebreaks
|
||||
*/
|
||||
int empty_count = 0;
|
||||
|
||||
struct cell *new_cells = new_grid[r]->cells;
|
||||
const struct cell *old_cells = old_grid[r]->cells;
|
||||
/* Walk current line of the old grid */
|
||||
for (int c = 0; c < old_cols; c++) {
|
||||
const struct cell *old_cell = &old_row->cells[c];
|
||||
|
||||
new_grid[r]->dirty = old_grid[r]->dirty;
|
||||
memcpy(new_cells, old_cells, copy_cols * sizeof(new_cells[0]));
|
||||
memset(&new_cells[copy_cols], 0, clear_cols * sizeof(new_cells[0]));
|
||||
if (old_cell->wc == 0) {
|
||||
empty_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(old_cell->wc != 0);
|
||||
|
||||
/* Non-empty cell. Emit preceeding string of empty cells,
|
||||
* and possibly line break for current cell */
|
||||
|
||||
for (int i = 0; i < empty_count + 1; i++) {
|
||||
if (new_col_idx >= new_cols) {
|
||||
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_row->dirty = true;
|
||||
new_grid[new_row_idx] = new_row;
|
||||
} else
|
||||
memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0]));
|
||||
}
|
||||
|
||||
new_col_idx++;
|
||||
}
|
||||
|
||||
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 last cell of the old grid's line if empty, then we
|
||||
* insert a linebreak in the new grid's line too. Unless, the
|
||||
* *entire* old line was empty.
|
||||
*/
|
||||
|
||||
if (empty_count < old_cols &&
|
||||
(old_row->cells[old_cols - 1].wc == 0 ||
|
||||
old_row->cells[old_cols - 1].attrs.linefeed))
|
||||
{
|
||||
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_row->dirty = true;
|
||||
new_grid[new_row_idx] = new_row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new_row_idx;
|
||||
}
|
||||
|
||||
/* Move to terminal.c? */
|
||||
|
|
@ -1045,31 +1126,52 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
|||
term->x_margin = (term->width - new_cols * term->cell_width) / 2;
|
||||
term->y_margin = (term->height - new_rows * term->cell_height) / 2;
|
||||
|
||||
term->normal.offset %= new_normal_grid_rows;
|
||||
term->normal.view %= new_normal_grid_rows;
|
||||
|
||||
term->alt.offset %= new_alt_grid_rows;
|
||||
term->alt.view %= new_alt_grid_rows;
|
||||
|
||||
/* Allocate new 'normal' grid */
|
||||
/* Allocate new 'normal' and 'alt' grids */
|
||||
struct row **normal = calloc(new_normal_grid_rows, sizeof(normal[0]));
|
||||
for (int r = 0; r < new_rows; r++) {
|
||||
size_t real_r = (term->normal.view + r) & (new_normal_grid_rows - 1);
|
||||
normal[real_r] = grid_row_alloc(new_cols, true);
|
||||
}
|
||||
|
||||
/* Allocate new 'alt' grid */
|
||||
struct row **alt = calloc(new_alt_grid_rows, sizeof(alt[0]));
|
||||
for (int r = 0; r < new_rows; r++) {
|
||||
int real_r = (term->alt.view + r) & (new_alt_grid_rows - 1);
|
||||
alt[real_r] = grid_row_alloc(new_cols, true);
|
||||
}
|
||||
|
||||
/* Reflow content */
|
||||
reflow(normal, new_cols, new_normal_grid_rows,
|
||||
term->normal.rows, old_cols, old_normal_grid_rows);
|
||||
reflow(alt, new_cols, new_alt_grid_rows,
|
||||
term->alt.rows, old_cols, old_alt_grid_rows);
|
||||
int last_normal_row = reflow(
|
||||
term, normal, new_cols, new_normal_grid_rows,
|
||||
term->normal.rows, old_cols, old_normal_grid_rows, term->normal.offset);
|
||||
int last_alt_row = reflow(
|
||||
term, alt, new_cols, new_alt_grid_rows,
|
||||
term->alt.rows, old_cols, old_alt_grid_rows, term->alt.offset);
|
||||
|
||||
/* Re-set current row pointers */
|
||||
term->normal.cur_row = normal[last_normal_row];
|
||||
term->alt.cur_row = alt[last_alt_row];
|
||||
|
||||
/* Reset offset such that the last copied row ends up at the
|
||||
* bottom of the screen */
|
||||
term->normal.offset = last_normal_row - new_rows;
|
||||
term->alt.offset = last_alt_row - new_rows;
|
||||
|
||||
/* Can't have negative offsets, so wrap 'em */
|
||||
while (term->normal.offset < 0)
|
||||
term->normal.offset += new_normal_grid_rows;
|
||||
while (term->alt.offset < 0)
|
||||
term->alt.offset += new_alt_grid_rows;
|
||||
|
||||
/* Make sure offset doesn't point to empty line */
|
||||
while (normal[term->normal.offset] == NULL)
|
||||
term->normal.offset = (term->normal.offset + 1) & (new_normal_grid_rows - 1);
|
||||
while (alt[term->alt.offset] == NULL)
|
||||
term->alt.offset = (term->alt.offset + 1) & (new_alt_grid_rows - 1);
|
||||
|
||||
term->normal.view = term->normal.offset;
|
||||
term->alt.view = term->alt.offset;
|
||||
|
||||
/* Make sure all visible lines have been allocated */
|
||||
for (int r = 0; r < new_rows; r++) {
|
||||
int idx = (term->normal.offset + r) & (new_normal_grid_rows - 1);
|
||||
if (normal[idx] == NULL)
|
||||
normal[idx] = grid_row_alloc(new_cols, true);
|
||||
|
||||
idx = (term->alt.offset + r) & (new_alt_grid_rows - 1);
|
||||
if (alt[idx] == NULL)
|
||||
alt[idx] = grid_row_alloc(new_cols, true);
|
||||
}
|
||||
|
||||
/* Free old 'normal' grid */
|
||||
for (int r = 0; r < term->normal.num_rows; r++)
|
||||
|
|
@ -1117,9 +1219,20 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
|||
if (term->scroll_region.end >= old_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;
|
||||
cursor_row--;
|
||||
|
||||
assert(cursor_row < term->rows);
|
||||
term_cursor_to(
|
||||
term,
|
||||
min(term->cursor.point.row, term->rows - 1),
|
||||
max(cursor_row, 0),
|
||||
min(term->cursor.point.col, term->cols - 1));
|
||||
|
||||
term->render.last_cursor.cell = NULL;
|
||||
|
|
|
|||
|
|
@ -212,7 +212,8 @@ extract_one(struct terminal *term, struct row *row, struct cell *cell,
|
|||
struct extract *ctx = data;
|
||||
|
||||
if (ctx->last_row != NULL && row != ctx->last_row &&
|
||||
((term->selection.kind == SELECTION_NORMAL && ctx->last_cell->wc == 0) ||
|
||||
((term->selection.kind == SELECTION_NORMAL &&
|
||||
(ctx->last_cell->wc == 0 || ctx->last_cell->attrs.linefeed)) ||
|
||||
term->selection.kind == SELECTION_BLOCK))
|
||||
{
|
||||
/* Last cell was the last column in the selection */
|
||||
|
|
|
|||
12
terminal.c
12
terminal.c
|
|
@ -1154,13 +1154,13 @@ term_font_size_adjust(struct terminal *term, double amount)
|
|||
void
|
||||
term_font_size_increase(struct terminal *term)
|
||||
{
|
||||
term_font_size_adjust(term, 1.);
|
||||
term_font_size_adjust(term, 0.5);
|
||||
}
|
||||
|
||||
void
|
||||
term_font_size_decrease(struct terminal *term)
|
||||
{
|
||||
term_font_size_adjust(term, -1.);
|
||||
term_font_size_adjust(term, -0.5);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1495,6 +1495,14 @@ term_scroll_reverse(struct terminal *term, int rows)
|
|||
term_scroll_reverse_partial(term, term->scroll_region, rows);
|
||||
}
|
||||
|
||||
void
|
||||
term_formfeed(struct terminal *term)
|
||||
{
|
||||
if (term->cursor.point.col > 0)
|
||||
term->grid->cur_row->cells[term->cursor.point.col - 1].attrs.linefeed = 1;
|
||||
term_cursor_left(term, term->cursor.point.col);
|
||||
}
|
||||
|
||||
void
|
||||
term_linefeed(struct terminal *term)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ struct attributes {
|
|||
uint32_t have_fg:1;
|
||||
uint32_t have_bg:1;
|
||||
uint32_t selected:2;
|
||||
uint32_t reserved:3;
|
||||
uint32_t linefeed:1;
|
||||
uint32_t reserved:2;
|
||||
uint32_t bg:24;
|
||||
};
|
||||
static_assert(sizeof(struct attributes) == 8, "bad size");
|
||||
|
|
@ -403,6 +404,7 @@ void term_scroll_partial(
|
|||
void term_scroll_reverse_partial(
|
||||
struct terminal *term, struct scroll_region region, int rows);
|
||||
|
||||
void term_formfeed(struct terminal *term);
|
||||
void term_linefeed(struct terminal *term);
|
||||
void term_reverse_index(struct terminal *term);
|
||||
|
||||
|
|
|
|||
4
vt.c
4
vt.c
|
|
@ -128,7 +128,7 @@ action_execute(struct terminal *term, uint8_t c)
|
|||
|
||||
case '\r':
|
||||
/* FF - form feed */
|
||||
term_cursor_left(term, term->cursor.point.col);
|
||||
term_formfeed(term);
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
|
|
@ -361,8 +361,8 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
|||
break;
|
||||
|
||||
case 'E':
|
||||
term_formfeed(term);
|
||||
term_linefeed(term);
|
||||
term_cursor_left(term, term->cursor.point.col);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue