Merge branch 'text-reflow'

This commit is contained in:
Daniel Eklöf 2020-02-11 19:39:23 +01:00
commit 335bf2e5b4
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 173 additions and 51 deletions

View file

@ -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

View file

@ -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

View file

@ -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
View file

@ -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;

View file

@ -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 */

View file

@ -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)
{

View file

@ -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
View file

@ -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':