diff options
Diffstat (limited to 'src/nvim/drawscreen.c')
-rw-r--r-- | src/nvim/drawscreen.c | 689 |
1 files changed, 353 insertions, 336 deletions
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 2abff6c894..04c342e068 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -20,7 +20,7 @@ // // Commands that scroll a window change w_topline and must call // check_cursor() to move the cursor into the visible part of the window, and -// call redraw_later(wp, VALID) to have the window displayed by update_screen() +// call redraw_later(wp, UPD_VALID) to have the window displayed by update_screen() // later. // // Commands that change text in the buffer must call changed_bytes() or @@ -32,23 +32,23 @@ // // Commands that change how a window is displayed (e.g., setting 'list') or // invalidate the contents of a window in another way (e.g., change fold -// settings), must call redraw_later(wp, NOT_VALID) to have the whole window +// settings), must call redraw_later(wp, UPD_NOT_VALID) to have the whole window // redisplayed by update_screen() later. // // Commands that change how a buffer is displayed (e.g., setting 'tabstop') -// must call redraw_curbuf_later(NOT_VALID) to have all the windows for the +// must call redraw_curbuf_later(UPD_NOT_VALID) to have all the windows for the // buffer redisplayed by update_screen() later. // // Commands that change highlighting and possibly cause a scroll too must call -// redraw_later(wp, SOME_VALID) to update the whole window but still use +// redraw_later(wp, UPD_SOME_VALID) to update the whole window but still use // scrolling to avoid redrawing everything. But the length of displayed lines -// must not change, use NOT_VALID then. +// must not change, use UPD_NOT_VALID then. // -// Commands that move the window position must call redraw_later(wp, NOT_VALID). +// Commands that move the window position must call redraw_later(wp, UPD_NOT_VALID). // TODO(neovim): should minimize redrawing by scrolling when possible. // // Commands that change everything (e.g., resizing the screen) must call -// redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR). +// redraw_all_later(UPD_NOT_VALID) or redraw_all_later(UPD_CLEAR). // // Things that are handled indirectly: // - When messages scroll the screen up, msg_scrolled will be set and @@ -59,28 +59,47 @@ #include <stdbool.h> #include <string.h> +#include "klib/kvec.h" +#include "nvim/api/private/defs.h" +#include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" +#include "nvim/decoration.h" +#include "nvim/decoration_provider.h" #include "nvim/diff.h" +#include "nvim/drawline.h" #include "nvim/drawscreen.h" #include "nvim/ex_getln.h" +#include "nvim/extmark_defs.h" +#include "nvim/fold.h" +#include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/insexpand.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/option.h" #include "nvim/plines.h" #include "nvim/popupmenu.h" +#include "nvim/pos.h" #include "nvim/profile.h" #include "nvim/regexp.h" +#include "nvim/screen.h" #include "nvim/statusline.h" #include "nvim/syntax.h" +#include "nvim/terminal.h" +#include "nvim/types.h" +#include "nvim/ui.h" #include "nvim/ui_compositor.h" -#include "nvim/undo.h" #include "nvim/version.h" +#include "nvim/vim.h" #include "nvim/window.h" /// corner value flags for hsep_connected and vsep_connected @@ -97,7 +116,7 @@ typedef enum { static bool redraw_popupmenu = false; static bool msg_grid_invalid = false; -static bool resizing = false; +static bool resizing_autocmd = false; static char *provider_err = NULL; @@ -107,15 +126,17 @@ static char *provider_err = NULL; void conceal_check_cursor_line(void) { bool should_conceal = conceal_cursor_line(curwin); - if (curwin->w_p_cole > 0 && (conceal_cursor_used != should_conceal)) { - redrawWinline(curwin, curwin->w_cursor.lnum); - // Need to recompute cursor column, e.g., when starting Visual mode - // without concealing. - curs_columns(curwin, true); + if (curwin->w_p_cole <= 0 || conceal_cursor_used == should_conceal) { + return; } + + redrawWinline(curwin, curwin->w_cursor.lnum); + // Need to recompute cursor column, e.g., when starting Visual mode + // without concealing. + curs_columns(curwin, true); } -/// Resize the screen to Rows and Columns. +/// Resize default_grid to Rows and Columns. /// /// Allocate default_grid.chars[] and other grid arrays. /// @@ -125,19 +146,20 @@ void conceal_check_cursor_line(void) /// 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 /// needed. -void screenalloc(void) +/// +/// @return whether resizing has been done +bool default_grid_alloc(void) { + static bool resizing = false; + // It's possible that we produce an out-of-memory message below, which // will cause this function to be called again. To break the loop, just // return here. if (resizing) { - return; + return false; } resizing = true; - int retry_count = 0; - -retry: // 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. @@ -148,24 +170,9 @@ retry: || Columns == 0 || (!full_screen && default_grid.chars == NULL)) { resizing = false; - return; - } - - // Note that the window sizes are updated before reallocating the arrays, - // thus we must not redraw here! - RedrawingDisabled++; - - // win_new_screensize will recompute floats position, but tell the - // compositor to not redraw them yet - ui_comp_set_screen_valid(false); - if (msg_grid.chars) { - msg_grid_invalid = true; + return false; } - win_new_screensize(); // fit the windows in the new sized screen - - comp_col(); // recompute columns for shown command and ruler - // We're changing the size of the screen. // - Allocate new arrays for default_grid // - Move lines from the old arrays into the new arrays, clear extra @@ -177,14 +184,10 @@ retry: // size is wrong. grid_alloc(&default_grid, Rows, Columns, true, true); - StlClickDefinition *new_tab_page_click_defs = - xcalloc((size_t)Columns, sizeof(*new_tab_page_click_defs)); stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size); - xfree(tab_page_click_defs); - - tab_page_click_defs = new_tab_page_click_defs; - tab_page_click_defs_size = Columns; + 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; @@ -193,35 +196,20 @@ retry: default_grid.col_offset = 0; default_grid.handle = DEFAULT_GRID_HANDLE; - must_redraw = CLEAR; // need to clear the screen later - - RedrawingDisabled--; - - // Do not apply autocommands more than 3 times to avoid an endless loop - // in case applying autocommands always changes Rows or Columns. - if (starting == 0 && ++retry_count <= 3) { - apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf); - // In rare cases, autocommands may have altered Rows or Columns, - // jump back to check if we need to allocate the screen again. - goto retry; - } - resizing = false; + return true; } void screenclear(void) { check_for_delay(false); - screenalloc(); // allocate screen buffers if size changed - - int i; if (starting == NO_SCREEN || default_grid.chars == NULL) { return; } // blank out the default grid - for (i = 0; i < default_grid.rows; i++) { + for (int i = 0; i < default_grid.rows; i++) { grid_clear_line(&default_grid, default_grid.line_offset[i], default_grid.cols, true); default_grid.line_wraps[i] = false; @@ -235,18 +223,18 @@ void screenclear(void) clear_cmdline = false; mode_displayed = false; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); redraw_cmdline = true; redraw_tabline = true; redraw_popupmenu = true; pum_invalidate(); FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_floating) { - wp->w_redr_type = CLEAR; + wp->w_redr_type = UPD_CLEAR; } } - if (must_redraw == CLEAR) { - must_redraw = NOT_VALID; // no need to clear again + if (must_redraw == UPD_CLEAR) { + must_redraw = UPD_NOT_VALID; // no need to clear again } compute_cmdrow(); msg_row = cmdline_row; // put cursor on last line for messages @@ -281,13 +269,6 @@ void screen_resize(int width, int height) return; } - // curwin->w_buffer can be NULL when we are closing a window and the - // buffer has already been closed and removing a scrollbar causes a resize - // event. Don't resize then, it will happen after entering another buffer. - if (curwin->w_buffer == NULL) { - return; - } - resizing_screen = true; Rows = height; @@ -301,16 +282,42 @@ void screen_resize(int width, int height) width = Columns; p_lines = Rows; p_columns = Columns; + ui_call_grid_resize(1, width, height); - /// The window layout used to be adjusted here, but it now happens in - /// screenalloc() (also invoked from screenclear()). That is because the - /// recursize "resizing_screen" check above may skip this, but not screenalloc(). + int retry_count = 0; + resizing_autocmd = true; + + // In rare cases, autocommands may have altered Rows or Columns, + // so retry to check if we need to allocate the screen again. + while (default_grid_alloc()) { + // win_new_screensize will recompute floats position, but tell the + // compositor to not redraw them yet + ui_comp_set_screen_valid(false); + if (msg_grid.chars) { + msg_grid_invalid = true; + } + + RedrawingDisabled++; + + win_new_screensize(); // fit the windows in the new sized screen + + comp_col(); // recompute columns for shown command and ruler + + RedrawingDisabled--; + + // Do not apply autocommands more than 3 times to avoid an endless loop + // in case applying autocommands always changes Rows or Columns. + if (++retry_count > 3) { + break; + } - if (State != MODE_ASKMORE && State != MODE_EXTERNCMD && State != MODE_CONFIRM) { - screenclear(); + apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf); } + resizing_autocmd = false; + redraw_all_later(UPD_CLEAR); + if (starting != NO_SCREEN) { maketitle(); @@ -320,14 +327,11 @@ void screen_resize(int width, int height) // We only redraw when it's needed: // - While at the more prompt or executing an external command, don't // redraw, but position the cursor. - // - While editing the command line, only redraw that. + // - While editing the command line, only redraw that. TODO: lies // - in Ex mode, don't redraw anything. // - Otherwise, redraw right now, and position the cursor. - // Always need to call update_screen() or screenalloc(), to make - // sure Rows/Columns and the size of the screen is correct! if (State == MODE_ASKMORE || State == MODE_EXTERNCMD || State == MODE_CONFIRM || exmode_active) { - screenalloc(); if (msg_grid.chars) { msg_grid_validate(); } @@ -341,7 +345,7 @@ void screen_resize(int width, int height) } if (State & MODE_CMDLINE) { redraw_popupmenu = false; - update_screen(NOT_VALID); + update_screen(); redrawcmdline(); if (pum_drawn()) { cmdline_pum_display(false); @@ -350,12 +354,12 @@ void screen_resize(int width, int height) update_topline(curwin); if (pum_drawn()) { // TODO(bfredl): ins_compl_show_pum wants to redraw the screen first. - // For now make sure the nested update_screen(0) won't redraw the + // For now make sure the nested update_screen() won't redraw the // pum at the old position. Try to untangle this later. redraw_popupmenu = false; ins_compl_show_pum(); } - update_screen(NOT_VALID); + update_screen(); if (redrawing()) { setcursor(); } @@ -370,9 +374,7 @@ void screen_resize(int width, int height) /// /// Most code shouldn't call this directly, rather use redraw_later() and /// and redraw_all_later() to mark parts of the screen as needing a redraw. -/// -/// @param type set to a NOT_VALID to force redraw of entire screen -int update_screen(int type) +int update_screen(void) { static bool did_intro = false; bool is_stl_global = global_stl_height() > 0; @@ -380,7 +382,7 @@ int update_screen(int type) // Don't do anything if the screen structures are (not yet) valid. // A VimResized autocmd can invoke redrawing in the middle of a resize, // which would bypass the checks in screen_resize for popupmenu etc. - if (!default_grid.chars || resizing) { + if (resizing_autocmd || !default_grid.chars) { return FAIL; } @@ -389,37 +391,25 @@ int update_screen(int type) diff_redraw(true); } - if (must_redraw) { - if (type < must_redraw) { // use maximal type - type = must_redraw; - } - - // must_redraw is reset here, so that when we run into some weird - // reason to redraw while busy redrawing (e.g., asynchronous - // scrolling), or update_topline() in win_update() will cause a - // scroll, or a decoration provider requires a redraw, the screen - // will be redrawn later or in win_update(). - must_redraw = 0; - } - - // Need to update w_lines[]. - if (curwin->w_lines_valid == 0 && type < NOT_VALID) { - type = NOT_VALID; - } - // Postpone the redrawing when it's not needed and when being called // recursively. if (!redrawing() || updating_screen) { - must_redraw = type; - if (type > INVERTED_ALL) { - curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now - } return FAIL; } + + int type = must_redraw; + + // must_redraw is reset here, so that when we run into some weird + // reason to redraw while busy redrawing (e.g., asynchronous + // scrolling), or update_topline() in win_update() will cause a + // scroll, or a decoration provider requires a redraw, the screen + // will be redrawn later or in win_update(). + must_redraw = 0; + updating_screen = 1; - display_tick++; // let syntax code know we're in a next round of - // display updating + display_tick++; // let syntax code know we're in a next round of + // display updating // Tricky: vim code can reset msg_scrolled behind our back, so need // separate bookkeeping for now. @@ -428,7 +418,7 @@ int update_screen(int type) msg_scrolled_at_flush = 0; } - if (type >= CLEAR || !default_grid.valid) { + if (type >= UPD_CLEAR || !default_grid.valid) { ui_comp_set_screen_valid(false); } @@ -443,68 +433,48 @@ int update_screen(int type) msg_grid.cols, false); } } - if (msg_use_msgsep()) { - msg_grid.throttled = false; - // CLEAR is already handled - if (type == NOT_VALID && !ui_has(kUIMultigrid) && msg_scrolled) { - 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); - } - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_floating) { - continue; - } - if (W_ENDROW(wp) > valid) { - wp->w_redr_type = MAX(wp->w_redr_type, NOT_VALID); - } - if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height > valid) { - wp->w_redr_status = true; - } - } - if (is_stl_global && Rows - p_ch - 1 > valid) { - curwin->w_redr_status = true; - } + msg_grid.throttled = false; + bool was_invalidated = false; + + // UPD_CLEAR is already handled + 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); } - msg_grid_set_pos(Rows - (int)p_ch, false); - msg_grid_invalid = false; - } else if (msg_scrolled > Rows - 5) { // clearing is faster - type = CLEAR; - } else if (type != CLEAR) { - check_for_delay(false); - grid_ins_lines(&default_grid, 0, msg_scrolled, Rows, 0, Columns); FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_floating) { continue; } - if (wp->w_winrow < msg_scrolled) { - if (W_ENDROW(wp) > msg_scrolled - && wp->w_redr_type < REDRAW_TOP - && wp->w_lines_valid > 0 - && wp->w_topline == wp->w_lines[0].wl_lnum) { - wp->w_upd_rows = msg_scrolled - wp->w_winrow; - wp->w_redr_type = REDRAW_TOP; - } else { - wp->w_redr_type = NOT_VALID; - if (wp->w_winrow + wp->w_winbar_height <= msg_scrolled) { - wp->w_redr_status = true; - } - } + if (W_ENDROW(wp) > valid) { + // TODO(bfredl): too pessimistic. type could be UPD_NOT_VALID + // only because windows that are above the separator. + wp->w_redr_type = MAX(wp->w_redr_type, UPD_NOT_VALID); + } + if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height > valid) { + wp->w_redr_status = true; } } - if (is_stl_global && Rows - p_ch - 1 <= msg_scrolled) { + if (is_stl_global && Rows - p_ch - 1 > valid) { curwin->w_redr_status = true; } - redraw_cmdline = true; - redraw_tabline = true; + } + msg_grid_set_pos(Rows - (int)p_ch, false); + msg_grid_invalid = false; + if (was_invalidated) { + // screen was only invalid for the msgarea part. + // @TODO(bfredl): using the same "valid" flag + // for both messages and floats moving is bit of a mess. + ui_comp_set_screen_valid(true); } msg_scrolled = 0; msg_scrolled_at_flush = 0; + msg_grid_scroll_discount = 0; need_wait_return = false; } - win_ui_flush(); + win_ui_flush(true); msg_ext_check_clear(); // reset cmdline_row now (may have been changed temporarily) @@ -517,10 +487,11 @@ int update_screen(int type) hl_changed = true; } - if (type == CLEAR) { // first clear screen - screenclear(); // will reset clear_cmdline + 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 = NOT_VALID; + type = UPD_NOT_VALID; // must_redraw may be set indirectly, avoid another redraw later must_redraw = 0; } else if (!default_grid.valid) { @@ -528,16 +499,15 @@ int update_screen(int type) default_grid.valid = true; } - // After disabling msgsep the grid might not have been deallocated yet, - // hence we also need to check msg_grid.chars - if (type == NOT_VALID && (msg_use_grid() || msg_grid.chars)) { + // 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); } ui_comp_set_screen_valid(true); DecorProviders providers; - decor_providers_start(&providers, type, &provider_err); + decor_providers_start(&providers, &provider_err); // "start" callback could have changed highlights for global elements if (win_check_ns_hl(NULL)) { @@ -551,37 +521,20 @@ int update_screen(int type) // Force redraw when width of 'number' or 'relativenumber' column // changes. - if (curwin->w_redr_type < NOT_VALID - && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu) + // 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_redr_type = NOT_VALID; - } - - // Only start redrawing if there is really something to do. - if (type == INVERTED) { - update_curswant(); - } - if (curwin->w_redr_type < type - && !((type == VALID - && curwin->w_lines[0].wl_valid - && curwin->w_topfill == curwin->w_old_topfill - && curwin->w_botfill == curwin->w_old_botfill - && curwin->w_topline == curwin->w_lines[0].wl_lnum) - || (type == INVERTED - && VIsual_active - && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum - && curwin->w_old_visual_mode == VIsual_mode - && (curwin->w_valid & VALID_VIRTCOL) - && curwin->w_old_curswant == curwin->w_curswant))) { - curwin->w_redr_type = type; + curwin->w_redr_type = UPD_NOT_VALID; } // Redraw the tab pages line if needed. - if (redraw_tabline || type >= NOT_VALID) { - update_window_hl(curwin, type >= NOT_VALID); + if (redraw_tabline || type >= UPD_NOT_VALID) { + update_window_hl(curwin, type >= UPD_NOT_VALID); FOR_ALL_TABS(tp) { if (tp != curtab) { - update_window_hl(tp->tp_curwin, type >= NOT_VALID); + update_window_hl(tp->tp_curwin, type >= UPD_NOT_VALID); } } draw_tabline(); @@ -590,7 +543,7 @@ int update_screen(int type) // Correct stored syntax highlighting info for changes in each displayed // buffer. Each buffer must only be done once. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - update_window_hl(wp, type >= NOT_VALID || hl_changed); + update_window_hl(wp, type >= UPD_NOT_VALID || hl_changed); buf_T *buf = wp->w_buffer; if (buf->b_mod_set) { @@ -612,9 +565,9 @@ int update_screen(int type) screen_search_hl.rm.regprog = NULL; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_redr_type == CLEAR && wp->w_floating && wp->w_grid_alloc.chars) { + if (wp->w_redr_type == UPD_CLEAR && wp->w_floating && wp->w_grid_alloc.chars) { grid_invalidate(&wp->w_grid_alloc); - wp->w_redr_type = NOT_VALID; + wp->w_redr_type = UPD_NOT_VALID; } win_check_ns_hl(wp); @@ -622,7 +575,7 @@ int update_screen(int type) // reallocate grid if needed. win_grid_alloc(wp); - if (wp->w_redr_border || wp->w_redr_type >= NOT_VALID) { + if (wp->w_redr_border || wp->w_redr_type >= UPD_NOT_VALID) { win_redr_border(wp); } @@ -679,6 +632,20 @@ int update_screen(int type) return OK; } +static void win_border_redr_title(win_T *wp, ScreenGrid *grid, int col) +{ + VirtText title_chunks = wp->w_float_config.title_chunks; + + for (size_t i = 0; i < title_chunks.size; i++) { + char *text = title_chunks.items[i].text; + int cell = (int)mb_string2cells(text); + int hl_id = title_chunks.items[i].hl_id; + int attr = hl_id ? syn_id2attr(hl_id) : 0; + grid_puts(grid, text, 0, col, attr); + col += cell; + } +} + static void win_redr_border(win_T *wp) { wp->w_redr_border = false; @@ -699,9 +666,24 @@ static void win_redr_border(win_T *wp) if (adj[3]) { grid_put_schar(grid, 0, 0, chars[0], attrs[0]); } + for (int i = 0; i < icol; i++) { grid_put_schar(grid, 0, i + adj[3], chars[1], attrs[1]); } + + if (wp->w_float_config.title) { + int title_col = 0; + int title_width = wp->w_float_config.title_width; + AlignTextPos title_pos = wp->w_float_config.title_pos; + + if (title_pos == kAlignCenter) { + title_col = (icol - title_width) / 2 + 1; + } else { + title_col = title_pos == kAlignLeft ? 1 : icol - title_width + 1; + } + + win_border_redr_title(wp, grid, title_col); + } if (adj[1]) { grid_put_schar(grid, 0, icol + adj[3], chars[2], attrs[2]); } @@ -746,6 +728,8 @@ void show_cursor_info(bool always) if (!always && !redrawing()) { return; } + + win_check_ns_hl(curwin); if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && (curwin->w_status_height || global_stl_height())) { redraw_custom_statusline(curwin); @@ -762,6 +746,7 @@ void show_cursor_info(bool always) maketitle(); } + win_check_ns_hl(NULL); // Redraw the tab pages line if needed. if (redraw_tabline) { draw_tabline(); @@ -854,29 +839,29 @@ static bool vsep_connected(win_T *wp, WindowCorner corner) /// Draw the vertical separator right of window "wp" static void draw_vsep_win(win_T *wp) { - int hl; - int c; - - if (wp->w_vsep_width) { - // draw the vertical separator right of this window - c = fillchar_vsep(wp, &hl); - grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp), - W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl); + if (!wp->w_vsep_width) { + return; } + + // draw the vertical separator right of this window + int hl; + int c = fillchar_vsep(wp, &hl); + grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp), + W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl); } /// Draw the horizontal separator below window "wp" static void draw_hsep_win(win_T *wp) { - int hl; - int c; - - if (wp->w_hsep_height) { - // draw the horizontal separator below this window - c = fillchar_hsep(wp, &hl); - grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1, - wp->w_wincol, W_ENDCOL(wp), c, c, hl); + if (!wp->w_hsep_height) { + return; } + + // draw the horizontal separator below this window + int hl; + int c = fillchar_hsep(wp, &hl); + grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1, + wp->w_wincol, W_ENDCOL(wp), c, c, hl); } /// Get the separator connector for specified window corner of window "wp" @@ -957,31 +942,26 @@ static void draw_sep_connectors_win(win_T *wp) /// /// How the window is redrawn depends on wp->w_redr_type. Each type also /// implies the one below it. -/// NOT_VALID redraw the whole window -/// SOME_VALID redraw the whole window but do scroll when possible -/// REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID -/// INVERTED redraw the changed part of the Visual area -/// INVERTED_ALL redraw the whole Visual area -/// VALID 1. scroll up/down to adjust for a changed w_topline -/// 2. update lines at the top when scrolled down -/// 3. redraw changed text: -/// - 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. -/// - continue redrawing when syntax status is invalid. -/// 4. if scrolled up, update lines at the bottom. +/// UPD_NOT_VALID redraw the whole window +/// UPD_SOME_VALID redraw the whole window but do scroll when possible +/// UPD_REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like UPD_VALID +/// UPD_INVERTED redraw the changed part of the Visual area +/// UPD_INVERTED_ALL redraw the whole Visual area +/// UPD_VALID 1. scroll up/down to adjust for a changed w_topline +/// 2. update lines at the top when scrolled down +/// 3. redraw changed text: +/// - 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. +/// - 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) { - bool called_decor_providers = false; -win_update_start: - ; - buf_T *buf = wp->w_buffer; - int type; 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 @@ -993,31 +973,28 @@ win_update_start: 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 row; // current window row to display - linenr_T lnum; // current buffer lnum to display - int idx; // current index in w_lines[] - int srow; // starting row of the current line + int bot_scroll_start = 999; // first line that needs to be redrawn due to + // scrolling. only used for EOB - bool eof = false; // if true, we hit the end of the file - bool didline = false; // if true, we finished the last line - int i; - long j; static bool recursive = false; // being called recursively - const linenr_T old_botline = wp->w_botline; + // Remember what happened to the previous line. -#define DID_NONE 1 // didn't update a line -#define DID_LINE 2 // updated a normal line -#define DID_FOLD 3 // updated a folded line - int did_update = DID_NONE; + enum { + 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; + linenr_T syntax_last_parsed = 0; // last parsed text line linenr_T mod_top = 0; linenr_T mod_bot = 0; - int save_got_int; - type = wp->w_redr_type; + int type = wp->w_redr_type; - if (type >= NOT_VALID) { + if (type >= UPD_NOT_VALID) { + // TODO(bfredl): should only be implied for CLEAR, not NOT_VALID! wp->w_redr_status = true; + wp->w_lines_valid = 0; } @@ -1039,16 +1016,32 @@ win_update_start: return; } + buf_T *buf = wp->w_buffer; + + // reset got_int, otherwise regexp won't work + int save_got_int = got_int; + got_int = 0; + // Set the time limit to 'redrawtime'. + proftime_T syntax_tm = profile_setlimit(p_rdt); + syn_set_timeout(&syntax_tm); + + win_extmark_arr.size = 0; + + decor_redraw_reset(buf, &decor_state); + + DecorProviders line_providers; + decor_providers_invoke_win(wp, providers, &line_providers, &provider_err); + redraw_win_signcol(wp); init_search_hl(wp, &screen_search_hl); // Force redraw when width of 'number' or 'relativenumber' column // changes. - i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0; - if (wp->w_nrwidth != i) { - type = NOT_VALID; - wp->w_nrwidth = i; + int nrwidth = (wp->w_p_nu || wp->w_p_rnu || *wp->w_p_stc) ? number_width(wp) : 0; + if (wp->w_nrwidth != nrwidth) { + type = UPD_NOT_VALID; + wp->w_nrwidth = nrwidth; if (buf->terminal) { terminal_check_size(buf->terminal); @@ -1059,7 +1052,7 @@ win_update_start: // 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 = NOT_VALID; + 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. @@ -1096,12 +1089,12 @@ win_update_start: } else { const matchitem_T *cur = wp->w_match_head; while (cur != NULL) { - if (cur->match.regprog != NULL - && re_multiline(cur->match.regprog)) { + if (cur->mit_match.regprog != NULL + && re_multiline(cur->mit_match.regprog)) { top_to_mod = true; break; } - cur = cur->next; + cur = cur->mit_next; } } } @@ -1120,7 +1113,7 @@ win_update_start: // to this line. If there is no valid entry, use MAXLNUM. lnumt = wp->w_topline; lnumb = MAXLNUM; - for (i = 0; i < wp->w_lines_valid; i++) { + for (int i = 0; i < wp->w_lines_valid; i++) { if (wp->w_lines[i].wl_valid) { if (wp->w_lines[i].wl_lastlnum < mod_top) { lnumt = wp->w_lines[i].wl_lastlnum + 1; @@ -1168,14 +1161,15 @@ win_update_start: mod_bot = MAXLNUM; } } + wp->w_redraw_top = 0; // reset for next time wp->w_redraw_bot = 0; // When only displaying the lines at the top, set top_end. Used when // window has scrolled down for msg_scrolled. - if (type == REDRAW_TOP) { - j = 0; - for (i = 0; i < wp->w_lines_valid; i++) { + if (type == UPD_REDRAW_TOP) { + long j = 0; + for (int i = 0; i < wp->w_lines_valid; i++) { j += wp->w_lines[i].wl_size; if (j >= wp->w_upd_rows) { top_end = (int)j; @@ -1184,10 +1178,10 @@ win_update_start: } if (top_end == 0) { // not found (cannot happen?): redraw everything - type = NOT_VALID; + type = UPD_NOT_VALID; } else { - // top area defined, the rest is VALID - type = VALID; + // top area defined, the rest is UPD_VALID + type = UPD_VALID; } } @@ -1197,8 +1191,8 @@ win_update_start: // 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 == VALID || type == SOME_VALID - || type == INVERTED || type == 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 @@ -1211,6 +1205,7 @@ win_update_start: || (wp->w_topline == wp->w_lines[0].wl_lnum && wp->w_topfill > wp->w_old_topfill))) { // New topline is above old topline: May scroll down. + long j; if (hasAnyFolding(wp)) { linenr_T ln; @@ -1228,7 +1223,7 @@ win_update_start: j = wp->w_lines[0].wl_lnum - wp->w_topline; } if (j < wp->w_grid.rows - 2) { // not too far off - i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1); + int i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1); // insert extra lines for previously invisible filler lines if (wp->w_lines[0].wl_lnum != wp->w_topline) { i += win_get_fill(wp, wp->w_lines[0].wl_lnum) - wp->w_old_topfill; @@ -1238,6 +1233,7 @@ win_update_start: // If not the last window, delete the lines at the bottom. // win_ins_lines may fail when the terminal can't do it. win_scroll_lines(wp, 0, i); + bot_scroll_start = 0; if (wp->w_lines_valid != 0) { // Need to update rows that are new, stop at the // first one that scrolled down. @@ -1249,6 +1245,7 @@ win_update_start: if ((wp->w_lines_valid += (linenr_T)j) > wp->w_grid.rows) { wp->w_lines_valid = wp->w_grid.rows; } + int idx; for (idx = wp->w_lines_valid; idx - j >= 0; idx--) { wp->w_lines[idx] = wp->w_lines[idx - j]; } @@ -1268,9 +1265,9 @@ win_update_start: // needs updating. // try to find wp->w_topline in wp->w_lines[].wl_lnum - j = -1; - row = 0; - for (i = 0; i < wp->w_lines_valid; i++) { + long 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) { j = i; @@ -1298,6 +1295,7 @@ win_update_start: if (row > 0) { win_scroll_lines(wp, 0, -row); bot_start = wp->w_grid.rows - row; + bot_scroll_start = bot_start; } if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) { // Skip the lines (below the deleted lines) that are still @@ -1305,7 +1303,7 @@ win_update_start: // upwards, to compensate for the deleted lines. Set // bot_start to the first row that needs redrawing. bot_start = 0; - idx = 0; + int idx = 0; for (;;) { wp->w_lines[idx] = wp->w_lines[j]; // stop at line that didn't fit, unless it is still @@ -1339,25 +1337,25 @@ win_update_start: mid_end = wp->w_grid.rows; } } else { - // Not VALID or INVERTED: redraw all lines. + // Not UPD_VALID or UPD_INVERTED: redraw all lines. mid_start = 0; mid_end = wp->w_grid.rows; } - if (type == SOME_VALID) { - // SOME_VALID: redraw all lines. + if (type == UPD_SOME_VALID) { + // UPD_SOME_VALID: redraw all lines. mid_start = 0; mid_end = wp->w_grid.rows; - type = NOT_VALID; + type = UPD_NOT_VALID; } // check if we are updating or removing the inverted part if ((VIsual_active && buf == curwin->w_buffer) - || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID)) { + || (wp->w_old_cursor_lnum != 0 && type != UPD_NOT_VALID)) { linenr_T from, to; if (VIsual_active) { - if (VIsual_mode != wp->w_old_visual_mode || type == INVERTED_ALL) { + if (VIsual_mode != wp->w_old_visual_mode || type == UPD_INVERTED_ALL) { // If the type of Visual selection changed, redraw the whole // selection. Also when the ownership of the X selection is // gained or lost. @@ -1443,7 +1441,7 @@ win_update_start: pos.lnum += cursor_above ? 1 : -1) { colnr_T t; - pos.col = (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, pos.lnum, false)); + pos.col = (colnr_T)strlen(ml_get_buf(wp->w_buffer, pos.lnum, false)); getvvcol(wp, &pos, NULL, NULL, &t); if (toc < t) { toc = t; @@ -1502,9 +1500,9 @@ win_update_start: // above the Visual area and reset wl_valid, do count these for // mid_end (in srow). if (mid_start > 0) { - lnum = wp->w_topline; - idx = 0; - srow = 0; + linenr_T lnum = wp->w_topline; + int idx = 0; + int srow = 0; if (scrolled_down) { mid_start = top_end; } else { @@ -1550,38 +1548,18 @@ win_update_start: wp->w_old_visual_col = 0; } - // reset got_int, otherwise regexp won't work - save_got_int = got_int; - got_int = 0; - // Set the time limit to 'redrawtime'. - proftime_T syntax_tm = profile_setlimit(p_rdt); - syn_set_timeout(&syntax_tm); - - // Update all the window rows. - idx = 0; // first entry in w_lines[].wl_size - row = 0; - srow = 0; - lnum = wp->w_topline; // first line shown in window - - win_extmark_arr.size = 0; - - decor_redraw_reset(buf, &decor_state); - - DecorProviders line_providers; - decor_providers_invoke_win(wp, providers, &line_providers, &provider_err); - (void)win_signcol_count(wp); // check if provider changed signcol width - if (must_redraw != 0) { - must_redraw = 0; - if (!called_decor_providers) { - called_decor_providers = true; - goto win_update_start; - } - } - bool cursorline_standout = win_cursorline_standout(wp); win_check_ns_hl(wp); + // 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 + linenr_T lnum = wp->w_topline; // first line shown in window + + bool eof = false; // if true, we hit the end of the file + bool didline = false; // if true, we finished the last line for (;;) { // stop updating when reached the end of the window (check for _past_ // the end of the window is at the end of the loop) @@ -1645,6 +1623,7 @@ win_update_start: int new_rows = 0; int xtra_rows; linenr_T l; + int i; // Count the old number of window rows, using w_lines[], which // should still contain the sizes for the lines as they are @@ -1675,10 +1654,11 @@ win_update_start: // need to redraw until the end of the window. // Inserting/deleting lines has no use. bot_start = 0; + bot_scroll_start = 0; } else { // Able to count old number of rows: Count new window // rows, and may insert/delete lines - j = idx; + long j = idx; for (l = lnum; l < mod_bot; l++) { if (hasFoldingWin(wp, l, NULL, &l, true, NULL)) { new_rows++; @@ -1705,6 +1685,7 @@ win_update_start: } else { win_scroll_lines(wp, row, xtra_rows); bot_start = wp->w_grid.rows + xtra_rows; + bot_scroll_start = bot_start; } } else if (xtra_rows > 0) { // May scroll text down. If there is not enough @@ -1714,6 +1695,7 @@ win_update_start: mod_bot = MAXLNUM; } else { win_scroll_lines(wp, row + old_rows, xtra_rows); + bot_scroll_start = 0; if (top_end > row + old_rows) { // Scrolled the part at the top that requires // updating down. @@ -1792,7 +1774,7 @@ win_update_start: // Let the syntax stuff know we skipped a few lines. if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum && syntax_present(wp)) { - syntax_end_parsing(syntax_last_parsed + 1); + syntax_end_parsing(wp, syntax_last_parsed + 1); } // Display one line @@ -1847,6 +1829,18 @@ win_update_start: did_update = DID_NONE; } + // 'statuscolumn' width has changed or errored, start from the top. + if (wp->w_redr_statuscol) { + wp->w_redr_statuscol = false; + idx = 0; + row = 0; + lnum = wp->w_topline; + wp->w_lines_valid = 0; + wp->w_valid &= ~VALID_WCOL; + decor_providers_invoke_win(wp, providers, &line_providers, &provider_err); + continue; + } + if (lnum > buf->b_ml.ml_line_count) { eof = true; break; @@ -1866,9 +1860,11 @@ win_update_start: // Let the syntax stuff know we stop parsing here. if (syntax_last_parsed != 0 && syntax_present(wp)) { - syntax_end_parsing(syntax_last_parsed + 1); + syntax_end_parsing(wp, syntax_last_parsed + 1); } + const linenr_T old_botline = wp->w_botline; + // If we didn't hit the end of the file, and we didn't finish the last // line we were working on, then the line didn't fit. wp->w_empty_rows = 0; @@ -1885,34 +1881,38 @@ win_update_start: wp->w_filler_rows = wp->w_grid.rows - srow; } else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate" int scr_row = wp->w_grid.rows - 1; + int symbol = wp->w_p_fcs_chars.lastline; + char fillbuf[12]; // 2 characters of 6 bytes + int charlen = utf_char2bytes(symbol, &fillbuf[0]); + utf_char2bytes(symbol, &fillbuf[charlen]); // Last line isn't finished: Display "@@@" in the last screen line. - grid_puts_len(&wp->w_grid, (char_u *)"@@", MIN(wp->w_grid.cols, 2), scr_row, 0, at_attr); - - grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.cols, - '@', ' ', at_attr); + grid_puts_len(&wp->w_grid, fillbuf, MIN(wp->w_grid.cols, 2) * charlen, scr_row, 0, at_attr); + grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.cols, symbol, ' ', at_attr); set_empty_rows(wp, srow); wp->w_botline = lnum; } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" int start_col = wp->w_grid.cols - 3; + int symbol = wp->w_p_fcs_chars.lastline; // Last line isn't finished: Display "@@@" at the end. grid_fill(&wp->w_grid, wp->w_grid.rows - 1, wp->w_grid.rows, - MAX(start_col, 0), wp->w_grid.cols, '@', '@', at_attr); + MAX(start_col, 0), wp->w_grid.cols, symbol, symbol, at_attr); set_empty_rows(wp, srow); wp->w_botline = lnum; } else { - win_draw_end(wp, '@', ' ', 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; } } else { if (eof) { // we hit the end of the file wp->w_botline = buf->b_ml.ml_line_count + 1; - j = win_get_fill(wp, wp->w_botline); + long j = win_get_fill(wp, wp->w_botline); if (j > 0 && !wp->w_botfill && row < wp->w_grid.rows) { // Display filler text below last line. win_line() will check // for ml_line_count+1 and only draw filler lines - foldinfo_T info = FOLDINFO_INIT; + foldinfo_T info = { 0 }; row = win_line(wp, wp->w_botline, row, wp->w_grid.rows, false, false, info, &line_providers, &provider_err); } @@ -1920,15 +1920,27 @@ win_update_start: wp->w_botline = lnum; } - // make sure the rest of the screen is blank - // write the 'eob' character to rows that aren't part of the file. - win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.rows, + // Make sure the rest of the screen is blank. + // write the "eob" character from 'fillchars' to rows that aren't part + // of the file. + // TODO(bfredl): just keep track of the valid EOB area from last redraw? + int lastline = bot_scroll_start; + if (mid_end >= row) { + lastline = MIN(lastline, mid_start); + } + // if (mod_bot > buf->b_ml.ml_line_count + 1) { + if (mod_bot > buf->b_ml.ml_line_count) { + lastline = 0; + } + + 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 >= REDRAW_TOP) { + if (wp->w_redr_type >= UPD_REDRAW_TOP) { draw_vsep_win(wp); draw_hsep_win(wp); draw_sep_connectors_win(wp); @@ -1966,11 +1978,11 @@ win_update_start: update_topline(curwin); // may invalidate w_botline again if (must_redraw != 0) { // Don't update for changes in buffer again. - i = curbuf->b_mod_set; + int mod_set = curbuf->b_mod_set; curbuf->b_mod_set = false; win_update(curwin, providers); must_redraw = 0; - curbuf->b_mod_set = i; + curbuf->b_mod_set = mod_set; } recursive = false; } @@ -1982,16 +1994,16 @@ win_update_start: } } -/// Redraw a window later, with update_screen(type). +/// Redraw a window later, with wp->w_redr_type >= type. /// /// Set must_redraw only if not already set to a higher value. -/// e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. +/// 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) { wp->w_redr_type = type; - if (type >= NOT_VALID) { + if (type >= UPD_NOT_VALID) { wp->w_lines_valid = 0; } if (must_redraw < type) { // must_redraw is the maximum of all windows @@ -2015,7 +2027,7 @@ void redraw_all_later(int type) void screen_invalidate_highlights(void) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); wp->w_grid_alloc.valid = false; } } @@ -2035,12 +2047,14 @@ void redraw_buf_later(buf_T *buf, int type) } } -void redraw_buf_line_later(buf_T *buf, linenr_T line) +void redraw_buf_line_later(buf_T *buf, linenr_T line, bool force) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == buf - && line >= wp->w_topline && line < wp->w_botline) { - redrawWinline(wp, line); + if (wp->w_buffer == buf) { + redrawWinline(wp, MIN(line, buf->b_ml.ml_line_count)); + if (force && line > buf->b_ml.ml_line_count) { + wp->w_redraw_bot = line; + } } } } @@ -2056,7 +2070,7 @@ void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline) if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lastline) { wp->w_redraw_bot = lastline; } - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } } @@ -2070,8 +2084,8 @@ void redraw_buf_status_later(buf_T *buf) || (wp == curwin && global_stl_height()) || wp->w_winbar_height)) { wp->w_redr_status = true; - if (must_redraw < VALID) { - must_redraw = VALID; + if (must_redraw < UPD_VALID) { + must_redraw = UPD_VALID; } } } @@ -2086,7 +2100,7 @@ void status_redraw_all(void) if ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin) || wp->w_winbar_height) { wp->w_redr_status = true; - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } } @@ -2106,7 +2120,7 @@ void status_redraw_buf(buf_T *buf) 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, VALID); + redraw_later(wp, UPD_VALID); } } } @@ -2116,10 +2130,13 @@ void redraw_statuslines(void) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_redr_status) { + win_check_ns_hl(wp); win_redr_winbar(wp); win_redr_status(wp); } } + + win_check_ns_hl(NULL); if (redraw_tabline) { draw_tabline(); } @@ -2162,6 +2179,6 @@ void redrawWinline(win_T *wp, linenr_T lnum) if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) { wp->w_redraw_bot = lnum; } - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } |