aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/drawscreen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/drawscreen.c')
-rw-r--r--src/nvim/drawscreen.c689
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);
}
}