diff --git a/grid.c b/grid.c index 744dd175..a9d155e0 100644 --- a/grid.c +++ b/grid.c @@ -28,6 +28,7 @@ grid_row_alloc(int cols, bool initialize) { struct row *row = malloc(sizeof(*row)); row->dirty = false; + row->linebreak = false; if (initialize) { row->cells = calloc(cols, sizeof(row->cells[0])); diff --git a/render.c b/render.c index 2c48629b..b78e6454 100644 --- a/render.c +++ b/render.c @@ -16,8 +16,10 @@ #define LOG_MODULE "render" #define LOG_ENABLE_DBG 0 #include "log.h" -#include "shm.h" +#include "config.h" #include "grid.h" +#include "selection.h" +#include "shm.h" #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -981,7 +983,6 @@ reflow(struct terminal *term, struct row **new_grid, int new_cols, int new_rows, 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, @@ -1009,20 +1010,33 @@ reflow(struct terminal *term, struct row **new_grid, int new_cols, int new_rows, /* Walk current line of the old grid */ for (int c = 0; c < old_cols; c++) { - const struct cell *old_cell = &old_row->cells[c]; - - if (old_cell->wc == 0) { + if (old_row->cells[c].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 */ + int old_cols_left = old_cols - c; + int cols_needed = empty_count + old_cols_left; + int new_cols_left = new_cols - new_col_idx; + if (new_cols_left < cols_needed && new_cols_left >= old_cols_left) + empty_count = max(0, empty_count - (cols_needed - new_cols_left)); for (int i = 0; i < empty_count + 1; i++) { + const struct cell *old_cell = &old_row->cells[c - empty_count + i]; + + /* Out of columns on current row in new grid? */ if (new_col_idx >= new_cols) { + /* + * If last cell on last row and first cell on new + * row are non-empty, wrap the line, otherwise + * insert a hard line break. + */ + if (new_row->cells[new_cols - 1].wc == 0 || + old_cell->wc == 0) + { + new_row->linebreak = true; + } + new_col_idx = 0; new_row_idx = (new_row_idx + 1) & (new_rows - 1); @@ -1030,38 +1044,27 @@ reflow(struct terminal *term, struct row **new_grid, int new_cols, int new_rows, if (new_row == NULL) { new_row = grid_row_alloc(new_cols, true); new_grid[new_row_idx] = new_row; - } else + } else { memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); - - new_row->dirty = true; + new_row->linebreak = false; + } } + assert(new_row != NULL); + assert(new_col_idx >= 0); + assert(new_col_idx < new_cols); + + new_row->cells[new_col_idx] = *old_cell; + new_row->cells[new_col_idx].attrs.clean = 1; 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 is empty, then we - * insert a linebreak in the new grid's line too. Unless, the - * *entire* old line was empty. - */ + if (old_row->linebreak) { + new_row->linebreak = true; - if (empty_count < old_cols && - //r < old_rows - 1 && - (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); @@ -1069,10 +1072,10 @@ reflow(struct terminal *term, struct row **new_grid, int new_cols, int new_rows, if (new_row == NULL) { new_row = grid_row_alloc(new_cols, true); new_grid[new_row_idx] = new_row; - } else + } else { memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); - - new_row->dirty = true; + new_row->linebreak = false; + } } } @@ -1108,6 +1111,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force) if (!force && width == term->width && height == term->height && scale == term->scale) return; + selection_cancel(term); + /* Cancel an application initiated "Synchronized Update" */ term_disable_app_sync_updates(term); @@ -1153,8 +1158,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force) /* 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; + term->normal.offset = last_normal_row - new_rows + 1; + term->alt.offset = last_alt_row - new_rows + 1; /* Can't have negative offsets, so wrap 'em */ while (term->normal.offset < 0) @@ -1168,6 +1173,7 @@ maybe_resize(struct terminal *term, int width, int height, bool force) while (alt[term->alt.offset] == NULL) term->alt.offset = (term->alt.offset + 1) & (new_alt_grid_rows - 1); + /* TODO: try to keep old view */ term->normal.view = term->normal.offset; term->alt.view = term->alt.offset; @@ -1237,21 +1243,14 @@ maybe_resize(struct terminal *term, int width, int height, bool force) while (cursor_row < 0) cursor_row += term->grid->num_rows; - /* Heuristic to prevent a new prompt from being printed a new line */ - bool do_linefeed = false; - if (term->cursor.point.col > 0) - cursor_row--; - else if (cursor_row >= term->rows) - do_linefeed = true; + assert(cursor_row >= 0); + assert(cursor_row < term->rows); term_cursor_to( term, - min(max(cursor_row, 0), term->rows - 1), + cursor_row, min(term->cursor.point.col, term->cols - 1)); - if (do_linefeed) - term_linefeed(term); - term->render.last_cursor.cell = NULL; tll_free(term->normal.scroll_damage); tll_free(term->alt.scroll_damage); diff --git a/selection.c b/selection.c index f1485f45..189119d9 100644 --- a/selection.c +++ b/selection.c @@ -213,7 +213,7 @@ extract_one(struct terminal *term, struct row *row, struct cell *cell, if (ctx->last_row != NULL && row != ctx->last_row && ((term->selection.kind == SELECTION_NORMAL && - (ctx->last_cell->wc == 0 || ctx->last_cell->attrs.linefeed)) || + ctx->last_row->linebreak) || term->selection.kind == SELECTION_BLOCK)) { /* Last cell was the last column in the selection */ diff --git a/terminal.c b/terminal.c index cb52a416..bec0ce7b 100644 --- a/terminal.c +++ b/terminal.c @@ -1090,8 +1090,8 @@ term_reset(struct terminal *term, bool hard) term->normal.offset = term->normal.view = 0; term->alt.offset = term->alt.view = 0; for (size_t i = 0; i < term->rows; i++) { - memset(grid_row_and_alloc(&term->normal, i)->cells, 0, term->cols * sizeof(struct cell)); - memset(grid_row_and_alloc(&term->alt, i)->cells, 0, term->cols * sizeof(struct cell)); + term->normal.rows[i] = grid_row_alloc(term->cols, true); + term->alt.rows[i] = grid_row_alloc(term->cols, true); } for (size_t i = term->rows; i < term->normal.num_rows; i++) { grid_row_free(term->normal.rows[i]); @@ -1253,6 +1253,7 @@ static inline void erase_line(struct terminal *term, struct row *row) { erase_cell_range(term, row, 0, term->cols - 1); + row->linebreak = false; } void @@ -1498,17 +1499,13 @@ term_scroll_reverse(struct terminal *term, int rows) void term_formfeed(struct terminal *term) { - int col = term->cursor.point.col; - if (!term->cursor.lcf) - col--; - if (col >= 0) - term->grid->cur_row->cells[col].attrs.linefeed = 1; term_cursor_left(term, term->cursor.point.col); } void term_linefeed(struct terminal *term) { + term->grid->cur_row->linebreak = true; if (term->cursor.point.row == term->scroll_region.end - 1) term_scroll(term, 1); else diff --git a/terminal.h b/terminal.h index 449a1329..1d19c9d7 100644 --- a/terminal.h +++ b/terminal.h @@ -42,8 +42,7 @@ struct attributes { uint32_t have_fg:1; uint32_t have_bg:1; uint32_t selected:2; - uint32_t linefeed:1; - uint32_t reserved:2; + uint32_t reserved:3; uint32_t bg:24; }; static_assert(sizeof(struct attributes) == 8, "bad size"); @@ -84,6 +83,7 @@ struct damage { struct row { struct cell *cells; bool dirty; + bool linebreak; }; struct grid {