diff options
Diffstat (limited to 'src/nvim/tui/tui.c')
-rw-r--r-- | src/nvim/tui/tui.c | 174 |
1 files changed, 95 insertions, 79 deletions
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 03288a3325..56c47ed6cc 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -88,6 +88,7 @@ typedef struct { bool cont_received; UGrid grid; kvec_t(Rect) invalid_regions; + int row, col; int out_fd; bool scroll_region_is_full_screen; bool can_change_scroll_region; @@ -98,6 +99,8 @@ typedef struct { bool busy, is_invisible; bool cork, overflow; cursorentry_T cursor_shapes[SHAPE_IDX_COUNT]; + HlAttrs clear_attrs; + kvec_t(HlAttrs) attrs; HlAttrs print_attrs; bool default_attr; ModeShape showing_mode; @@ -126,10 +129,9 @@ UI *tui_start(void) { UI *ui = xcalloc(1, sizeof(UI)); // Freed by ui_bridge_stop(). ui->stop = tui_stop; - ui->resize = tui_resize; - ui->clear = tui_clear; - ui->eol_clear = tui_eol_clear; - ui->cursor_goto = tui_cursor_goto; + ui->grid_resize = tui_grid_resize; + ui->grid_clear = tui_grid_clear; + ui->grid_cursor_goto = tui_grid_cursor_goto; ui->mode_info_set = tui_mode_info_set; ui->update_menu = tui_update_menu; ui->busy_start = tui_busy_start; @@ -137,10 +139,8 @@ UI *tui_start(void) ui->mouse_on = tui_mouse_on; ui->mouse_off = tui_mouse_off; ui->mode_change = tui_mode_change; - ui->set_scroll_region = tui_set_scroll_region; - ui->scroll = tui_scroll; - ui->highlight_set = tui_highlight_set; - ui->put = tui_put; + ui->grid_scroll = tui_grid_scroll; + ui->hl_attr_define = tui_hl_attr_define; ui->bell = tui_bell; ui->visual_bell = tui_visual_bell; ui->default_colors_set = tui_default_colors_set; @@ -149,8 +149,10 @@ UI *tui_start(void) ui->set_title = tui_set_title; ui->set_icon = tui_set_icon; ui->option_set= tui_option_set; + ui->raw_line = tui_raw_line; memset(ui->ui_ext, 0, sizeof(ui->ui_ext)); + ui->ui_ext[kUINewgrid] = true; return ui_bridge_attach(ui, tui_main, tui_scheduler); } @@ -290,7 +292,7 @@ static void terminfo_stop(UI *ui) static void tui_terminal_start(UI *ui) { TUIData *data = ui->data; - data->print_attrs = HLATTRS_INIT; + data->print_attrs = HLATTRS_INVALID; ugrid_init(&data->grid); terminfo_start(ui); update_size(ui); @@ -346,6 +348,9 @@ static void tui_main(UIBridgeData *bridge, UI *ui) signal_watcher_start(&data->cont_handle, sigcont_cb, SIGCONT); #endif + // TODO(bfredl): zero hl is empty, send this explicitly? + kv_push(data->attrs, HLATTRS_INIT); + #if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 data->input.tk_ti_hook_fn = tui_tk_ti_getstr; #endif @@ -380,6 +385,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui) signal_watcher_close(&data->winch_handle, NULL); loop_close(&tui_loop, false); kv_destroy(data->invalid_regions); + kv_destroy(data->attrs); xfree(data); } @@ -438,18 +444,17 @@ static void update_attrs(UI *ui, HlAttrs attrs) } data->print_attrs = attrs; - UGrid *grid = &data->grid; int fg = ui->rgb ? attrs.rgb_fg_color : (attrs.cterm_fg_color - 1); if (fg == -1) { - fg = ui->rgb ? grid->clear_attrs.rgb_fg_color - : (grid->clear_attrs.cterm_fg_color - 1); + fg = ui->rgb ? data->clear_attrs.rgb_fg_color + : (data->clear_attrs.cterm_fg_color - 1); } int bg = ui->rgb ? attrs.rgb_bg_color : (attrs.cterm_bg_color - 1); if (bg == -1) { - bg = ui->rgb ? grid->clear_attrs.rgb_bg_color - : (grid->clear_attrs.cterm_bg_color - 1); + bg = ui->rgb ? data->clear_attrs.rgb_bg_color + : (data->clear_attrs.cterm_bg_color - 1); } int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr; @@ -592,6 +597,8 @@ static void cursor_goto(UI *ui, int row, int col) if (row == grid->row && col == grid->col) { return; } + grid->row = row; + grid->col = col; if (0 == row && 0 == col) { unibi_out(ui, unibi_cursor_home); ugrid_goto(grid, row, col); @@ -679,20 +686,20 @@ static void cursor_goto(UI *ui, int row, int col) ugrid_goto(grid, row, col); } -static void clear_region(UI *ui, int top, int bot, int left, int right) +static void clear_region(UI *ui, int top, int bot, int left, int right, + HlAttrs attrs) { TUIData *data = ui->data; UGrid *grid = &data->grid; - int saved_row = grid->row; - int saved_col = grid->col; bool cleared = false; - bool nobg = ui->rgb ? grid->clear_attrs.rgb_bg_color == -1 - : grid->clear_attrs.cterm_bg_color == 0; + // TODO(bfredl): support BCE for non-default background + bool nobg = ui->rgb ? attrs.rgb_bg_color == -1 + : attrs.cterm_bg_color == 0; if (nobg && right == ui->width -1) { // Background is set to the default color and the right edge matches the // screen end, try to use terminal codes for clearing the requested area. - update_attrs(ui, grid->clear_attrs); + update_attrs(ui, attrs); if (left == 0) { if (bot == ui->height - 1) { if (top == 0) { @@ -725,7 +732,7 @@ static void clear_region(UI *ui, int top, int bot, int left, int right) } // restore cursor - cursor_goto(ui, saved_row, saved_col); + cursor_goto(ui, data->row, data->col); } static bool can_use_scroll(UI * ui) @@ -792,7 +799,7 @@ static void reset_scroll_region(UI *ui) unibi_goto(ui, grid->row, grid->col); } -static void tui_resize(UI *ui, Integer width, Integer height) +static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height) { TUIData *data = ui->data; ugrid_resize(&data->grid, (int)width, (int)height); @@ -810,25 +817,21 @@ static void tui_resize(UI *ui, Integer width, Integer height) } } -static void tui_clear(UI *ui) +static void tui_grid_clear(UI *ui, Integer g) { TUIData *data = ui->data; UGrid *grid = &data->grid; ugrid_clear(grid); kv_size(data->invalid_regions) = 0; - clear_region(ui, grid->top, grid->bot, grid->left, grid->right); + clear_region(ui, grid->top, grid->bot, grid->left, grid->right, + data->clear_attrs); } -static void tui_eol_clear(UI *ui) +static void tui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col) { TUIData *data = ui->data; - UGrid *grid = &data->grid; - ugrid_eol_clear(grid); - clear_region(ui, grid->row, grid->row, grid->col, grid->right); -} - -static void tui_cursor_goto(UI *ui, Integer row, Integer col) -{ + data->row = (int)row; + data->col = (int)col; cursor_goto(ui, (int)row, (int)col); } @@ -958,27 +961,23 @@ static void tui_mode_change(UI *ui, String mode, Integer mode_idx) data->showing_mode = (ModeShape)mode_idx; } -static void tui_set_scroll_region(UI *ui, Integer top, Integer bot, - Integer left, Integer right) +static void tui_grid_scroll(UI *ui, Integer g, Integer top, Integer bot, + Integer left, Integer right, + Integer rows, Integer cols) { TUIData *data = ui->data; - ugrid_set_scroll_region(&data->grid, (int)top, (int)bot, - (int)left, (int)right); + UGrid *grid = &data->grid; + ugrid_set_scroll_region(&data->grid, (int)top, (int)bot-1, + (int)left, (int)right-1); + data->scroll_region_is_full_screen = - left == 0 && right == ui->width - 1 - && top == 0 && bot == ui->height - 1; -} + left == 0 && right == ui->width + && top == 0 && bot == ui->height; -static void tui_scroll(UI *ui, Integer count) -{ - TUIData *data = ui->data; - UGrid *grid = &data->grid; int clear_top, clear_bot; - ugrid_scroll(grid, (int)count, &clear_top, &clear_bot); + ugrid_scroll(grid, (int)rows, &clear_top, &clear_bot); if (can_use_scroll(ui)) { - int saved_row = grid->row; - int saved_col = grid->col; bool scroll_clears_to_current_colour = unibi_get_bool(data->ut, unibi_back_color_erase); @@ -989,21 +988,21 @@ static void tui_scroll(UI *ui, Integer count) cursor_goto(ui, grid->top, grid->left); // also set default color attributes or some terminals can become funny if (scroll_clears_to_current_colour) { - update_attrs(ui, grid->clear_attrs); + update_attrs(ui, data->clear_attrs); } - if (count > 0) { - if (count == 1) { + if (rows > 0) { + if (rows == 1) { unibi_out(ui, unibi_delete_line); } else { - UNIBI_SET_NUM_VAR(data->params[0], (int)count); + UNIBI_SET_NUM_VAR(data->params[0], (int)rows); unibi_out(ui, unibi_parm_delete_line); } } else { - if (count == -1) { + if (rows == -1) { unibi_out(ui, unibi_insert_line); } else { - UNIBI_SET_NUM_VAR(data->params[0], -(int)count); + UNIBI_SET_NUM_VAR(data->params[0], -(int)rows); unibi_out(ui, unibi_parm_insert_line); } } @@ -1012,12 +1011,13 @@ static void tui_scroll(UI *ui, Integer count) if (!data->scroll_region_is_full_screen) { reset_scroll_region(ui); } - cursor_goto(ui, saved_row, saved_col); + cursor_goto(ui, data->row, data->col); if (!scroll_clears_to_current_colour) { // Scrolling will leave wrong background in the cleared area on non-BCE // terminals. Update the cleared area. - clear_region(ui, clear_top, clear_bot, grid->left, grid->right); + clear_region(ui, clear_top, clear_bot, grid->left, grid->right, + data->clear_attrs); } } else { // Mark the entire scroll region as invalid for redrawing later @@ -1025,23 +1025,11 @@ static void tui_scroll(UI *ui, Integer count) } } -static void tui_highlight_set(UI *ui, HlAttrs attrs) -{ - ((TUIData *)ui->data)->grid.attrs = attrs; -} - -static void tui_put(UI *ui, String text) +static void tui_hl_attr_define(UI *ui, Integer id, HlAttrs attrs, + HlAttrs cterm_attrs, Array info) { TUIData *data = ui->data; - UGrid *grid = &data->grid; - UCell *cell; - - cell = ugrid_put(&data->grid, (uint8_t *)text.data, text.size); - // ugrid_put does not advance the cursor correctly, as the actual terminal - // will when we print. Its cursor motion model is simplistic and wrong. So - // we have to undo what it has just done before doing it right. - grid->col--; - print_cell(ui, cell); + kv_a(data->attrs, (size_t)id) = attrs; } static void tui_bell(UI *ui) @@ -1058,12 +1046,16 @@ static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp, Integer cterm_fg, Integer cterm_bg) { - UGrid *grid = &((TUIData *)ui->data)->grid; - grid->clear_attrs.rgb_fg_color = (int)rgb_fg; - grid->clear_attrs.rgb_bg_color = (int)rgb_bg; - grid->clear_attrs.rgb_sp_color = (int)rgb_sp; - grid->clear_attrs.cterm_fg_color = (int)cterm_fg; - grid->clear_attrs.cterm_bg_color = (int)cterm_bg; + TUIData *data = ui->data; + + data->clear_attrs.rgb_fg_color = (int)rgb_fg; + data->clear_attrs.rgb_bg_color = (int)rgb_bg; + data->clear_attrs.rgb_sp_color = (int)rgb_sp; + data->clear_attrs.cterm_fg_color = (int)cterm_fg; + data->clear_attrs.cterm_bg_color = (int)cterm_bg; + + data->print_attrs = HLATTRS_INVALID; + invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1); } static void tui_flush(UI *ui) @@ -1083,9 +1075,6 @@ static void tui_flush(UI *ui) tui_busy_stop(ui); // avoid hidden cursor } - int saved_row = grid->row; - int saved_col = grid->col; - while (kv_size(data->invalid_regions)) { Rect r = kv_pop(data->invalid_regions); assert(r.bot < grid->height && r.right < grid->width); @@ -1095,7 +1084,7 @@ static void tui_flush(UI *ui) }); } - cursor_goto(ui, saved_row, saved_col); + cursor_goto(ui, data->row, data->col); flush_buf(ui); } @@ -1176,10 +1165,37 @@ static void tui_option_set(UI *ui, String name, Object value) TUIData *data = ui->data; if (strequal(name.data, "termguicolors")) { ui->rgb = value.data.boolean; + + data->print_attrs = HLATTRS_INVALID; invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1); } } +static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, + Integer endcol, Integer clearcol, Integer clearattr, + const schar_T *chunk, const sattr_T *attrs) +{ + TUIData *data = ui->data; + UGrid *grid = &data->grid; + for (Integer c = startcol; c < endcol; c++) { + memcpy(grid->cells[linerow][c].data, chunk[c-startcol], sizeof(schar_T)); + grid->cells[linerow][c].attrs = kv_A(data->attrs, attrs[c-startcol]); + } + UGRID_FOREACH_CELL(grid, (int)linerow, (int)linerow, (int)startcol, + (int)endcol-1, { + cursor_goto(ui, row, col); + print_cell(ui, cell); + }); + + if (clearcol > endcol) { + HlAttrs cl_attrs = kv_A(data->attrs, (size_t)clearattr); + ugrid_clear_chunk(grid, (int)linerow, (int)endcol, (int)clearcol, + cl_attrs); + clear_region(ui, (int)linerow, (int)linerow, (int)endcol, (int)clearcol-1, + cl_attrs); + } +} + static void invalidate(UI *ui, int top, int bot, int left, int right) { TUIData *data = ui->data; |