diff options
-rw-r--r-- | src/nvim/api/ui.c | 2 | ||||
-rw-r--r-- | src/nvim/api/ui_events.in.h | 2 | ||||
-rw-r--r-- | src/nvim/popupmnu.c | 2 | ||||
-rw-r--r-- | src/nvim/screen.c | 47 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 5 | ||||
-rw-r--r-- | src/nvim/ui.c | 12 | ||||
-rw-r--r-- | src/nvim/ui.h | 7 | ||||
-rw-r--r-- | src/nvim/ui_bridge.c | 6 | ||||
-rw-r--r-- | src/nvim/ui_compositor.c | 84 |
9 files changed, 99 insertions, 68 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 9d577db022..b77516d588 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -461,7 +461,7 @@ static void remote_ui_put(UI *ui, const char *cell) static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol, Integer clearcol, Integer clearattr, - Boolean wrap, const schar_T *chunk, + LineFlags flags, const schar_T *chunk, const sattr_T *attrs) { UIData *data = ui->data; diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 70f8b9d85c..ef3ff0f4c2 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -92,7 +92,7 @@ void grid_destroy(Integer grid) // translate this in to the public grid_line format. void raw_line(Integer grid, Integer row, Integer startcol, Integer endcol, Integer clearcol, Integer clearattr, - Boolean wrap, const schar_T *chunk, const sattr_T *attrs) + LineFlags flags, const schar_T *chunk, const sattr_T *attrs) FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL; void event(char *name, Array args, bool *args_consumed) diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index 78b64621e9..d64406846a 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -363,7 +363,7 @@ void pum_redraw(void) if (!pum_grid.chars || pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) { - grid_alloc(&pum_grid, pum_height, grid_width, !moved); + grid_alloc(&pum_grid, pum_height, grid_width, !moved, false); ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows); } else if (moved) { grid_invalidate(&pum_grid); diff --git a/src/nvim/screen.c b/src/nvim/screen.c index b50333e7fa..7252289e0e 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -5316,7 +5316,7 @@ void grid_puts(ScreenGrid *grid, char_u *text, int row, int col, int attr) } static int put_dirty_row = -1; -static int put_dirty_first = -1; +static int put_dirty_first = INT_MAX; static int put_dirty_last = 0; /// Start a group of screen_puts_len calls that builds a single screen line. @@ -5347,8 +5347,6 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int prev_c = 0; /* previous Arabic character */ int pc, nc, nc1; int pcc[MAX_MCO]; - int force_redraw_this; - int force_redraw_next = FALSE; int need_redraw; bool do_flush = false; @@ -5371,16 +5369,10 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, /* When drawing over the right halve of a double-wide char clear out the * left halve. Only needed in a terminal. */ - if (col > 0 && col < grid->Columns && grid_fix_col(grid, col, row) != col) { - schar_from_ascii(grid->chars[off - 1], ' '); - grid->attrs[off - 1] = 0; + if (grid != &default_grid && col == 0 && grid_invalid_row(grid, row)) { // redraw the previous cell, make it empty - if (put_dirty_first == -1) { - put_dirty_first = col-1; - } - put_dirty_last = col+1; - // force the cell at "col" to be redrawn - force_redraw_next = true; + put_dirty_first = -1; + put_dirty_last = MAX(put_dirty_last, 1); } max_off = grid->line_offset[row] + grid->Columns; @@ -5428,15 +5420,12 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, schar_from_cc(buf, u8c, u8cc); - force_redraw_this = force_redraw_next; - force_redraw_next = FALSE; - need_redraw = schar_cmp(grid->chars[off], buf) || (mbyte_cells == 2 && grid->chars[off + 1][0] != 0) || grid->attrs[off] != attr || exmode_active; - if (need_redraw || force_redraw_this) { + if (need_redraw) { // When at the end of the text and overwriting a two-cell // character with a one-cell character, need to clear the next // cell. Also when overwriting the left halve of a two-cell char @@ -5460,9 +5449,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, grid->chars[off + 1][0] = 0; grid->attrs[off + 1] = attr; } - if (put_dirty_first == -1 || col < put_dirty_first) { - put_dirty_first = col; - } + put_dirty_first = MIN(put_dirty_first, col); put_dirty_last = MAX(put_dirty_last, col+mbyte_cells); } @@ -5491,14 +5478,14 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, void grid_puts_line_flush(ScreenGrid *grid, bool set_cursor) { assert(put_dirty_row != -1); - if (put_dirty_first != -1) { + if (put_dirty_first < put_dirty_last) { if (set_cursor) { ui_grid_cursor_goto(grid->handle, put_dirty_row, MIN(put_dirty_last, grid->Columns-1)); } ui_line(grid, put_dirty_row, put_dirty_first, put_dirty_last, put_dirty_last, 0, false); - put_dirty_first = -1; + put_dirty_first = INT_MAX; put_dirty_last = 0; } put_dirty_row = -1; @@ -5870,9 +5857,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, if (dirty_last > dirty_first) { // TODO(bfredl): support a cleared suffix even with a batched line? if (put_dirty_row == row) { - if (put_dirty_first == -1 || dirty_first < put_dirty_first) { - put_dirty_first = dirty_first; - } + put_dirty_first = MIN(put_dirty_first, dirty_first); put_dirty_last = MAX(put_dirty_last, dirty_last); } else { int last = c2 != ' ' ? dirty_last : dirty_first + (c1 != ' '); @@ -5958,7 +5943,7 @@ void win_grid_alloc(win_T *wp) || grid->Rows != rows || grid->Columns != cols) { if (want_allocation) { - grid_alloc(grid, rows, cols, true); + grid_alloc(grid, rows, cols, true, true); } else { // Single grid mode, all rendering will be redirected to default_grid. // Only keep track of the size and offset of the window. @@ -6054,7 +6039,7 @@ retry: // Continuing with the old arrays may result in a crash, because the // size is wrong. - grid_alloc(&default_grid, Rows, Columns, !doclear); + grid_alloc(&default_grid, Rows, Columns, !doclear, true); StlClickDefinition *new_tab_page_click_defs = xcalloc( (size_t)Columns, sizeof(*new_tab_page_click_defs)); @@ -6088,7 +6073,7 @@ retry: } } -void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy) +void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid) { int new_row; ScreenGrid new = *grid; @@ -6106,7 +6091,7 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy) new.line_offset[new_row] = new_row * new.Columns; new.line_wraps[new_row] = false; - grid_clear_line(&new, new.line_offset[new_row], columns, true); + grid_clear_line(&new, new.line_offset[new_row], columns, valid); if (copy) { // If the screen is not going to be cleared, copy as much as @@ -6234,6 +6219,12 @@ void grid_invalidate(ScreenGrid *grid) (void)memset(grid->attrs, -1, grid->Rows * grid->Columns * sizeof(sattr_T)); } +bool grid_invalid_row(ScreenGrid *grid, int row) +{ + return grid->attrs[grid->line_offset[row]] < 0; +} + + /// Copy part of a grid line for vertically split window. static void linecopy(ScreenGrid *grid, int to, int from, int col, int width) diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 2e26a75be1..a1a43c3e3a 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1273,7 +1273,7 @@ static void tui_option_set(UI *ui, String name, Object value) static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, Integer endcol, Integer clearcol, Integer clearattr, - Boolean wrap, const schar_T *chunk, + LineFlags flags, const schar_T *chunk, const sattr_T *attrs) { TUIData *data = ui->data; @@ -1295,7 +1295,8 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, (int)clearattr); } - if (wrap && ui->width == grid->width && linerow + 1 < grid->height) { + if (flags & kLineFlagWrap && ui->width == grid->width + && linerow + 1 < grid->height) { // Only do line wrapping if the grid width is equal to the terminal // width and the line continuation is within the grid. diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 3dc6ccaf52..dd4eb0f196 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -315,11 +315,17 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active) void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, int clearattr, bool wrap) { + LineFlags flags = wrap ? kLineFlagWrap : 0; + if (startcol == -1) { + startcol = 0; + flags |= kLineFlagInvalid; + } + size_t off = grid->line_offset[row] + (size_t)startcol; - ui_call_raw_line(grid->handle, row, startcol, endcol, - clearcol, clearattr, wrap, (const schar_T *)grid->chars + off, - (const sattr_T *)grid->attrs + off); + ui_call_raw_line(grid->handle, row, startcol, endcol, clearcol, clearattr, + flags, (const schar_T *)grid->chars + off, + (const sattr_T *)grid->attrs + off); if (p_wd) { // 'writedelay': flush & delay each time. int old_row = cursor_row, old_col = cursor_col; diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 8aeb632f6d..a5a0fa8b75 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -34,6 +34,13 @@ EXTERN const char *ui_ext_names[] INIT(= { typedef struct ui_t UI; +enum { + kLineFlagWrap = 1, + kLineFlagInvalid = 2, +}; + +typedef int LineFlags; + struct ui_t { bool rgb; bool composed; diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index bd5d37be73..91cd458702 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -153,14 +153,14 @@ static void ui_bridge_raw_line_event(void **argv) UI *ui = UI(argv[0]); ui->raw_line(ui, PTR2INT(argv[1]), PTR2INT(argv[2]), PTR2INT(argv[3]), PTR2INT(argv[4]), PTR2INT(argv[5]), PTR2INT(argv[6]), - PTR2INT(argv[7]), argv[8], argv[9]); + (LineFlags)PTR2INT(argv[7]), argv[8], argv[9]); xfree(argv[8]); xfree(argv[9]); } static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol, Integer clearcol, Integer clearattr, - Boolean wrap, const schar_T *chunk, + LineFlags flags, const schar_T *chunk, const sattr_T *attrs) { size_t ncol = (size_t)(endcol-startcol); @@ -168,7 +168,7 @@ static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row, sattr_T *hl = xmemdup(attrs, ncol * sizeof(sattr_T)); UI_BRIDGE_CALL(ui, raw_line, 10, ui, INT2PTR(grid), INT2PTR(row), INT2PTR(startcol), INT2PTR(endcol), INT2PTR(clearcol), - INT2PTR(clearattr), INT2PTR(wrap), c, hl); + INT2PTR(clearattr), INT2PTR(flags), c, hl); } static void ui_bridge_suspend(UI *b) diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index 2ca0d1a6eb..9e0c44f3c2 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -217,8 +217,16 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle, /// do something more efficient (where efficiency means smaller deltas to /// the downstream UI.) static void compose_line(Integer row, Integer startcol, Integer endcol, - bool wrap) + LineFlags flags) { + // in case we start on the right half of a double-width char, we need to + // check the left half. But skip it in output if it wasn't doublewidth. + int skip = 0; + if (startcol > 0 && (flags & kLineFlagInvalid)) { + startcol--; + skip = 1; + } + int col = (int)startcol; ScreenGrid *grid = NULL; @@ -247,15 +255,37 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, + (size_t)(col-grid->comp_col); memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf)); memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf)); + + // Tricky: if overlap caused a doublewidth char to get cut-off, must + // replace the visible half with a space. + if (linebuf[col-startcol][0] == NUL) { + linebuf[col-startcol][0] = ' '; + linebuf[col-startcol][1] = NUL; + } else if (n > 1 && linebuf[col-startcol+1][0] == NUL) { + skip = 0; + } + if (grid->comp_col+grid->Columns > until + && grid->chars[off+n][0] == NUL) { + linebuf[until-1-startcol][0] = ' '; + linebuf[until-1-startcol][1] = '\0'; + if (col == startcol && n == 1) { + skip = 0; + } + } col = until; } assert(endcol <= chk_width); assert(row < chk_height); - // TODO(bfredl): too conservative, need check - // grid->line_wraps if grid->Width == Width - wrap = wrap && grid && grid->handle == 1; - ui_composed_call_raw_line(1, row, startcol, endcol, endcol, 0, wrap, - (const schar_T *)linebuf, (const sattr_T *)attrbuf); + + if (!(grid && grid == &default_grid)) { + // TODO(bfredl): too conservative, need check + // grid->line_wraps if grid->Width == Width + flags = flags & ~kLineFlagWrap; + } + + ui_composed_call_raw_line(1, row, startcol+skip, endcol, endcol, 0, flags, + (const schar_T *)linebuf+skip, + (const sattr_T *)attrbuf+skip); } static void compose_area(Integer startrow, Integer endrow, @@ -264,39 +294,35 @@ static void compose_area(Integer startrow, Integer endrow, endrow = MIN(endrow, default_grid.Rows); endcol = MIN(endcol, default_grid.Columns); for (int r = (int)startrow; r < endrow; r++) { - compose_line(r, startcol, endcol, false); + compose_line(r, startcol, endcol, kLineFlagInvalid); } } -static void draw_line(ScreenGrid *grid, Integer row, Integer startcol, - Integer endcol, Integer clearcol, Integer clearattr, - bool wrap, const schar_T *chunk, const sattr_T *attrs) -{ - row += grid->comp_row; - startcol += grid->comp_col; - endcol += grid->comp_col; - clearcol += grid->comp_col; - wrap = wrap && grid->handle == 1; - assert(clearcol <= default_grid.Columns); - if (kv_size(layers) > grid->comp_index+1) { - compose_line(row, startcol, clearcol, wrap); - } else { - ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr, - wrap, chunk, attrs); - } -} - static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol, - Integer clearcol, Integer clearattr, bool wrap, - const schar_T *chunk, const sattr_T *attrs) + Integer clearcol, Integer clearattr, + LineFlags flags, const schar_T *chunk, + const sattr_T *attrs) { if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) { return; } - draw_line(curgrid, row, startcol, endcol, clearcol, clearattr, wrap, chunk, - attrs); + + row += curgrid->comp_row; + startcol += curgrid->comp_col; + endcol += curgrid->comp_col; + clearcol += curgrid->comp_col; + if (curgrid != &default_grid) { + flags = flags & ~kLineFlagWrap; + } + assert(clearcol <= default_grid.Columns); + if (flags & kLineFlagInvalid || kv_size(layers) > curgrid->comp_index+1) { + compose_line(row, startcol, clearcol, flags); + } else { + ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr, + flags, chunk, attrs); + } } /// The screen is invalid and will soon be cleared |