diff options
Diffstat (limited to 'src/nvim/drawscreen.c')
-rw-r--r-- | src/nvim/drawscreen.c | 687 |
1 files changed, 310 insertions, 377 deletions
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 6cc623cb72..145229bacc 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1,5 +1,5 @@ // drawscreen.c: Code for updating all the windows on the screen. -// This is the top level, drawline.c is the middle and grid.c/screen.c the lower level. +// This is the top level, drawline.c is the middle and grid.c the lower level. // update_screen() is the function that updates all windows and status lines. // It is called from the main loop when must_redraw is non-zero. It may be @@ -59,15 +59,16 @@ #include <stdlib.h> #include <string.h> -#include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" +#include "nvim/autocmd_defs.h" #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cursor.h" #include "nvim/decoration.h" +#include "nvim/decoration_defs.h" #include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/digraph.h" @@ -76,31 +77,36 @@ #include "nvim/eval.h" #include "nvim/ex_getln.h" #include "nvim/fold.h" -#include "nvim/func_attr.h" +#include "nvim/fold_defs.h" #include "nvim/getchar.h" -#include "nvim/gettext.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/grid.h" +#include "nvim/grid_defs.h" #include "nvim/highlight.h" +#include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" #include "nvim/insexpand.h" +#include "nvim/marktree_defs.h" #include "nvim/match.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/message.h" #include "nvim/move.h" #include "nvim/normal.h" +#include "nvim/normal_defs.h" #include "nvim/option.h" #include "nvim/option_vars.h" +#include "nvim/os/os_defs.h" #include "nvim/plines.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" #include "nvim/profile.h" #include "nvim/regexp.h" #include "nvim/search.h" -#include "nvim/sign_defs.h" #include "nvim/spell.h" #include "nvim/state.h" +#include "nvim/state_defs.h" #include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/syntax.h" @@ -108,10 +114,13 @@ #include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/ui_compositor.h" +#include "nvim/ui_defs.h" #include "nvim/version.h" #include "nvim/vim_defs.h" #include "nvim/window.h" +#include "klib/kvec.h" + /// corner value flags for hsep_connected and vsep_connected typedef enum { WC_TOP_LEFT = 0, @@ -151,8 +160,8 @@ void conceal_check_cursor_line(void) /// There may be some time between setting Rows and Columns and (re)allocating /// default_grid arrays. This happens when starting up and when /// (manually) changing the screen size. Always use default_grid.rows and -/// default_grid.Columns to access items in default_grid.chars[]. Use Rows -/// and Columns for positioning text etc. where the final size of the screen is +/// default_grid.cols to access items in default_grid.chars[]. Use Rows and +/// Columns for positioning text etc. where the final size of the screen is /// needed. /// /// @return whether resizing has been done @@ -171,12 +180,8 @@ bool default_grid_alloc(void) // Allocation of the screen buffers is done only when the size changes and // when Rows and Columns have been set and we have started doing full // screen stuff. - if ((default_grid.chars != NULL - && Rows == default_grid.rows - && Columns == default_grid.cols) - || Rows == 0 - || Columns == 0 - || (!full_screen && default_grid.chars == NULL)) { + if ((default_grid.chars != NULL && Rows == default_grid.rows && Columns == default_grid.cols) + || Rows == 0 || Columns == 0 || (!full_screen && default_grid.chars == NULL)) { resizing = false; return false; } @@ -194,8 +199,8 @@ bool default_grid_alloc(void) grid_alloc(&default_grid, Rows, Columns, true, true); stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size); - tab_page_click_defs = stl_alloc_click_defs(tab_page_click_defs, Columns, - &tab_page_click_defs_size); + tab_page_click_defs + = stl_alloc_click_defs(tab_page_click_defs, Columns, &tab_page_click_defs_size); default_grid.comp_height = Rows; default_grid.comp_width = Columns; @@ -218,8 +223,7 @@ void screenclear(void) // blank out the default grid for (int i = 0; i < default_grid.rows; i++) { - grid_clear_line(&default_grid, default_grid.line_offset[i], - default_grid.cols, true); + grid_clear_line(&default_grid, default_grid.line_offset[i], default_grid.cols, true); } ui_call_grid_clear(1); // clear the display @@ -266,7 +270,7 @@ void screen_resize(int width, int height) return; } - if (width < 0 || height < 0) { // just checking... + if (width < 0 || height < 0) { // just checking... return; } @@ -307,9 +311,9 @@ void screen_resize(int width, int height) RedrawingDisabled++; - win_new_screensize(); // fit the windows in the new sized screen + win_new_screensize(); // fit the windows in the new sized screen - comp_col(); // recompute columns for shown command and ruler + comp_col(); // recompute columns for shown command and ruler RedrawingDisabled--; @@ -403,8 +407,7 @@ void check_screensize(void) /// Return true if redrawing should currently be done. bool redrawing(void) { - return !RedrawingDisabled - && !(p_lz && char_avail() && !KeyTyped && !do_redraw); + return !RedrawingDisabled && !(p_lz && char_avail() && !KeyTyped && !do_redraw); } /// Redraw the parts of the screen that is marked for redraw. @@ -443,7 +446,7 @@ int update_screen(void) // will be redrawn later or in win_update(). must_redraw = 0; - updating_screen = 1; + updating_screen = true; display_tick++; // let syntax code know we're in a next round of // display updating @@ -475,8 +478,7 @@ int update_screen(void) if (msg_grid.chars) { // non-displayed part of msg_grid is considered invalid. for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) { - grid_clear_line(&msg_grid, msg_grid.line_offset[i], - msg_grid.cols, i < p_ch); + grid_clear_line(&msg_grid, msg_grid.line_offset[i], msg_grid.cols, i < p_ch); } } msg_grid.throttled = false; @@ -486,8 +488,7 @@ int update_screen(void) if (type == UPD_NOT_VALID && !ui_has(kUIMultigrid) && msg_scrolled) { was_invalidated = ui_comp_set_screen_valid(false); for (int i = valid; i < Rows - p_ch; i++) { - grid_clear_line(&default_grid, default_grid.line_offset[i], - Columns, false); + grid_clear_line(&default_grid, default_grid.line_offset[i], Columns, false); } FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_floating) { @@ -533,10 +534,10 @@ int update_screen(void) hl_changed = true; } - if (type == UPD_CLEAR) { // first clear screen - screenclear(); // will reset clear_cmdline - // and set UPD_NOT_VALID for each window - cmdline_screen_cleared(); // clear external cmdline state + if (type == UPD_CLEAR) { // first clear screen + screenclear(); // will reset clear_cmdline + // and set UPD_NOT_VALID for each window + cmdline_screen_cleared(); // clear external cmdline state type = UPD_NOT_VALID; // must_redraw may be set indirectly, avoid another redraw later must_redraw = 0; @@ -547,13 +548,12 @@ int update_screen(void) // might need to clear space on default_grid for the message area. if (type == UPD_NOT_VALID && clear_cmdline && !ui_has(kUIMessages)) { - grid_fill(&default_grid, Rows - (int)p_ch, Rows, 0, Columns, ' ', ' ', 0); + grid_clear(&default_grid, Rows - (int)p_ch, Rows, 0, Columns, 0); } ui_comp_set_screen_valid(true); - DecorProviders providers; - decor_providers_start(&providers); + decor_providers_start(); // "start" callback could have changed highlights for global elements if (win_check_ns_hl(NULL)) { @@ -561,7 +561,7 @@ int update_screen(void) redraw_tabline = true; } - if (clear_cmdline) { // going to clear cmdline (done below) + if (clear_cmdline) { // going to clear cmdline (done below) msg_check_for_delay(false); } @@ -570,8 +570,9 @@ int update_screen(void) // TODO(bfredl): special casing curwin here is SÅ JÄVLA BULL. // Either this should be done for all windows or not at all. if (curwin->w_redr_type < UPD_NOT_VALID - && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu || *curwin->w_p_stc) - ? number_width(curwin) : 0)) { + && curwin->w_nrwidth + != ((curwin->w_p_nu || curwin->w_p_rnu || *curwin->w_p_stc) ? number_width(curwin) + : 0)) { curwin->w_redr_type = UPD_NOT_VALID; } @@ -593,26 +594,16 @@ int update_screen(void) buf_T *buf = wp->w_buffer; if (buf->b_mod_set) { - if (buf->b_mod_tick_syn < display_tick - && syntax_present(wp)) { + if (buf->b_mod_tick_syn < display_tick && syntax_present(wp)) { syn_stack_apply_changes(buf); buf->b_mod_tick_syn = display_tick; } if (buf->b_mod_tick_decor < display_tick) { - decor_providers_invoke_buf(buf, &providers); + decor_providers_invoke_buf(buf); buf->b_mod_tick_decor = display_tick; } } - - // Reset 'statuscolumn' if there is no dedicated signcolumn but it is invalid. - if (*wp->w_p_stc != NUL && wp->w_minscwidth <= SCL_NO - && (wp->w_buffer->b_signcols.invalid_bot || !wp->w_buffer->b_signcols.sentinel)) { - wp->w_nrwidth_line_count = 0; - wp->w_valid &= ~VALID_WCOL; - wp->w_redr_type = UPD_NOT_VALID; - wp->w_buffer->b_signcols.invalid_bot = 0; - } } // Go from top to bottom through the windows, redrawing the ones that need it. @@ -639,7 +630,7 @@ int update_screen(void) did_one = true; start_search_hl(); } - win_update(wp, &providers); + win_update(wp); } // redraw status line and window bar after the window to minimize cursor movement @@ -659,13 +650,14 @@ int update_screen(void) win_check_ns_hl(NULL); - // Reset b_mod_set flags. Going through all windows is probably faster - // than going through all buffers (there could be many buffers). + // Reset b_mod_set and b_signcols.resized flags. Going through all windows is + // probably faster than going through all buffers (there could be many buffers). FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { wp->w_buffer->b_mod_set = false; + wp->w_buffer->b_signcols.resized = false; } - updating_screen = 0; + updating_screen = false; // Clear or redraw the command line. Done last, because scrolling may // mess up the command line. @@ -679,8 +671,7 @@ int update_screen(void) } did_intro = true; - decor_providers_invoke_end(&providers); - kvi_destroy(providers); + decor_providers_invoke_end(); // either cmdline is cleared, not drawn or mode is last drawn cmdline_was_last_drawn = false; @@ -740,7 +731,7 @@ int win_get_bordertext_col(int total_col, int text_width, AlignTextPos align) static void win_redr_border(win_T *wp) { wp->w_redr_border = false; - if (!(wp->w_floating && wp->w_float_config.border)) { + if (!(wp->w_floating && wp->w_config.border)) { return; } @@ -748,9 +739,9 @@ static void win_redr_border(win_T *wp) schar_T chars[8]; for (int i = 0; i < 8; i++) { - chars[i] = schar_from_str(wp->w_float_config.border_chars[i]); + chars[i] = schar_from_str(wp->w_config.border_chars[i]); } - int *attrs = wp->w_float_config.border_attr; + int *attrs = wp->w_config.border_attr; int *adj = wp->w_border_adj; int irow = wp->w_height_inner + wp->w_winbar_height; @@ -766,10 +757,10 @@ static void win_redr_border(win_T *wp) grid_line_put_schar(i + adj[3], chars[1], attrs[1]); } - if (wp->w_float_config.title) { - int title_col = win_get_bordertext_col(icol, wp->w_float_config.title_width, - wp->w_float_config.title_pos); - win_redr_bordertext(wp, wp->w_float_config.title_chunks, title_col); + if (wp->w_config.title) { + int title_col + = win_get_bordertext_col(icol, wp->w_config.title_width, wp->w_config.title_pos); + win_redr_bordertext(wp, wp->w_config.title_chunks, title_col); } if (adj[1]) { grid_line_put_schar(icol + adj[3], chars[2], attrs[2]); @@ -802,10 +793,10 @@ static void win_redr_border(win_T *wp) grid_line_put_schar(i + adj[3], chars[ic], attrs[ic]); } - if (wp->w_float_config.footer) { - int footer_col = win_get_bordertext_col(icol, wp->w_float_config.footer_width, - wp->w_float_config.footer_pos); - win_redr_bordertext(wp, wp->w_float_config.footer_chunks, footer_col); + if (wp->w_config.footer) { + int footer_col + = win_get_bordertext_col(icol, wp->w_config.footer_width, wp->w_config.footer_pos); + win_redr_bordertext(wp, wp->w_config.footer_chunks, footer_col); } if (adj[1]) { grid_line_put_schar(icol + adj[3], chars[4], attrs[4]); @@ -834,8 +825,7 @@ void setcursor_mayforce(bool force) // With 'rightleft' set and the cursor on a double-wide character, // position it on the leftmost column. col = curwin->w_width_inner - curwin->w_wcol - - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2 - && vim_isprintc(gchar_cursor())) ? 2 : 1); + - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2 && vim_isprintc(gchar_cursor())) ? 2 : 1); } grid_adjust(&grid, &row, &col); @@ -849,22 +839,19 @@ void setcursor_mayforce(bool force) void show_cursor_info_later(bool force) { int state = get_real_state(); - int empty_line = (State & MODE_INSERT) == 0 - && *ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum) == NUL; + int empty_line + = (State & MODE_INSERT) == 0 && *ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum) == NUL; // Only draw when something changed. validate_virtcol_win(curwin); - if (force - || curwin->w_cursor.lnum != curwin->w_stl_cursor.lnum + if (force || curwin->w_cursor.lnum != curwin->w_stl_cursor.lnum || curwin->w_cursor.col != curwin->w_stl_cursor.col || curwin->w_virtcol != curwin->w_stl_virtcol || curwin->w_cursor.coladd != curwin->w_stl_cursor.coladd || curwin->w_topline != curwin->w_stl_topline || curwin->w_buffer->b_ml.ml_line_count != curwin->w_stl_line_count - || curwin->w_topfill != curwin->w_stl_topfill - || empty_line != curwin->w_stl_empty - || reg_recording != curwin->w_stl_recording - || state != curwin->w_stl_state + || curwin->w_topfill != curwin->w_stl_topfill || empty_line != curwin->w_stl_empty + || reg_recording != curwin->w_stl_recording || state != curwin->w_stl_state || (VIsual_active && VIsual_mode != curwin->w_stl_visual_mode)) { if (curwin->w_status_height || global_stl_height()) { curwin->w_redr_status = true; @@ -876,8 +863,7 @@ void show_cursor_info_later(bool force) curwin->w_redr_status = true; } - if ((p_icon && (stl_syntax & STL_IN_ICON)) - || (p_title && (stl_syntax & STL_IN_TITLE))) { + if ((p_icon && (stl_syntax & STL_IN_ICON)) || (p_title && (stl_syntax & STL_IN_TITLE))) { need_maketitle = true; } } @@ -928,15 +914,12 @@ int showmode(void) msg_grid_validate(); - int do_mode = ((p_smd && msg_silent == 0) - && ((State & MODE_TERMINAL) - || (State & MODE_INSERT) - || restart_edit != NUL - || VIsual_active)); + bool do_mode = ((p_smd && msg_silent == 0) + && ((State & MODE_TERMINAL) || (State & MODE_INSERT) || restart_edit != NUL + || VIsual_active)); bool can_show_mode = (p_ch != 0 || ui_has(kUIMessages)); if ((do_mode || reg_recording != 0) && can_show_mode) { - int sub_attr; if (skip_showmode()) { return 0; // show mode later } @@ -954,7 +937,7 @@ int showmode(void) // Position on the last line in the window, column 0 msg_pos_mode(); - int attr = HL_ATTR(HLF_CM); // Highlight mode + int attr = HL_ATTR(HLF_CM); // Highlight mode // When the screen is too narrow to show the entire mode message, // avoid scrolling and truncate instead. @@ -989,7 +972,8 @@ int showmode(void) } if (edit_submode_extra != NULL) { msg_puts_attr(" ", attr); // Add a space in between. - if ((int)edit_submode_highl < HLF_COUNT) { + int sub_attr; + if (edit_submode_highl < HLF_COUNT) { sub_attr = win_hl_attr(curwin, (int)edit_submode_highl); } else { sub_attr = attr; @@ -1009,8 +993,8 @@ int showmode(void) msg_puts_attr(_(" REVERSE"), attr); } msg_puts_attr(_(" INSERT"), attr); - } else if (restart_edit == 'I' || restart_edit == 'i' - || restart_edit == 'a' || restart_edit == 'A') { + } else if (restart_edit == 'I' || restart_edit == 'i' || restart_edit == 'a' + || restart_edit == 'A') { if (curbuf->terminal) { msg_puts_attr(_(" (terminal)"), attr); } else { @@ -1024,8 +1008,7 @@ int showmode(void) if (State & MODE_LANGMAP) { if (curwin->w_p_arab) { msg_puts_attr(_(" Arabic"), attr); - } else if (get_keymap_str(curwin, " (%s)", - NameBuff, MAXPATHL)) { + } else if (get_keymap_str(curwin, " (%s)", NameBuff, MAXPATHL)) { msg_puts_attr(NameBuff, attr); } } @@ -1038,21 +1021,25 @@ int showmode(void) // Don't concatenate separate words to avoid translation // problems. - switch ((VIsual_select ? 4 : 0) - + (VIsual_mode == Ctrl_V) * 2 - + (VIsual_mode == 'V')) { + switch ((VIsual_select ? 4 : 0) + (VIsual_mode == Ctrl_V) * 2 + (VIsual_mode == 'V')) { case 0: - p = N_(" VISUAL"); break; + p = N_(" VISUAL"); + break; case 1: - p = N_(" VISUAL LINE"); break; + p = N_(" VISUAL LINE"); + break; case 2: - p = N_(" VISUAL BLOCK"); break; + p = N_(" VISUAL BLOCK"); + break; case 4: - p = N_(" SELECT"); break; + p = N_(" SELECT"); + break; case 5: - p = N_(" SELECT LINE"); break; + p = N_(" SELECT LINE"); + break; default: - p = N_(" SELECT BLOCK"); break; + p = N_(" SELECT BLOCK"); + break; } msg_puts_attr(_(p), attr); } @@ -1061,9 +1048,8 @@ int showmode(void) need_clear = true; } - if (reg_recording != 0 - && edit_submode == NULL // otherwise it gets too long - ) { + if (reg_recording != 0 && edit_submode == NULL // otherwise it gets too long + ) { recording_mode(attr); need_clear = true; } @@ -1072,12 +1058,12 @@ int showmode(void) if (need_clear || clear_cmdline || redraw_mode) { msg_clr_eos(); } - msg_didout = false; // overwrite this message + msg_didout = false; // overwrite this message length = msg_col; msg_col = 0; msg_no_more = false; lines_left = save_lines_left; - need_wait_return = nwr_save; // never ask for hit-return for this + need_wait_return = nwr_save; // never ask for hit-return for this } else if (clear_cmdline && msg_silent == 0) { // Clear the whole command line. Will reset "clear_cmdline". msg_clr_cmdline(); @@ -1151,17 +1137,19 @@ void clearmode(void) static void recording_mode(int attr) { - msg_puts_attr(_("recording"), attr); if (shortmess(SHM_RECORDING)) { return; } - char s[4]; - snprintf(s, ARRAY_SIZE(s), " @%c", reg_recording); + msg_puts_attr(_("recording"), attr); + char reg_str[8]; + reg_str[utf_char2bytes(reg_recording, reg_str)] = 0; + char s[16]; + snprintf(s, ARRAY_SIZE(s), " @%s", reg_str); msg_puts_attr(s, attr); } -#define COL_RULER 17 // columns needed by standard ruler +#define COL_RULER 17 // columns needed by standard ruler /// Compute columns for ruler and shown command. 'sc_col' is also used to /// decide what the maximum length of a message on the status line can be. @@ -1180,19 +1168,17 @@ void comp_col(void) sc_col = ru_col; } } - if (p_sc) { + if (p_sc && *p_sloc == 'l') { sc_col += SHOWCMD_COLS; - if (!p_ru || last_has_status) { // no need for separating space + if (!p_ru || last_has_status) { // no need for separating space sc_col++; } } - assert(sc_col >= 0 - && INT_MIN + sc_col <= Columns); + assert(sc_col >= 0 && INT_MIN + sc_col <= Columns); sc_col = Columns - sc_col; - assert(ru_col >= 0 - && INT_MIN + ru_col <= Columns); + assert(ru_col >= 0 && INT_MIN + ru_col <= Columns); ru_col = Columns - ru_col; - if (sc_col <= 0) { // screen too narrow, will become a mess + if (sc_col <= 0) { // screen too narrow, will become a mess sc_col = 1; } if (ru_col <= 0) { @@ -1201,17 +1187,34 @@ void comp_col(void) set_vim_var_nr(VV_ECHOSPACE, sc_col - 1); } -static void redraw_win_signcol(win_T *wp) +/// Redraw entire window "wp" if "auto" 'signcolumn' width has changed. +static bool win_redraw_signcols(win_T *wp) { - // If we can compute a change in the automatic sizing of the sign column - // under 'signcolumn=auto:X' and signs currently placed in the buffer, better - // figuring it out here so we can redraw the entire screen for it. - int scwidth = wp->w_scwidth; - wp->w_scwidth = win_signcol_count(wp); - if (wp->w_scwidth != scwidth) { - changed_line_abv_curs_win(wp); - redraw_later(wp, UPD_NOT_VALID); + buf_T *buf = wp->w_buffer; + + if (!buf->b_signcols.autom + && (*wp->w_p_stc != NUL || (wp->w_maxscwidth > 1 && wp->w_minscwidth != wp->w_maxscwidth))) { + buf->b_signcols.autom = true; + buf_signcols_count_range(buf, 0, buf->b_ml.ml_line_count, MAXLNUM, kFalse); } + + while (buf->b_signcols.max > 0 && buf->b_signcols.count[buf->b_signcols.max - 1] == 0) { + buf->b_signcols.resized = true; + buf->b_signcols.max--; + } + + int width = MIN(wp->w_maxscwidth, buf->b_signcols.max); + bool rebuild_stc = buf->b_signcols.resized && *wp->w_p_stc != NUL; + + if (rebuild_stc) { + wp->w_nrwidth_line_count = 0; + } else if (wp->w_minscwidth == 0 && wp->w_maxscwidth == 1) { + width = buf_meta_total(buf, kMTMetaSignText) > 0; + } + + int scwidth = wp->w_scwidth; + wp->w_scwidth = MAX(MAX(0, wp->w_minscwidth), width); + return (wp->w_scwidth != scwidth || rebuild_stc); } /// Check if horizontal separator of window "wp" at specified window corner is connected to the @@ -1220,8 +1223,7 @@ static void redraw_win_signcol(win_T *wp) static bool hsep_connected(win_T *wp, WindowCorner corner) { bool before = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT); - int sep_row = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) - ? wp->w_winrow - 1 : W_ENDROW(wp); + int sep_row = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) ? wp->w_winrow - 1 : W_ENDROW(wp); frame_T *fr = wp->w_frame; while (fr->fr_parent != NULL) { @@ -1255,8 +1257,8 @@ static bool hsep_connected(win_T *wp, WindowCorner corner) static bool vsep_connected(win_T *wp, WindowCorner corner) { bool before = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT); - int sep_col = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) - ? wp->w_wincol - 1 : W_ENDCOL(wp); + int sep_col + = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) ? wp->w_wincol - 1 : W_ENDCOL(wp); frame_T *fr = wp->w_frame; while (fr->fr_parent != NULL) { @@ -1293,10 +1295,11 @@ static void draw_vsep_win(win_T *wp) } // draw the vertical separator right of this window - int hl = win_hl_attr(wp, HLF_C); - int c = wp->w_p_fcs_chars.vert; - grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp), - W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl); + for (int row = wp->w_winrow; row < W_ENDROW(wp); row++) { + grid_line_start(&default_grid, row); + grid_line_put_schar(W_ENDCOL(wp), wp->w_p_fcs_chars.vert, win_hl_attr(wp, HLF_C)); + grid_line_flush(); + } } /// Draw the horizontal separator below window "wp" @@ -1307,10 +1310,9 @@ static void draw_hsep_win(win_T *wp) } // draw the horizontal separator below this window - int hl = win_hl_attr(wp, HLF_C); - int c = wp->w_p_fcs_chars.horiz; - grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1, - wp->w_wincol, W_ENDCOL(wp), c, c, hl); + grid_line_start(&default_grid, W_ENDROW(wp)); + grid_line_fill(wp->w_wincol, W_ENDCOL(wp), wp->w_p_fcs_chars.horiz, win_hl_attr(wp, HLF_C)); + grid_line_flush(); } /// Get the separator connector for specified window corner of window "wp" @@ -1318,21 +1320,19 @@ static schar_T get_corner_sep_connector(win_T *wp, WindowCorner corner) { // It's impossible for windows to be connected neither vertically nor horizontally // So if they're not vertically connected, assume they're horizontally connected - int c; if (vsep_connected(wp, corner)) { if (hsep_connected(wp, corner)) { - c = wp->w_p_fcs_chars.verthoriz; + return wp->w_p_fcs_chars.verthoriz; } else if (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) { - c = wp->w_p_fcs_chars.vertright; + return wp->w_p_fcs_chars.vertright; } else { - c = wp->w_p_fcs_chars.vertleft; + return wp->w_p_fcs_chars.vertleft; } } else if (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) { - c = wp->w_p_fcs_chars.horizdown; + return wp->w_p_fcs_chars.horizdown; } else { - c = wp->w_p_fcs_chars.horizup; + return wp->w_p_fcs_chars.horizup; } - return schar_from_char(c); } /// Draw separator connecting characters on the corners of window "wp" @@ -1414,28 +1414,28 @@ static void draw_sep_connectors_win(win_T *wp) /// - if wp->w_buffer->b_mod_set set, update lines between /// b_mod_top and b_mod_bot. /// - if wp->w_redraw_top non-zero, redraw lines between -/// wp->w_redraw_top and wp->w_redr_bot. +/// wp->w_redraw_top and wp->w_redraw_bot. /// - continue redrawing when syntax status is invalid. /// 4. if scrolled up, update lines at the bottom. /// This results in three areas that may need updating: /// top: from first row to top_end (when scrolled down) /// mid: from mid_start to mid_end (update inversion or changed text) /// bot: from bot_start to last row (when scrolled up) -static void win_update(win_T *wp, DecorProviders *providers) +static void win_update(win_T *wp) { - int top_end = 0; // Below last row of the top area that needs - // updating. 0 when no top area updating. - int mid_start = 999; // first row of the mid area that needs - // updating. 999 when no mid area updating. - int mid_end = 0; // Below last row of the mid area that needs - // updating. 0 when no mid area updating. - int bot_start = 999; // first row of the bot area that needs - // updating. 999 when no bot area updating - bool scrolled_down = false; // true when scrolled down when w_topline got smaller a bit - bool top_to_mod = false; // redraw above mod_top - - int bot_scroll_start = 999; // first line that needs to be redrawn due to - // scrolling. only used for EOB + int top_end = 0; // Below last row of the top area that needs + // updating. 0 when no top area updating. + int mid_start = 999; // first row of the mid area that needs + // updating. 999 when no mid area updating. + int mid_end = 0; // Below last row of the mid area that needs + // updating. 0 when no mid area updating. + int bot_start = 999; // first row of the bot area that needs + // updating. 999 when no bot area updating + bool scrolled_down = false; // true when scrolled down when w_topline got smaller a bit + bool top_to_mod = false; // redraw above mod_top + + int bot_scroll_start = 999; // first line that needs to be redrawn due to + // scrolling. only used for EOB static bool recursive = false; // being called recursively @@ -1444,9 +1444,10 @@ static void win_update(win_T *wp, DecorProviders *providers) DID_NONE = 1, // didn't update a line DID_LINE = 2, // updated a normal line DID_FOLD = 3, // updated a folded line - } did_update = DID_NONE; + } did_update + = DID_NONE; - linenr_T syntax_last_parsed = 0; // last parsed text line + linenr_T syntax_last_parsed = 0; // last parsed text line linenr_T mod_top = 0; linenr_T mod_bot = 0; @@ -1488,10 +1489,13 @@ static void win_update(win_T *wp, DecorProviders *providers) decor_redraw_reset(wp, &decor_state); - DecorProviders line_providers; - decor_providers_invoke_win(wp, providers, &line_providers); + decor_providers_invoke_win(wp); - redraw_win_signcol(wp); + if (win_redraw_signcols(wp)) { + wp->w_lines_valid = 0; + wp->w_redr_type = UPD_NOT_VALID; + changed_line_abv_curs_win(wp); + } init_search_hl(wp, &screen_search_hl); @@ -1521,13 +1525,6 @@ static void win_update(win_T *wp, DecorProviders *providers) if (wp->w_nrwidth != nrwidth_new) { type = UPD_NOT_VALID; wp->w_nrwidth = nrwidth_new; - } else if (buf->b_mod_set - && buf->b_mod_xlines != 0 - && wp->w_redraw_top != 0) { - // When there are both inserted/deleted lines and specific lines to be - // redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw - // everything (only happens when redrawing is off for while). - type = UPD_NOT_VALID; } else { // Set mod_top to the first line that needs displaying because of // changes. Set mod_bot to the first line after the changes. @@ -1558,14 +1555,12 @@ static void win_update(win_T *wp, DecorProviders *providers) // previous line invalid. Simple solution: redraw all visible // lines above the change. // Same for a match pattern. - if (screen_search_hl.rm.regprog != NULL - && re_multiline(screen_search_hl.rm.regprog)) { + if (screen_search_hl.rm.regprog != NULL && re_multiline(screen_search_hl.rm.regprog)) { top_to_mod = true; } else { const matchitem_T *cur = wp->w_match_head; while (cur != NULL) { - if (cur->mit_match.regprog != NULL - && re_multiline(cur->mit_match.regprog)) { + if (cur->mit_match.regprog != NULL && re_multiline(cur->mit_match.regprog)) { top_to_mod = true; break; } @@ -1602,14 +1597,14 @@ static void win_update(win_T *wp, DecorProviders *providers) } } - (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, true, NULL); + hasFoldingWin(wp, mod_top, &mod_top, NULL, true, NULL); if (mod_top > lnumt) { mod_top = lnumt; } // Now do the same for the bottom line (one above mod_bot). mod_bot--; - (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, true, NULL); + hasFoldingWin(wp, mod_bot, NULL, &mod_bot, true, NULL); mod_bot++; if (mod_bot < lnumb) { mod_bot = lnumb; @@ -1627,12 +1622,6 @@ static void win_update(win_T *wp, DecorProviders *providers) top_end = 1; } } - - // When line numbers are displayed need to redraw all lines below - // inserted/deleted lines. - if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu) { - mod_bot = MAXLNUM; - } } wp->w_redraw_top = 0; // reset for next time @@ -1664,13 +1653,11 @@ static void win_update(win_T *wp, DecorProviders *providers) // 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up // 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in // w_lines[] that needs updating. - if ((type == UPD_VALID || type == UPD_SOME_VALID - || type == UPD_INVERTED || type == UPD_INVERTED_ALL) + if ((type == UPD_VALID || type == UPD_SOME_VALID || type == UPD_INVERTED + || type == UPD_INVERTED_ALL) && !wp->w_botfill && !wp->w_old_botfill) { - if (mod_top != 0 - && wp->w_topline == mod_top - && (!wp->w_lines[0].wl_valid - || wp->w_topline == wp->w_lines[0].wl_lnum)) { + if (mod_top != 0 && wp->w_topline == mod_top + && (!wp->w_lines[0].wl_valid || wp->w_topline == wp->w_lines[0].wl_lnum)) { // w_topline is the first changed line and window is not scrolled, // the scrolling from changed lines will be done further down. } else if (wp->w_lines[0].wl_valid @@ -1680,22 +1667,20 @@ static void win_update(win_T *wp, DecorProviders *providers) // New topline is above old topline: May scroll down. int j; if (hasAnyFolding(wp)) { - linenr_T ln; - // count the number of lines we are off, counting a sequence // of folded lines as one j = 0; - for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ln++) { + for (linenr_T ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ln++) { j++; if (j >= wp->w_grid.rows - 2) { break; } - (void)hasFoldingWin(wp, ln, NULL, &ln, true, NULL); + hasFoldingWin(wp, ln, NULL, &ln, true, NULL); } } else { j = wp->w_lines[0].wl_lnum - wp->w_topline; } - if (j < wp->w_grid.rows - 2) { // not too far off + if (j < wp->w_grid.rows - 2) { // not too far off int i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1, true); // insert extra lines for previously invisible filler lines if (wp->w_lines[0].wl_lnum != wp->w_topline) { @@ -1741,8 +1726,7 @@ static void win_update(win_T *wp, DecorProviders *providers) int j = -1; int row = 0; for (int i = 0; i < wp->w_lines_valid; i++) { - if (wp->w_lines[i].wl_valid - && wp->w_lines[i].wl_lnum == wp->w_topline) { + if (wp->w_lines[i].wl_valid && wp->w_lines[i].wl_lnum == wp->w_topline) { j = i; break; } @@ -1781,8 +1765,7 @@ static void win_update(win_T *wp, DecorProviders *providers) wp->w_lines[idx] = wp->w_lines[j]; // stop at line that didn't fit, unless it is still // valid (no lines deleted) - if (row > 0 && bot_start + row - + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) { + if (row > 0 && bot_start + row + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) { wp->w_lines_valid = idx + 1; break; } @@ -1798,8 +1781,8 @@ static void win_update(win_T *wp, DecorProviders *providers) // Correct the first entry for filler lines at the top // when it won't get updated below. if (win_may_fill(wp) && bot_start > 0) { - wp->w_lines[0].wl_size = (uint16_t)(plines_win_nofill(wp, wp->w_topline, true) - + wp->w_topfill); + wp->w_lines[0].wl_size + = (uint16_t)(plines_win_nofill(wp, wp->w_topline, true) + wp->w_topfill); } } } @@ -1862,15 +1845,13 @@ static void win_update(win_T *wp, DecorProviders *providers) } else { from = wp->w_old_cursor_lnum; to = curwin->w_cursor.lnum; - if (from == 0) { // Visual mode just started + if (from == 0) { // Visual mode just started from = to; } } - if (VIsual.lnum != wp->w_old_visual_lnum - || VIsual.col != wp->w_old_visual_col) { - if (wp->w_old_visual_lnum < from - && wp->w_old_visual_lnum != 0) { + if (VIsual.lnum != wp->w_old_visual_lnum || VIsual.col != wp->w_old_visual_col) { + if (wp->w_old_visual_lnum < from && wp->w_old_visual_lnum != 0) { from = wp->w_old_visual_lnum; } if (wp->w_old_visual_lnum > to) { @@ -1926,8 +1907,7 @@ static void win_update(win_T *wp, DecorProviders *providers) } } - if (fromc != wp->w_old_cursor_fcol - || toc != wp->w_old_cursor_lcol) { + if (fromc != wp->w_old_cursor_fcol || toc != wp->w_old_cursor_lcol) { if (from > VIsual.lnum) { from = VIsual.lnum; } @@ -1981,7 +1961,7 @@ static void win_update(win_T *wp, DecorProviders *providers) } else { mid_start = 0; } - while (lnum < from && idx < wp->w_lines_valid) { // find start + while (lnum < from && idx < wp->w_lines_valid) { // find start if (wp->w_lines[idx].wl_valid) { mid_start += wp->w_lines[idx].wl_size; } else if (!scrolled_down) { @@ -1996,9 +1976,8 @@ static void win_update(win_T *wp, DecorProviders *providers) } srow += mid_start; mid_end = wp->w_grid.rows; - for (; idx < wp->w_lines_valid; idx++) { // find end - if (wp->w_lines[idx].wl_valid - && wp->w_lines[idx].wl_lnum >= to + 1) { + for (; idx < wp->w_lines_valid; idx++) { // find end + if (wp->w_lines[idx].wl_valid && wp->w_lines[idx].wl_lnum >= to + 1) { // Only update until first row of this line mid_end = srow; break; @@ -2042,12 +2021,12 @@ static void win_update(win_T *wp, DecorProviders *providers) } // Update all the window rows. - int idx = 0; // first entry in w_lines[].wl_size - int row = 0; // current window row to display - int srow = 0; // starting row of the current line + int idx = 0; // first entry in w_lines[].wl_size + int row = 0; // current window row to display + int srow = 0; // starting row of the current line - bool eof = false; // if true, we hit the end of the file - bool didline = false; // if true, we finished the last line + bool eof = false; // if true, we hit the end of the file + bool didline = false; // if true, we finished the last line while (true) { // stop updating when reached the end of the window (check for _past_ // the end of the window is at the end of the loop) @@ -2073,27 +2052,19 @@ static void win_update(win_T *wp, DecorProviders *providers) // When syntax folding is being used, the saved syntax states will // already have been updated, we can't see where the syntax state is // the same again, just update until the end of the window. - if (row < top_end - || (row >= mid_start && row < mid_end) - || top_to_mod - || idx >= wp->w_lines_valid - || (row + wp->w_lines[idx].wl_size > bot_start) + if (row < top_end || (row >= mid_start && row < mid_end) || top_to_mod + || idx >= wp->w_lines_valid || (row + wp->w_lines[idx].wl_size > bot_start) || (mod_top != 0 && (lnum == mod_top || (lnum >= mod_top - && (lnum < mod_bot - || did_update == DID_FOLD - || (did_update == DID_LINE - && syntax_present(wp) - && ((foldmethodIsSyntax(wp) - && hasAnyFolding(wp)) + && (lnum < mod_bot || did_update == DID_FOLD + || (did_update == DID_LINE && syntax_present(wp) + && ((foldmethodIsSyntax(wp) && hasAnyFolding(wp)) || syntax_check_changed(lnum))) // match in fixed position might need redraw // if lines were inserted or deleted - || (wp->w_match_head != NULL - && buf->b_mod_xlines != 0))))) - || lnum == wp->w_cursorline - || lnum == wp->w_last_cursorline) { + || (wp->w_match_head != NULL && buf->b_mod_xlines != 0))))) + || lnum == wp->w_cursorline || lnum == wp->w_last_cursorline) { if (lnum == mod_top) { top_to_mod = false; } @@ -2103,9 +2074,7 @@ static void win_update(win_T *wp, DecorProviders *providers) // Don't do this when the change continues until the end. // Don't scroll when dollar_vcol >= 0, keep the "$". // Don't scroll when redrawing the top, scrolled already above. - if (lnum == mod_top - && mod_bot != MAXLNUM - && !(dollar_vcol >= 0 && mod_bot == mod_top + 1) + if (lnum == mod_top && mod_bot != MAXLNUM && !(dollar_vcol >= 0 && mod_bot == mod_top + 1) && row >= top_end) { int old_rows = 0; linenr_T l; @@ -2117,18 +2086,15 @@ static void win_update(win_T *wp, DecorProviders *providers) for (i = idx; i < wp->w_lines_valid; i++) { // Only valid lines have a meaningful wl_lnum. Invalid // lines are part of the changed area. - if (wp->w_lines[i].wl_valid - && wp->w_lines[i].wl_lnum == mod_bot) { + if (wp->w_lines[i].wl_valid && wp->w_lines[i].wl_lnum == mod_bot) { break; } old_rows += wp->w_lines[i].wl_size; - if (wp->w_lines[i].wl_valid - && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) { + if (wp->w_lines[i].wl_valid && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) { // Must have found the last valid entry above mod_bot. // Add following invalid entries. i++; - while (i < wp->w_lines_valid - && !wp->w_lines[i].wl_valid) { + while (i < wp->w_lines_valid && !wp->w_lines[i].wl_valid) { old_rows += wp->w_lines[i++].wl_size; } break; @@ -2211,8 +2177,7 @@ static void win_update(win_T *wp, DecorProviders *providers) } wp->w_lines[j] = wp->w_lines[i]; // stop at a line that won't fit - if (x + (int)wp->w_lines[j].wl_size - > wp->w_grid.rows) { + if (x + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) { wp->w_lines_valid = j + 1; break; } @@ -2222,8 +2187,8 @@ static void win_update(win_T *wp, DecorProviders *providers) if (bot_start > x) { bot_start = x; } - } else { // j > i - // move entries in w_lines[] downwards + } else { // j > i + // move entries in w_lines[] downwards j -= i; wp->w_lines_valid += (linenr_T)j; if (wp->w_lines_valid > wp->w_grid.rows) { @@ -2248,52 +2213,52 @@ static void win_update(win_T *wp, DecorProviders *providers) // When lines are folded, display one line for all of them. // Otherwise, display normally (can be several display lines when // 'wrap' is on). - foldinfo_T foldinfo = wp->w_p_cul && lnum == wp->w_cursor.lnum - ? cursorline_fi : fold_info(wp, lnum); - - if (foldinfo.fi_lines == 0 - && idx < wp->w_lines_valid - && wp->w_lines[idx].wl_valid - && wp->w_lines[idx].wl_lnum == lnum - && lnum > wp->w_topline + foldinfo_T foldinfo + = wp->w_p_cul && lnum == wp->w_cursor.lnum ? cursorline_fi : fold_info(wp, lnum); + + if (foldinfo.fi_lines == 0 && idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid + && wp->w_lines[idx].wl_lnum == lnum && lnum > wp->w_topline && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) - && srow + wp->w_lines[idx].wl_size > wp->w_grid.rows - && win_get_fill(wp, lnum) == 0) { + && srow + wp->w_lines[idx].wl_size > wp->w_grid.rows && win_get_fill(wp, lnum) == 0) { // This line is not going to fit. Don't draw anything here, // will draw "@ " lines below. row = wp->w_grid.rows + 1; } else { prepare_search_hl(wp, &screen_search_hl, lnum); // Let the syntax stuff know we skipped a few lines. - if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum - && syntax_present(wp)) { + if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum && syntax_present(wp)) { syntax_end_parsing(wp, syntax_last_parsed + 1); } + bool display_buf_line = (foldinfo.fi_lines == 0 || *wp->w_p_fdt == NUL); + // Display one line spellvars_T zero_spv = { 0 }; - row = win_line(wp, lnum, srow, wp->w_grid.rows, false, - foldinfo.fi_lines > 0 ? &zero_spv : &spv, - foldinfo, &line_providers); + row = win_line(wp, lnum, srow, wp->w_grid.rows, 0, display_buf_line ? &spv : &zero_spv, + foldinfo); + + if (display_buf_line) { + syntax_last_parsed = lnum; + } else { + spv.spv_capcol_lnum = 0; + } if (foldinfo.fi_lines == 0) { wp->w_lines[idx].wl_folded = false; wp->w_lines[idx].wl_lastlnum = lnum; did_update = DID_LINE; - syntax_last_parsed = lnum; } else { foldinfo.fi_lines--; wp->w_lines[idx].wl_folded = true; wp->w_lines[idx].wl_lastlnum = lnum + foldinfo.fi_lines; did_update = DID_FOLD; - spv.spv_capcol_lnum = 0; } } wp->w_lines[idx].wl_lnum = lnum; wp->w_lines[idx].wl_valid = true; - if (row > wp->w_grid.rows) { // past end of grid + if (row > wp->w_grid.rows) { // past end of grid // we may need the size of that too long line later on if (dollar_vcol == -1) { wp->w_lines[idx].wl_size = (uint16_t)plines_win(wp, lnum, true); @@ -2307,12 +2272,15 @@ static void win_update(win_T *wp, DecorProviders *providers) idx++; lnum += foldinfo.fi_lines + 1; } else { - if (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum) { - // 'relativenumber' set and cursor moved vertically: The - // text doesn't need to be drawn, but the number column does. - foldinfo_T info = wp->w_p_cul && lnum == wp->w_cursor.lnum - ? cursorline_fi : fold_info(wp, lnum); - (void)win_line(wp, lnum, srow, wp->w_grid.rows, true, &spv, info, &line_providers); + // If: + // - 'number' is set and below inserted/deleted lines, or + // - 'relativenumber' is set and cursor moved vertically, + // the text doesn't need to be redrawn, but the number column does. + if ((wp->w_p_nu && mod_top != 0 && lnum >= mod_bot && buf->b_mod_xlines != 0) + || (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum)) { + foldinfo_T info + = wp->w_p_cul && lnum == wp->w_cursor.lnum ? cursorline_fi : fold_info(wp, lnum); + win_line(wp, lnum, srow, wp->w_grid.rows, wp->w_lines[idx].wl_size, &spv, info); } // This line does not need to be drawn, advance to the next one. @@ -2327,6 +2295,7 @@ static void win_update(win_T *wp, DecorProviders *providers) // 'statuscolumn' width has changed or errored, start from the top. if (wp->w_redr_statuscol) { + redr_statuscol: wp->w_redr_statuscol = false; idx = 0; row = 0; @@ -2334,7 +2303,7 @@ static void win_update(win_T *wp, DecorProviders *providers) wp->w_lines_valid = 0; wp->w_valid &= ~VALID_WCOL; decor_redraw_reset(wp, &decor_state); - decor_providers_invoke_win(wp, providers, &line_providers); + decor_providers_invoke_win(wp); continue; } @@ -2376,26 +2345,26 @@ static void win_update(win_T *wp, DecorProviders *providers) // Window ends in filler lines. wp->w_botline = lnum; wp->w_filler_rows = wp->w_grid.rows - srow; - } else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate" + } else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate" // Last line isn't finished: Display "@@@" in the last screen line. grid_line_start(&wp->w_grid, wp->w_grid.rows - 1); grid_line_fill(0, MIN(wp->w_grid.cols, 3), wp->w_p_fcs_chars.lastline, at_attr); - grid_line_fill(3, wp->w_grid.cols, ' ', at_attr); + grid_line_fill(3, wp->w_grid.cols, schar_from_ascii(' '), at_attr); grid_line_flush(); set_empty_rows(wp, srow); wp->w_botline = lnum; - } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" + } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" // Last line isn't finished: Display "@@@" at the end. // If this would split a doublewidth char in two, we need to display "@@@@" instead grid_line_start(&wp->w_grid, wp->w_grid.rows - 1); int width = grid_line_getchar(MAX(wp->w_grid.cols - 3, 0), NULL) == NUL ? 4 : 3; - grid_line_fill(MAX(wp->w_grid.cols - width, 0), wp->w_grid.cols, - wp->w_p_fcs_chars.lastline, at_attr); + grid_line_fill(MAX(wp->w_grid.cols - width, 0), wp->w_grid.cols, wp->w_p_fcs_chars.lastline, + at_attr); grid_line_flush(); set_empty_rows(wp, srow); wp->w_botline = lnum; } else { - win_draw_end(wp, wp->w_p_fcs_chars.lastline, ' ', true, srow, wp->w_grid.rows, HLF_AT); + win_draw_end(wp, wp->w_p_fcs_chars.lastline, true, srow, wp->w_grid.rows, HLF_AT); set_empty_rows(wp, srow); wp->w_botline = lnum; } @@ -2408,8 +2377,11 @@ static void win_update(win_T *wp, DecorProviders *providers) // for ml_line_count+1 and only draw filler lines spellvars_T zero_spv = { 0 }; foldinfo_T zero_foldinfo = { 0 }; - row = win_line(wp, wp->w_botline, row, wp->w_grid.rows, false, &zero_spv, - zero_foldinfo, &line_providers); + row = win_line(wp, wp->w_botline, row, wp->w_grid.rows, 0, &zero_spv, zero_foldinfo); + if (wp->w_redr_statuscol) { + eof = false; + goto redr_statuscol; + } } } else if (dollar_vcol == -1) { wp->w_botline = lnum; @@ -2428,13 +2400,10 @@ static void win_update(win_T *wp, DecorProviders *providers) lastline = 0; } - win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, MAX(lastline, row), wp->w_grid.rows, - HLF_EOB); + win_draw_end(wp, wp->w_p_fcs_chars.eob, false, MAX(lastline, row), wp->w_grid.rows, HLF_EOB); set_empty_rows(wp, row); } - kvi_destroy(line_providers); - if (wp->w_redr_type >= UPD_REDRAW_TOP) { draw_vsep_win(wp); draw_hsep_win(wp); @@ -2449,9 +2418,9 @@ static void win_update(win_T *wp, DecorProviders *providers) // Send win_extmarks if needed for (size_t n = 0; n < kv_size(win_extmark_arr); n++) { - ui_call_win_extmark(wp->w_grid_alloc.handle, wp->handle, - kv_A(win_extmark_arr, n).ns_id, (Integer)kv_A(win_extmark_arr, n).mark_id, - kv_A(win_extmark_arr, n).win_row, kv_A(win_extmark_arr, n).win_col); + ui_call_win_extmark(wp->w_grid_alloc.handle, wp->handle, kv_A(win_extmark_arr, n).ns_id, + (Integer)kv_A(win_extmark_arr, n).mark_id, kv_A(win_extmark_arr, n).win_row, + kv_A(win_extmark_arr, n).win_col); } if (dollar_vcol == -1) { @@ -2475,7 +2444,7 @@ static void win_update(win_T *wp, DecorProviders *providers) // Don't update for changes in buffer again. int mod_set = curbuf->b_mod_set; curbuf->b_mod_set = false; - win_update(curwin, providers); + win_update(curwin); must_redraw = 0; curbuf->b_mod_set = mod_set; } @@ -2509,71 +2478,49 @@ void win_scroll_lines(win_T *wp, int row, int line_count) } if (line_count < 0) { - grid_del_lines(&wp->w_grid, row, -line_count, - wp->w_grid.rows, 0, wp->w_grid.cols); + grid_del_lines(&wp->w_grid, row, -line_count, wp->w_grid.rows, 0, wp->w_grid.cols); } else { - grid_ins_lines(&wp->w_grid, row, line_count, - wp->w_grid.rows, 0, wp->w_grid.cols); + grid_ins_lines(&wp->w_grid, row, line_count, wp->w_grid.rows, 0, wp->w_grid.cols); } } -/// Call grid_fill() with columns adjusted for 'rightleft' if needed. -/// Return the new offset. -static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row, int endrow, - int attr) -{ - int nn = off + width; - const int endcol = wp->w_grid.cols; - - if (nn > endcol) { - nn = endcol; - } - - if (wp->w_p_rl) { - grid_fill(&wp->w_grid, row, endrow, endcol - nn, endcol - off, c1, c2, attr); - } else { - grid_fill(&wp->w_grid, row, endrow, off, nn, c1, c2, attr); - } - - return nn; -} - /// Clear lines near the end of the window and mark the unused lines with "c1". -/// Use "c2" as filler character. /// When "draw_margin" is true, then draw the sign/fold/number columns. -void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, int endrow, hlf_T hl) +void win_draw_end(win_T *wp, schar_T c1, bool draw_margin, int startrow, int endrow, hlf_T hl) { assert(hl >= 0 && hl < HLF_COUNT); - int n = 0; - - if (draw_margin) { - // draw the fold column - int fdc = compute_foldcolumn(wp, 0); - if (fdc > 0) { - n = win_fill_end(wp, ' ', ' ', n, fdc, row, endrow, - win_hl_attr(wp, HLF_FC)); - } - // draw the sign column - int count = wp->w_scwidth; - if (count > 0) { - n = win_fill_end(wp, ' ', ' ', n, SIGN_WIDTH * count, row, - endrow, win_hl_attr(wp, HLF_SC)); + for (int row = startrow; row < endrow; row++) { + grid_line_start(&wp->w_grid, row); + + int n = 0; + if (draw_margin) { + // draw the fold column + int fdc = MAX(0, compute_foldcolumn(wp, 0)); + n = grid_line_fill(n, n + fdc, schar_from_ascii(' '), win_hl_attr(wp, HLF_FC)); + + // draw the sign column + n = grid_line_fill(n, n + wp->w_scwidth, schar_from_ascii(' '), win_hl_attr(wp, HLF_FC)); + + // draw the number column + if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) == NULL) { + int width = number_width(wp) + 1; + n = grid_line_fill(n, n + width, schar_from_ascii(' '), win_hl_attr(wp, HLF_N)); + } } - // draw the number column - if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) == NULL) { - n = win_fill_end(wp, ' ', ' ', n, number_width(wp) + 1, row, endrow, - win_hl_attr(wp, HLF_N)); + + int attr = hl_combine_attr(win_bg_attr(wp), win_hl_attr(wp, (int)hl)); + + if (n < wp->w_grid.cols) { + grid_line_put_schar(n, c1, 0); // base attr is inherited from clear + n++; } - } - int attr = hl_combine_attr(win_bg_attr(wp), win_hl_attr(wp, (int)hl)); + grid_line_clear_end(n, wp->w_grid.cols, attr); - const int endcol = wp->w_grid.cols; - if (wp->w_p_rl) { - grid_fill(&wp->w_grid, row, endrow, 0, endcol - 1 - n, c2, c2, attr); - grid_fill(&wp->w_grid, row, endrow, endcol - 1 - n, endcol - n, c1, c2, attr); - } else { - grid_fill(&wp->w_grid, row, endrow, n, endcol, c1, c2, attr); + if (wp->w_p_rl) { + grid_line_mirror(); + } + grid_line_flush(); } } @@ -2631,7 +2578,7 @@ int number_width(win_T *wp) // If 'signcolumn' is set to 'number' and there is a sign to display, then // the minimal width for the number column is 2. - if (n < 2 && wp->w_buffer->b_signs_with_text && wp->w_minscwidth == SCL_NUM) { + if (n < 2 && buf_meta_total(wp->w_buffer, kMTMetaSignText) && wp->w_minscwidth == SCL_NUM) { n = 2; } @@ -2644,14 +2591,15 @@ int number_width(win_T *wp) /// Set must_redraw only if not already set to a higher value. /// e.g. if must_redraw is UPD_CLEAR, type UPD_NOT_VALID will do nothing. void redraw_later(win_T *wp, int type) - FUNC_ATTR_NONNULL_ALL { - if (!exiting && wp->w_redr_type < type) { + // curwin may have been set to NULL when exiting + assert(wp != NULL || exiting); + if (!exiting && !redraw_not_allowed && wp->w_redr_type < type) { wp->w_redr_type = type; if (type >= UPD_NOT_VALID) { wp->w_lines_valid = 0; } - if (must_redraw < type) { // must_redraw is the maximum of all windows + if (must_redraw < type) { // must_redraw is the maximum of all windows must_redraw = type; } } @@ -2664,7 +2612,14 @@ void redraw_all_later(int type) redraw_later(wp, type); } // This may be needed when switching tabs. - if (must_redraw < type) { + set_must_redraw(type); +} + +/// Set "must_redraw" to "type" unless it already has a higher value +/// or it is currently not allowed. +void set_must_redraw(int type) +{ + if (!redraw_not_allowed && must_redraw < type) { must_redraw = type; } } @@ -2704,11 +2659,10 @@ void redraw_buf_line_later(buf_T *buf, linenr_T line, bool force) } } -void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline) +void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == buf - && lastline >= wp->w_topline && firstline < wp->w_botline) { + if (wp->w_buffer == buf && lastline >= wp->w_topline && firstline < wp->w_botline) { if (wp->w_redraw_top == 0 || wp->w_redraw_top > firstline) { wp->w_redraw_top = firstline; } @@ -2725,13 +2679,9 @@ void redraw_buf_status_later(buf_T *buf) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer == buf - && (wp->w_status_height - || (wp == curwin && global_stl_height()) - || wp->w_winbar_height)) { + && (wp->w_status_height || (wp == curwin && global_stl_height()) || wp->w_winbar_height)) { wp->w_redr_status = true; - if (must_redraw < UPD_VALID) { - must_redraw = UPD_VALID; - } + set_must_redraw(UPD_VALID); } } } @@ -2742,8 +2692,7 @@ void status_redraw_all(void) bool is_stl_global = global_stl_height() != 0; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if ((!is_stl_global && wp->w_status_height) || wp == curwin - || wp->w_winbar_height) { + if ((!is_stl_global && wp->w_status_height) || wp == curwin || wp->w_winbar_height) { wp->w_redr_status = true; redraw_later(wp, UPD_VALID); } @@ -2762,8 +2711,9 @@ void status_redraw_buf(buf_T *buf) bool is_stl_global = global_stl_height() != 0; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == buf && ((!is_stl_global && wp->w_status_height) - || (is_stl_global && wp == curwin) || wp->w_winbar_height)) { + if (wp->w_buffer == buf + && ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin) + || wp->w_winbar_height)) { wp->w_redr_status = true; redraw_later(wp, UPD_VALID); } @@ -2793,8 +2743,7 @@ void redraw_statuslines(void) } /// Redraw all status lines at the bottom of frame "frp". -void win_redraw_last_status(const frame_T *frp) - FUNC_ATTR_NONNULL_ARG(1) +void win_redraw_last_status(const frame_T *frp) FUNC_ATTR_NONNULL_ARG(1) { if (frp->fr_layout == FR_LEAF) { frp->fr_win->w_redr_status = true; @@ -2818,11 +2767,9 @@ void win_redraw_last_status(const frame_T *frp) /// Used to remove the "$" from a change command. /// Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot /// may become invalid and the whole window will have to be redrawn. -void redrawWinline(win_T *wp, linenr_T lnum) - FUNC_ATTR_NONNULL_ALL +void redrawWinline(win_T *wp, linenr_T lnum) FUNC_ATTR_NONNULL_ALL { - if (lnum >= wp->w_topline - && lnum < wp->w_botline) { + if (lnum >= wp->w_topline && lnum < wp->w_botline) { if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) { wp->w_redraw_top = lnum; } @@ -2835,8 +2782,7 @@ void redrawWinline(win_T *wp, linenr_T lnum) /// Return true if the cursor line in window "wp" may be concealed, according /// to the 'concealcursor' option. -bool conceal_cursor_line(const win_T *wp) - FUNC_ATTR_NONNULL_ALL +bool conceal_cursor_line(const win_T *wp) FUNC_ATTR_NONNULL_ALL { int c; @@ -2860,20 +2806,7 @@ bool conceal_cursor_line(const win_T *wp) /// Whether cursorline is drawn in a special way /// /// If true, both old and new cursorline will need to be redrawn when moving cursor within windows. -bool win_cursorline_standout(const win_T *wp) - FUNC_ATTR_NONNULL_ALL +bool win_cursorline_standout(const win_T *wp) FUNC_ATTR_NONNULL_ALL { return wp->w_p_cul || (wp->w_p_cole > 0 && !conceal_cursor_line(wp)); } - -/// Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set. -/// Also when concealing is on and 'concealcursor' is not active. -void redraw_for_cursorline(win_T *wp) - FUNC_ATTR_NONNULL_ALL -{ - if ((wp->w_valid & VALID_CROW) == 0 && !pum_visible() - && (wp->w_p_rnu || win_cursorline_standout(wp))) { - // win_line() will redraw the number column and cursorline only. - redraw_later(wp, UPD_VALID); - } -} |