aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/screen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/screen.c')
-rw-r--r--src/nvim/screen.c2910
1 files changed, 944 insertions, 1966 deletions
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 3c91d764bf..e99f9b9153 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -67,6 +67,7 @@
#include "nvim/api/extmark.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/ui.h"
#include "nvim/api/vim.h"
#include "nvim/arabic.h"
#include "nvim/ascii.h"
@@ -75,6 +76,7 @@
#include "nvim/cursor.h"
#include "nvim/cursor_shape.h"
#include "nvim/decoration.h"
+#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
@@ -86,13 +88,16 @@
#include "nvim/fold.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
#include "nvim/mark.h"
+#include "nvim/match.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
@@ -126,21 +131,8 @@
#define MB_FILLER_CHAR '<' /* character used when a double-width character
* doesn't fit. */
-typedef kvec_withinit_t(DecorProvider *, 4) Providers;
-
-// temporary buffer for rendering a single screenline, so it can be
-// compared with previous contents to calculate smallest delta.
-// Per-cell attributes
-static size_t linebuf_size = 0;
-static schar_T *linebuf_char = NULL;
-static sattr_T *linebuf_attr = NULL;
-
static match_T search_hl; // used for 'hlsearch' highlight matching
-StlClickDefinition *tab_page_click_defs = NULL;
-
-long tab_page_click_defs_size = 0;
-
// for line_putchar. Contains the state that needs to be remembered from
// putting one character to the next.
typedef struct {
@@ -160,44 +152,20 @@ static bool msg_grid_invalid = false;
static bool resizing = false;
+typedef struct {
+ NS ns_id;
+ uint64_t mark_id;
+ int win_row;
+ int win_col;
+} WinExtmark;
+static kvec_t(WinExtmark) win_extmark_arr INIT(= KV_INITIAL_VALUE);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.c.generated.h"
#endif
-#define SEARCH_HL_PRIORITY 0
static char *provider_err = NULL;
-static bool provider_invoke(NS ns_id, const char *name, LuaRef ref, Array args, bool default_true)
-{
- Error err = ERROR_INIT;
-
- textlock++;
- provider_active = true;
- Object ret = nlua_call_ref(ref, name, args, true, &err);
- provider_active = false;
- textlock--;
-
- if (!ERROR_SET(&err)
- && api_object_to_bool(ret, "provider %s retval", default_true, &err)) {
- return true;
- }
-
- if (ERROR_SET(&err)) {
- const char *ns_name = describe_ns(ns_id);
- ELOG("error in provider %s:%s: %s", ns_name, name, err.msg);
- bool verbose_errs = true; // TODO(bfredl):
- if (verbose_errs && provider_err == NULL) {
- static char errbuf[IOSIZE];
- snprintf(errbuf, sizeof errbuf, "%s: %s", ns_name, err.msg);
- provider_err = xstrdup(errbuf);
- }
- }
-
- api_free_object(ret);
- return false;
-}
-
/// Redraw a window later, with update_screen(type).
///
/// Set must_redraw only if not already set to a higher value.
@@ -304,20 +272,12 @@ void redrawWinline(win_T *wp, linenr_T lnum)
}
}
-/*
- * update all windows that are editing the current buffer
- */
-void update_curbuf(int type)
-{
- redraw_curbuf_later(type);
- update_screen(type);
-}
-
/// called when the status bars for the buffer 'buf' need to be updated
void redraw_buf_status_later(buf_T *buf)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_buffer == buf && wp->w_status_height) {
+ if (wp->w_buffer == buf && (wp->w_status_height || (wp == curwin && global_stl_height())
+ || wp->w_winbar_height)) {
wp->w_redr_status = true;
if (must_redraw < VALID) {
must_redraw = VALID;
@@ -326,6 +286,25 @@ void redraw_buf_status_later(buf_T *buf)
}
}
+void redraw_win_signcol(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);
+ }
+}
+
+/// Update all windows that are editing the current buffer.
+void update_curbuf(int type)
+{
+ redraw_curbuf_later(type);
+ update_screen(type);
+}
+
/// Redraw the parts of the screen that is marked for redraw.
///
/// Most code shouldn't call this directly, rather use redraw_later() and
@@ -335,6 +314,7 @@ void redraw_buf_status_later(buf_T *buf)
int update_screen(int type)
{
static bool did_intro = false;
+ bool is_stl_global = global_stl_height() > 0;
// Don't do anything if the screen structures are (not yet) valid.
// A VimResized autocmd can invoke redrawing in the middle of a resize,
@@ -353,10 +333,11 @@ int update_screen(int 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, the screen will be redrawn later or in win_update(). */
+ // 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;
}
@@ -396,9 +377,9 @@ int update_screen(int type)
int valid = MAX(Rows - msg_scrollsize(), 0);
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++) {
+ for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) {
grid_clear_line(&msg_grid, msg_grid.line_offset[i],
- msg_grid.Columns, false);
+ msg_grid.cols, false);
}
}
if (msg_use_msgsep()) {
@@ -406,7 +387,7 @@ int update_screen(int type)
// 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++) {
+ for (int i = valid; i < Rows - p_ch; i++) {
grid_clear_line(&default_grid, default_grid.line_offset[i],
Columns, false);
}
@@ -417,12 +398,15 @@ int update_screen(int type)
if (W_ENDROW(wp) > valid) {
wp->w_redr_type = MAX(wp->w_redr_type, NOT_VALID);
}
- if (W_ENDROW(wp) + wp->w_status_height > 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_set_pos(Rows-p_ch, false);
+ msg_grid_set_pos(Rows - p_ch, false);
msg_grid_invalid = false;
} else if (msg_scrolled > Rows - 5) { // clearing is faster
type = CLEAR;
@@ -442,13 +426,15 @@ int update_screen(int type)
wp->w_redr_type = REDRAW_TOP;
} else {
wp->w_redr_type = NOT_VALID;
- if (W_ENDROW(wp) + wp->w_status_height
- <= msg_scrolled) {
- wp->w_redr_status = TRUE;
+ if (wp->w_winrow + wp->w_winbar_height <= msg_scrolled) {
+ wp->w_redr_status = true;
}
}
}
}
+ if (is_stl_global && Rows - p_ch - 1 <= msg_scrolled) {
+ curwin->w_redr_status = true;
+ }
redraw_cmdline = true;
redraw_tabline = true;
}
@@ -484,33 +470,13 @@ int update_screen(int type)
// 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)) {
- grid_fill(&default_grid, Rows-p_ch, Rows, 0, Columns, ' ', ' ', 0);
+ grid_fill(&default_grid, Rows - p_ch, Rows, 0, Columns, ' ', ' ', 0);
}
ui_comp_set_screen_valid(true);
- Providers providers;
- kvi_init(providers);
- for (size_t i = 0; i < kv_size(decor_providers); i++) {
- DecorProvider *p = &kv_A(decor_providers, i);
- if (!p->active) {
- continue;
- }
-
- bool active;
- if (p->redraw_start != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 2);
- args.items[0] = INTEGER_OBJ(display_tick);
- args.items[1] = INTEGER_OBJ(type);
- active = provider_invoke(p->ns_id, "start", p->redraw_start, args, true);
- } else {
- active = true;
- }
-
- if (active) {
- kvi_push(providers, p);
- }
- }
+ DecorProviders providers;
+ decor_providers_start(&providers, type, &provider_err);
// "start" callback could have changed highlights for global elements
if (win_check_ns_hl(NULL)) {
@@ -579,14 +545,7 @@ int update_screen(int type)
}
if (buf->b_mod_tick_decor < display_tick) {
- for (size_t i = 0; i < kv_size(providers); i++) {
- DecorProvider *p = kv_A(providers, i);
- if (p && p->redraw_buf != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 1);
- args.items[0] = BUFFER_OBJ(buf->handle);
- provider_invoke(p->ns_id, "buf", p->redraw_buf, args, true);
- }
- }
+ decor_providers_invoke_buf(buf, &providers, &provider_err);
buf->b_mod_tick_decor = display_tick;
}
}
@@ -599,7 +558,6 @@ int update_screen(int type)
bool did_one = false;
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) {
grid_invalidate(&wp->w_grid_alloc);
@@ -621,8 +579,9 @@ int update_screen(int type)
win_update(wp, &providers);
}
- // redraw status line after the window to minimize cursor movement
+ // redraw status line and window bar after the window to minimize cursor movement
if (wp->w_redr_status) {
+ win_redr_winbar(wp);
win_redr_status(wp);
}
}
@@ -634,8 +593,6 @@ int update_screen(int type)
pum_redraw();
}
- send_grid_resize = false;
-
/* Reset b_mod_set 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) {
@@ -656,21 +613,9 @@ int update_screen(int type)
}
did_intro = true;
- for (size_t i = 0; i < kv_size(providers); i++) {
- DecorProvider *p = kv_A(providers, i);
- if (!p->active) {
- continue;
- }
-
- if (p->redraw_end != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 1);
- args.items[0] = INTEGER_OBJ(display_tick);
- provider_invoke(p->ns_id, "end", p->redraw_end, args, true);
- }
- }
+ decor_providers_invoke_end(&providers, &provider_err);
kvi_destroy(providers);
-
// either cmdline is cleared, not drawn or mode is last drawn
cmdline_was_last_drawn = false;
return OK;
@@ -686,18 +631,18 @@ bool conceal_cursor_line(const win_T *wp)
if (*wp->w_p_cocu == NUL) {
return false;
}
- if (get_real_state() & VISUAL) {
+ if (get_real_state() & MODE_VISUAL) {
c = 'v';
- } else if (State & INSERT) {
+ } else if (State & MODE_INSERT) {
c = 'i';
- } else if (State & NORMAL) {
+ } else if (State & MODE_NORMAL) {
c = 'n';
- } else if (State & CMDLINE) {
+ } else if (State & MODE_CMDLINE) {
c = 'c';
} else {
return false;
}
- return vim_strchr(wp->w_p_cocu, c) != NULL;
+ return vim_strchr((char *)wp->w_p_cocu, c) != NULL;
}
// Check if the cursor line needs to be redrawn because of 'concealcursor'.
@@ -716,15 +661,11 @@ void conceal_check_cursor_line(void)
/// 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.
-/// TODO(bfredl): VIsual_active shouldn't be needed, but is used to fix a glitch
-/// caused by scrolling.
+/// 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
{
- return wp->w_p_cul
- || (wp->w_p_cole > 0 && (VIsual_active || !conceal_cursor_line(wp)));
+ return wp->w_p_cul || (wp->w_p_cole > 0 && !conceal_cursor_line(wp));
}
/*
@@ -754,8 +695,11 @@ bool win_cursorline_standout(const win_T *wp)
* 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, Providers *providers)
+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
@@ -790,12 +734,6 @@ static void win_update(win_T *wp, Providers *providers)
linenr_T mod_bot = 0;
int save_got_int;
-
- // 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.
- buf_signcols(buf);
-
type = wp->w_redr_type;
if (type >= NOT_VALID) {
@@ -803,21 +741,27 @@ static void win_update(win_T *wp, Providers *providers)
wp->w_lines_valid = 0;
}
- // Window is zero-height: nothing to draw.
- if (wp->w_grid.Rows == 0) {
+ // Window is zero-height: Only need to draw the separator
+ if (wp->w_grid.rows == 0) {
+ // draw the horizontal separator below this window
+ draw_hsep_win(wp);
+ draw_sep_connectors_win(wp);
wp->w_redr_type = 0;
return;
}
// Window is zero-width: Only need to draw the separator.
- if (wp->w_grid.Columns == 0) {
+ if (wp->w_grid.cols == 0) {
// draw the vertical separator right of this window
- draw_vsep_win(wp, 0);
+ draw_vsep_win(wp);
+ draw_sep_connectors_win(wp);
wp->w_redr_type = 0;
return;
}
- init_search_hl(wp);
+ redraw_win_signcol(wp);
+
+ init_search_hl(wp, &search_hl);
/* Force redraw when width of 'number' or 'relativenumber' column
* changes. */
@@ -987,7 +931,7 @@ static void win_update(win_T *wp, Providers *providers)
if (mod_top != 0
&& wp->w_topline == mod_top
&& (!wp->w_lines[0].wl_valid
- || wp->w_topline <= wp->w_lines[0].wl_lnum)) {
+ || 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
@@ -1006,7 +950,7 @@ static void win_update(win_T *wp, Providers *providers)
j = 0;
for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ln++) {
j++;
- if (j >= wp->w_grid.Rows - 2) {
+ if (j >= wp->w_grid.rows - 2) {
break;
}
(void)hasFoldingWin(wp, ln, NULL, &ln, true, NULL);
@@ -1014,13 +958,13 @@ static void win_update(win_T *wp, Providers *providers)
} 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
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;
}
- if (i != 0 && i < wp->w_grid.Rows - 2) { // less than a screen off
+ if (i != 0 && i < wp->w_grid.rows - 2) { // less than a screen off
// Try to insert the correct number of lines.
// If not the last window, delete the lines at the bottom.
// win_ins_lines may fail when the terminal can't do it.
@@ -1033,8 +977,8 @@ static void win_update(win_T *wp, Providers *providers)
// Move the entries that were scrolled, disable
// the entries for the lines to be redrawn.
- if ((wp->w_lines_valid += j) > wp->w_grid.Rows) {
- wp->w_lines_valid = wp->w_grid.Rows;
+ if ((wp->w_lines_valid += j) > wp->w_grid.rows) {
+ wp->w_lines_valid = wp->w_grid.rows;
}
for (idx = wp->w_lines_valid; idx - j >= 0; idx--) {
wp->w_lines[idx] = wp->w_lines[idx - j];
@@ -1087,7 +1031,7 @@ static void win_update(win_T *wp, Providers *providers)
row -= wp->w_topfill;
if (row > 0) {
win_scroll_lines(wp, 0, -row);
- bot_start = wp->w_grid.Rows - row;
+ bot_start = wp->w_grid.rows - row;
}
if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) {
/*
@@ -1103,7 +1047,7 @@ static void win_update(win_T *wp, Providers *providers)
/* 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) {
+ + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) {
wp->w_lines_valid = idx + 1;
break;
}
@@ -1128,18 +1072,18 @@ static void win_update(win_T *wp, Providers *providers)
// When starting redraw in the first line, redraw all lines.
if (mid_start == 0) {
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
}
} else {
// Not VALID or INVERTED: redraw all lines.
mid_start = 0;
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
}
if (type == SOME_VALID) {
// SOME_VALID: redraw all lines.
mid_start = 0;
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
type = NOT_VALID;
}
@@ -1215,19 +1159,40 @@ static void win_update(win_T *wp, Providers *providers)
*/
if (VIsual_mode == Ctrl_V) {
colnr_T fromc, toc;
- int save_ve_flags = ve_flags;
+ unsigned int save_ve_flags = curwin->w_ve_flags;
if (curwin->w_p_lbr) {
- ve_flags = VE_ALL;
+ curwin->w_ve_flags = VE_ALL;
}
getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
- ve_flags = save_ve_flags;
toc++;
+ curwin->w_ve_flags = save_ve_flags;
// Highlight to the end of the line, unless 'virtualedit' has
// "block".
- if (curwin->w_curswant == MAXCOL && !(ve_flags & VE_BLOCK)) {
- toc = MAXCOL;
+ if (curwin->w_curswant == MAXCOL) {
+ if (get_ve_flags() & VE_BLOCK) {
+ pos_T pos;
+ int cursor_above = curwin->w_cursor.lnum < VIsual.lnum;
+
+ // Need to find the longest line.
+ toc = 0;
+ pos.coladd = 0;
+ for (pos.lnum = curwin->w_cursor.lnum;
+ cursor_above ? pos.lnum <= VIsual.lnum : pos.lnum >= VIsual.lnum;
+ pos.lnum += cursor_above ? 1 : -1) {
+ colnr_T t;
+
+ pos.col = STRLEN(ml_get_buf(wp->w_buffer, pos.lnum, false));
+ getvvcol(wp, &pos, NULL, NULL, &t);
+ if (toc < t) {
+ toc = t;
+ }
+ }
+ toc++;
+ } else {
+ toc = MAXCOL;
+ }
}
if (fromc != wp->w_old_cursor_fcol
@@ -1305,7 +1270,7 @@ static void win_update(win_T *wp, Providers *providers)
}
}
srow += mid_start;
- mid_end = wp->w_grid.Rows;
+ 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) {
@@ -1346,37 +1311,27 @@ static void win_update(win_T *wp, Providers *providers)
srow = 0;
lnum = wp->w_topline; // first line shown in window
- decor_redraw_reset(buf, &decor_state);
-
- Providers line_providers;
- kvi_init(line_providers);
+ win_extmark_arr.size = 0;
- linenr_T knownmax = ((wp->w_valid & VALID_BOTLINE)
- ? wp->w_botline
- : (wp->w_topline + wp->w_height_inner));
+ decor_redraw_reset(buf, &decor_state);
- for (size_t k = 0; k < kv_size(*providers); k++) {
- DecorProvider *p = kv_A(*providers, k);
- if (p && p->redraw_win != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 4);
- args.items[0] = WINDOW_OBJ(wp->handle);
- args.items[1] = BUFFER_OBJ(buf->handle);
- // TODO(bfredl): we are not using this, but should be first drawn line?
- args.items[2] = INTEGER_OBJ(wp->w_topline-1);
- args.items[3] = INTEGER_OBJ(knownmax);
- if (provider_invoke(p->ns_id, "win", p->redraw_win, args, true)) {
- kvi_push(line_providers, p);
- }
+ 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;
}
}
- win_check_ns_hl(wp);
-
+ bool cursorline_standout = win_cursorline_standout(wp);
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) */
- if (row == wp->w_grid.Rows) {
+ if (row == wp->w_grid.rows) {
didline = true;
break;
}
@@ -1417,8 +1372,8 @@ static void win_update(win_T *wp, Providers *providers)
// if lines were inserted or deleted
|| (wp->w_match_head != NULL
&& buf->b_mod_xlines != 0)))))
- || (wp->w_p_cul && (lnum == wp->w_cursor.lnum
- || lnum == wp->w_last_cursorline))) {
+ || (cursorline_standout && lnum == wp->w_cursor.lnum)
+ || lnum == wp->w_last_cursorline) {
if (lnum == mod_top) {
top_to_mod = false;
}
@@ -1481,7 +1436,7 @@ static void win_update(win_T *wp, Providers *providers)
new_rows += plines_win(wp, l, true);
}
j++;
- if (new_rows > wp->w_grid.Rows - row - 2) {
+ if (new_rows > wp->w_grid.rows - row - 2) {
// it's getting too much, must redraw the rest
new_rows = 9999;
break;
@@ -1493,17 +1448,17 @@ static void win_update(win_T *wp, Providers *providers)
* remaining text or scrolling fails, must redraw the
* rest. If scrolling works, must redraw the text
* below the scrolled text. */
- if (row - xtra_rows >= wp->w_grid.Rows - 2) {
+ if (row - xtra_rows >= wp->w_grid.rows - 2) {
mod_bot = MAXLNUM;
} else {
win_scroll_lines(wp, row, xtra_rows);
- bot_start = wp->w_grid.Rows + xtra_rows;
+ bot_start = wp->w_grid.rows + xtra_rows;
}
} else if (xtra_rows > 0) {
/* May scroll text down. If there is not enough
* remaining text of scrolling fails, must redraw the
* rest. */
- if (row + xtra_rows >= wp->w_grid.Rows - 2) {
+ if (row + xtra_rows >= wp->w_grid.rows - 2) {
mod_bot = MAXLNUM;
} else {
win_scroll_lines(wp, row + old_rows, xtra_rows);
@@ -1531,7 +1486,7 @@ static void win_update(win_T *wp, Providers *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) {
+ > wp->w_grid.rows) {
wp->w_lines_valid = j + 1;
break;
}
@@ -1545,8 +1500,8 @@ static void win_update(win_T *wp, Providers *providers)
// move entries in w_lines[] downwards
j -= i;
wp->w_lines_valid += j;
- if (wp->w_lines_valid > wp->w_grid.Rows) {
- wp->w_lines_valid = wp->w_grid.Rows;
+ if (wp->w_lines_valid > wp->w_grid.rows) {
+ wp->w_lines_valid = wp->w_grid.rows;
}
for (i = wp->w_lines_valid; i - j >= idx; i--) {
wp->w_lines[i] = wp->w_lines[i - j];
@@ -1577,13 +1532,13 @@ static void win_update(win_T *wp, Providers *providers)
&& 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
+ && 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;
+ row = wp->w_grid.rows + 1;
} else {
- prepare_search_hl(wp, lnum);
+ prepare_search_hl(wp, &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)) {
@@ -1592,26 +1547,26 @@ static void win_update(win_T *wp, Providers *providers)
// Display one line
row = win_line(wp, lnum, srow,
- foldinfo.fi_lines ? srow : wp->w_grid.Rows,
+ foldinfo.fi_lines ? srow : wp->w_grid.rows,
mod_top == 0, false, foldinfo, &line_providers);
- wp->w_lines[idx].wl_folded = foldinfo.fi_lines != 0;
- wp->w_lines[idx].wl_lastlnum = lnum;
- did_update = DID_LINE;
-
- if (foldinfo.fi_lines > 0) {
- did_update = DID_FOLD;
+ 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;
}
-
- syntax_last_parsed = lnum;
}
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 = plines_win(wp, lnum, true);
@@ -1625,17 +1580,17 @@ static void win_update(win_T *wp, Providers *providers)
idx++;
lnum += foldinfo.fi_lines + 1;
} else {
- if (wp->w_p_rnu) {
- // 'relativenumber' set: The text doesn't need to be drawn, but
- // the number column nearly always does.
+ 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 = fold_info(wp, lnum);
- (void)win_line(wp, lnum, srow, wp->w_grid.Rows, true, true,
+ (void)win_line(wp, lnum, srow, wp->w_grid.rows, true, true,
info, &line_providers);
}
// This line does not need to be drawn, advance to the next one.
row += wp->w_lines[idx++].wl_size;
- if (row > wp->w_grid.Rows) { // past end of screen
+ if (row > wp->w_grid.rows) { // past end of screen
break;
}
lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
@@ -1651,6 +1606,11 @@ static void win_update(win_T *wp, Providers *providers)
* End of loop over all window lines.
*/
+ // Now that the window has been redrawn with the old and new cursor line,
+ // update w_last_cursorline.
+ wp->w_last_cursorline = cursorline_standout ? wp->w_cursor.lnum : 0;
+
+ wp->w_last_cursor_lnum_rnu = wp->w_p_rnu ? wp->w_cursor.lnum : 0;
if (idx > wp->w_lines_valid) {
wp->w_lines_valid = idx;
@@ -1678,39 +1638,41 @@ static void win_update(win_T *wp, Providers *providers)
* Don't overwrite it, it can be edited.
*/
wp->w_botline = lnum + 1;
- } else if (win_get_fill(wp, lnum) >= wp->w_grid.Rows - srow) {
+ } else if (win_get_fill(wp, lnum) >= wp->w_grid.rows - srow) {
// Window ends in filler lines.
wp->w_botline = lnum;
- wp->w_filler_rows = wp->w_grid.Rows - srow;
+ 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 scr_row = wp->w_grid.rows - 1;
// Last line isn't finished: Display "@@@" in the last screen line.
- grid_puts_len(&wp->w_grid, (char_u *)"@@", 2, scr_row, 0, at_attr);
+ 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.Columns,
+ grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.cols,
'@', ' ', 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;
+
// Last line isn't finished: Display "@@@" at the end.
- grid_fill(&wp->w_grid, wp->w_grid.Rows - 1, wp->w_grid.Rows,
- wp->w_grid.Columns - 3, wp->w_grid.Columns, '@', '@', at_attr);
+ grid_fill(&wp->w_grid, wp->w_grid.rows - 1, wp->w_grid.rows,
+ MAX(start_col, 0), wp->w_grid.cols, '@', '@', 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, '@', ' ', true, srow, wp->w_grid.rows, HLF_AT);
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);
- if (j > 0 && !wp->w_botfill && row < wp->w_grid.Rows) {
+ 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;
- row = win_line(wp, wp->w_botline, row, wp->w_grid.Rows,
+ row = win_line(wp, wp->w_botline, row, wp->w_grid.rows,
false, false, info, &line_providers);
}
} else if (dollar_vcol == -1) {
@@ -1719,14 +1681,16 @@ static void win_update(win_T *wp, Providers *providers)
// 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,
+ win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.rows,
HLF_EOB);
}
kvi_destroy(line_providers);
if (wp->w_redr_type >= REDRAW_TOP) {
- draw_vsep_win(wp, 0);
+ draw_vsep_win(wp);
+ draw_hsep_win(wp);
+ draw_sep_connectors_win(wp);
}
syn_set_timeout(NULL);
@@ -1735,6 +1699,13 @@ static void win_update(win_T *wp, Providers *providers)
wp->w_old_topfill = wp->w_topfill;
wp->w_old_botfill = wp->w_botfill;
+ // 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, 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) {
/*
* There is a trick with w_botline. If we invalidate it on each
@@ -1766,12 +1737,11 @@ static void win_update(win_T *wp, Providers *providers)
}
}
-
// restore got_int, unless CTRL-C was hit while redrawing
if (!got_int) {
got_int = save_got_int;
}
-} // NOLINT(readability/fn_size)
+}
/// Returns width of the signcolumn that should be used for the whole window
///
@@ -1795,8 +1765,8 @@ static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row,
{
int nn = off + width;
- if (nn > wp->w_grid.Columns) {
- nn = wp->w_grid.Columns;
+ if (nn > wp->w_grid.cols) {
+ nn = wp->w_grid.cols;
}
if (wp->w_p_rl) {
@@ -1825,7 +1795,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, i
win_hl_attr(wp, HLF_FC));
}
// draw the sign column
- int count = win_signcol_count(wp);
+ int count = wp->w_scwidth;
if (count > 0) {
n = win_fill_end(wp, ' ', ' ', n, win_signcol_width(wp) * count, row,
endrow, win_hl_attr(wp, HLF_SC));
@@ -1845,13 +1815,12 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, i
grid_fill(&wp->w_grid, row, endrow, W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
c1, c2, attr);
} else {
- grid_fill(&wp->w_grid, row, endrow, n, wp->w_grid.Columns, c1, c2, attr);
+ grid_fill(&wp->w_grid, row, endrow, n, wp->w_grid.cols, c1, c2, attr);
}
set_empty_rows(wp, row);
}
-
/// Advance **color_cols
///
/// @return true when there are columns to draw.
@@ -1869,7 +1838,7 @@ static int compute_foldcolumn(win_T *wp, int col)
{
int fdc = win_fdccol_count(wp);
int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
- int wwidth = wp->w_grid.Columns;
+ int wwidth = wp->w_grid.cols;
if (fdc > wwidth - (col + wmw)) {
fdc = wwidth - (col + wmw);
@@ -1883,8 +1852,8 @@ static int compute_foldcolumn(win_T *wp, int col)
static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, bool rl, int vcol)
{
const char_u *p = (char_u *)s->p;
- int cells = utf_ptr2cells(p);
- int c_len = utfc_ptr2len(p);
+ int cells = utf_ptr2cells((char *)p);
+ int c_len = utfc_ptr2len((char *)p);
int u8c, u8cc[MAX_MCO];
if (cells > maxcells) {
return -1;
@@ -1900,7 +1869,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
schar_from_ascii(dest[0], *p);
s->prev_c = u8c;
} else {
- if (p_arshape && !p_tbidi && arabic_char(u8c)) {
+ if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) {
// Do Arabic shaping.
int pc, pc1, nc;
int pcc[MAX_MCO];
@@ -1911,7 +1880,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
if (rl) {
pc = s->prev_c;
pc1 = s->prev_c1;
- nc = utf_ptr2char(p + c_len);
+ nc = utf_ptr2char((char *)p + c_len);
s->prev_c1 = u8cc[0];
} else {
pc = utfc_ptr2char(p + c_len, pcc);
@@ -1934,7 +1903,6 @@ done:
return cells;
}
-
/// Fills the foldcolumn at "p" for window "wp".
/// Only to be called when 'foldcolumn' > 0.
///
@@ -1960,7 +1928,7 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
level = foldinfo.fi_level;
// If the column is too narrow, we start at the lowest level that
- // fits and use numbers to indicated the depth.
+ // fits and use numbers to indicate the depth.
first_level = level - fdc - closed + 1;
if (first_level < 1) {
first_level = 1;
@@ -1978,7 +1946,7 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
symbol = '>';
}
- len = utf_char2bytes(symbol, &p[char_counter]);
+ len = utf_char2bytes(symbol, (char *)&p[char_counter]);
char_counter += len;
if (first_level + i >= level) {
i++;
@@ -1992,11 +1960,43 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
char_counter -= len;
memset(&p[char_counter], ' ', len);
}
- len = utf_char2bytes(wp->w_p_fcs_chars.foldclosed, &p[char_counter]);
+ len = utf_char2bytes(wp->w_p_fcs_chars.foldclosed, (char *)&p[char_counter]);
char_counter += len;
}
- return MAX(char_counter + (fdc-i), (size_t)fdc);
+ return MAX(char_counter + (fdc - i), (size_t)fdc);
+}
+
+static inline void provider_err_virt_text(linenr_T lnum, char *err)
+{
+ Decoration err_decor = DECORATION_INIT;
+ int hl_err = syn_check_group(S_LEN("ErrorMsg"));
+ kv_push(err_decor.virt_text,
+ ((VirtTextChunk){ .text = provider_err,
+ .hl_id = hl_err }));
+ err_decor.virt_text_width = mb_string2cells(err);
+ decor_add_ephemeral(lnum - 1, 0, lnum - 1, 0, &err_decor, 0, 0);
+}
+
+static inline void get_line_number_str(win_T *wp, linenr_T lnum, char_u *buf, size_t buf_len)
+{
+ long num;
+ char *fmt = "%*ld ";
+
+ if (wp->w_p_nu && !wp->w_p_rnu) {
+ // 'number' + 'norelativenumber'
+ num = (long)lnum;
+ } else {
+ // 'relativenumber', don't use negative numbers
+ num = labs((long)get_cursor_rel_lnum(wp, lnum));
+ if (num == 0 && wp->w_p_nu && wp->w_p_rnu) {
+ // 'number' + 'relativenumber'
+ num = lnum;
+ fmt = "%-*ld ";
+ }
+ }
+
+ snprintf((char *)buf, buf_len, fmt, number_width(wp), num);
}
/// Display line "lnum" of window 'wp' on the screen.
@@ -2014,7 +2014,7 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
///
/// @return the number of last row the line occupies.
static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
- bool number_only, foldinfo_T foldinfo, Providers *providers)
+ bool number_only, foldinfo_T foldinfo, DecorProviders *providers)
{
int c = 0; // init for GCC
long vcol = 0; // virtual column (for tabs)
@@ -2111,13 +2111,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
int line_attr_save;
int line_attr_lowprio = 0; // low-priority attribute for the line
int line_attr_lowprio_save;
- matchitem_T *cur; // points to the match list
- match_T *shl; // points to search_hl or a match
- bool shl_flag; // flag to indicate whether search_hl
- // has been processed or not
- bool prevcol_hl_flag; // flag to indicate whether prevcol
- // equals startcol of search_hl or one
- // of the matches
int prev_c = 0; // previous Arabic character
int prev_c1 = 0; // first composing char for prev_c
@@ -2139,13 +2132,13 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// draw_state: items that are drawn in sequence:
#define WL_START 0 // nothing done yet
-#define WL_CMDLINE WL_START + 1 // cmdline window column
-#define WL_FOLD WL_CMDLINE + 1 // 'foldcolumn'
-#define WL_SIGN WL_FOLD + 1 // column for signs
-#define WL_NR WL_SIGN + 1 // line number
-#define WL_BRI WL_NR + 1 // 'breakindent'
-#define WL_SBR WL_BRI + 1 // 'showbreak' or 'diff'
-#define WL_LINE WL_SBR + 1 // text in the line
+#define WL_CMDLINE (WL_START + 1) // cmdline window column
+#define WL_FOLD (WL_CMDLINE + 1) // 'foldcolumn'
+#define WL_SIGN (WL_FOLD + 1) // column for signs
+#define WL_NR (WL_SIGN + 1) // line number
+#define WL_BRI (WL_NR + 1) // 'breakindent'
+#define WL_SBR (WL_BRI + 1) // 'showbreak' or 'diff'
+#define WL_LINE (WL_SBR + 1) // text in the line
int draw_state = WL_START; // what to draw next
int syntax_flags = 0;
@@ -2177,13 +2170,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
row = startrow;
buf_T *buf = wp->w_buffer;
- bool end_fill = (lnum == buf->b_ml.ml_line_count+1);
+ bool end_fill = (lnum == buf->b_ml.ml_line_count + 1);
if (!number_only) {
// To speed up the loop below, set extra_check when there is linebreak,
// trailing white space and/or syntax processing to be done.
extra_check = wp->w_p_lbr;
- if (syntax_present(wp) && !wp->w_s->b_syn_error && !wp->w_s->b_syn_slow) {
+ if (syntax_present(wp) && !wp->w_s->b_syn_error && !wp->w_s->b_syn_slow
+ && !has_fold && !end_fill) {
// Prepare for syntax highlighting in this line. When there is an
// error, stop syntax highlighting.
save_did_emsg = did_emsg;
@@ -2200,37 +2194,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- has_decor = decor_redraw_line(wp->w_buffer, lnum-1,
- &decor_state);
+ has_decor = decor_redraw_line(buf, lnum - 1, &decor_state);
- for (size_t k = 0; k < kv_size(*providers); k++) {
- DecorProvider *p = kv_A(*providers, k);
- if (p && p->redraw_line != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 3);
- args.items[0] = WINDOW_OBJ(wp->handle);
- args.items[1] = BUFFER_OBJ(buf->handle);
- args.items[2] = INTEGER_OBJ(lnum-1);
- if (provider_invoke(p->ns_id, "line", p->redraw_line, args, true)) {
- has_decor = true;
- } else {
- // return 'false' or error: skip rest of this window
- kv_A(*providers, k) = NULL;
- }
-
- win_check_ns_hl(wp);
- }
- }
+ providers_invoke_line(wp, providers, lnum - 1, &has_decor, &provider_err);
if (provider_err) {
- Decoration err_decor = DECORATION_INIT;
- int hl_err = syn_check_group(S_LEN("ErrorMsg"));
- kv_push(err_decor.virt_text,
- ((VirtTextChunk){ .text = provider_err,
- .hl_id = hl_err }));
- err_decor.virt_text_width = mb_string2cells((char_u *)provider_err);
- decor_add_ephemeral(lnum-1, 0, lnum-1, 0, &err_decor);
- provider_err = NULL;
+ provider_err_virt_text(lnum, provider_err);
has_decor = true;
+ provider_err = NULL;
}
if (has_decor) {
@@ -2413,7 +2384,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) {
line_attr_lowprio = cul_attr;
} else {
- if (!(State & INSERT) && bt_quickfix(wp->w_buffer)
+ if (!(State & MODE_INSERT) && bt_quickfix(wp->w_buffer)
&& qf_current_entry(wp) == lnum) {
line_attr = hl_combine_attr(cul_attr, line_attr);
} else {
@@ -2425,12 +2396,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
area_highlighting = true;
}
- // Update w_last_cursorline even if Visual mode is active.
- wp->w_last_cursorline = wp->w_cursor.lnum;
}
memset(sattrs, 0, sizeof(sattrs));
num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs);
+ decor_redraw_signs(buf, lnum - 1, &num_signs, sattrs);
// If this line has a sign with line highlighting set line_attr.
// TODO(bfredl, vigoux): this should not take priority over decoration!
@@ -2490,6 +2460,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_list && !has_fold && !end_fill) {
if (wp->w_p_lcs_chars.space
|| wp->w_p_lcs_chars.multispace != NULL
+ || wp->w_p_lcs_chars.leadmultispace != NULL
|| wp->w_p_lcs_chars.trail
|| wp->w_p_lcs_chars.lead
|| wp->w_p_lcs_chars.nbsp) {
@@ -2504,7 +2475,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
trailcol += (colnr_T)(ptr - line);
}
// find end of leading whitespace
- if (wp->w_p_lcs_chars.lead) {
+ if (wp->w_p_lcs_chars.lead || wp->w_p_lcs_chars.leadmultispace != NULL) {
leadcol = 0;
while (ascii_iswhite(ptr[leadcol])) {
leadcol++;
@@ -2557,7 +2528,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
ptr = prev_ptr;
// If the character fits on the screen, don't need to skip it.
// Except for a TAB.
- if (utf_ptr2cells(ptr) >= c || *ptr == TAB) {
+ if (utf_ptr2cells((char *)ptr) >= c || *ptr == TAB) {
n_skip = v - vcol;
}
}
@@ -2637,69 +2608,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- /*
- * Handle highlighting the last used search pattern and matches.
- * Do this for both search_hl and the match list.
- */
- cur = wp->w_match_head;
- shl_flag = false;
- while ((cur != NULL || !shl_flag) && !number_only
- && !has_fold && !end_fill) {
- if (!shl_flag) {
- shl = &search_hl;
- shl_flag = true;
- } else {
- shl = &cur->hl; // -V595
- }
- shl->startcol = MAXCOL;
- shl->endcol = MAXCOL;
- shl->attr_cur = 0;
- shl->is_addpos = false;
- v = (ptr - line);
- if (cur != NULL) {
- cur->pos.cur = 0;
- }
- next_search_hl(wp, shl, lnum, (colnr_T)v,
- shl == &search_hl ? NULL : cur);
- if (wp->w_s->b_syn_slow) {
- has_syntax = false;
- }
-
- // Need to get the line again, a multi-line regexp may have made it
- // invalid.
- line = ml_get_buf(wp->w_buffer, lnum, false);
- ptr = line + v;
-
- if (shl->lnum != 0 && shl->lnum <= lnum) {
- if (shl->lnum == lnum) {
- shl->startcol = shl->rm.startpos[0].col;
- } else {
- shl->startcol = 0;
- }
- if (lnum == shl->lnum + shl->rm.endpos[0].lnum
- - shl->rm.startpos[0].lnum) {
- shl->endcol = shl->rm.endpos[0].col;
- } else {
- shl->endcol = MAXCOL;
- }
- // Highlight one character for an empty match.
- if (shl->startcol == shl->endcol) {
- if (line[shl->endcol] != NUL) {
- shl->endcol += utfc_ptr2len(line + shl->endcol);
- } else {
- ++shl->endcol;
- }
- }
- if ((long)shl->startcol < v) { // match at leftcol
- shl->attr_cur = shl->attr;
- search_attr = shl->attr;
- search_attr_from_match = shl != &search_hl;
- }
- area_highlighting = true;
- }
- if (shl != &search_hl && cur != NULL) {
- cur = cur->next;
- }
+ if (!number_only && !has_fold && !end_fill) {
+ v = ptr - line;
+ area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v,
+ &line, &search_hl, &search_attr,
+ &search_attr_from_match);
+ ptr = line + v; // "line" may have been updated
}
unsigned off = 0; // Offset relative start of line
@@ -2708,7 +2622,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// Rightleft window: process the text in the normal direction, but put
// it in linebuf_char[off] from right to left. Start at the
// rightmost column of the window.
- col = grid->Columns - 1;
+ col = grid->cols - 1;
off += col;
}
@@ -2723,6 +2637,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// Repeat for the whole displayed line.
for (;;) {
int has_match_conc = 0; ///< match wants to conceal
+ int decor_conceal = 0;
+
bool did_decrement_ptr = false;
// Skip this quickly when working on the text.
@@ -2771,13 +2687,17 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
draw_state = WL_SIGN;
/* Show the sign column when there are any signs in this
* buffer or when using Netbeans. */
- int count = win_signcol_count(wp);
- if (count > 0) {
+ if (wp->w_scwidth > 0) {
get_sign_display_info(false, wp, lnum, sattrs, row,
- startrow, filler_lines, filler_todo, count,
+ startrow, filler_lines, filler_todo,
&c_extra, &c_final, extra, sizeof(extra),
- &p_extra, &n_extra,
- &char_attr, &draw_state, &sign_idx);
+ &p_extra, &n_extra, &char_attr, sign_idx);
+ sign_idx++;
+ if (sign_idx < wp->w_scwidth) {
+ draw_state = WL_SIGN - 1;
+ } else {
+ sign_idx = 0;
+ }
}
}
@@ -2792,34 +2712,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// in 'lnum', then display the sign instead of the line
// number.
if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'
- && num_signs > 0) {
- int count = win_signcol_count(wp);
+ && num_signs > 0 && sign_get_attr(SIGN_TEXT, sattrs, 0, 1)) {
get_sign_display_info(true, wp, lnum, sattrs, row,
- startrow, filler_lines, filler_todo, count,
+ startrow, filler_lines, filler_todo,
&c_extra, &c_final, extra, sizeof(extra),
- &p_extra, &n_extra,
- &char_attr, &draw_state, &sign_idx);
+ &p_extra, &n_extra, &char_attr, sign_idx);
} else {
+ // Draw the line number (empty space after wrapping).
if (row == startrow + filler_lines) {
- // Draw the line number (empty space after wrapping). */
- long num;
- char *fmt = "%*ld ";
-
- if (wp->w_p_nu && !wp->w_p_rnu) {
- // 'number' + 'norelativenumber'
- num = (long)lnum;
- } else {
- // 'relativenumber', don't use negative numbers
- num = labs((long)get_cursor_rel_lnum(wp, lnum));
- if (num == 0 && wp->w_p_nu && wp->w_p_rnu) {
- // 'number' + 'relativenumber'
- num = lnum;
- fmt = "%-*ld ";
- }
- }
-
- snprintf((char *)extra, sizeof(extra),
- fmt, number_width(wp), num);
+ get_line_number_str(wp, lnum, (char_u *)extra, sizeof(extra));
if (wp->w_skipcol > 0) {
for (p_extra = extra; *p_extra == ' '; p_extra++) {
*p_extra = '-';
@@ -2827,9 +2728,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
if (wp->w_p_rl) { // reverse line numbers
// like rl_mirror(), but keep the space at the end
- char_u *p2 = skipwhite(extra);
+ char_u *p2 = (char_u *)skipwhite((char *)extra);
p2 = skiptowhite(p2) - 1;
- for (char_u *p1 = skipwhite(extra); p1 < p2; p1++, p2--) {
+ for (char_u *p1 = (char_u *)skipwhite((char *)extra); p1 < p2; p1++, p2--) {
const int t = *p1;
*p1 = *p2;
*p2 = t;
@@ -2837,41 +2738,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
p_extra = extra;
c_extra = NUL;
- c_final = NUL;
} else {
c_extra = ' ';
- c_final = NUL;
}
+ c_final = NUL;
n_extra = number_width(wp) + 1;
- char_attr = win_hl_attr(wp, HLF_N);
-
- if (wp->w_p_rnu && lnum < wp->w_cursor.lnum) {
- // Use LineNrAbove
- char_attr = win_hl_attr(wp, HLF_LNA);
- }
- if (wp->w_p_rnu && lnum > wp->w_cursor.lnum) {
- // Use LineNrBelow
- char_attr = win_hl_attr(wp, HLF_LNB);
- }
-
- sign_attrs_T *num_sattr = sign_get_attr(SIGN_NUMHL, sattrs, 0, 1);
- if (num_sattr != NULL) {
- // :sign defined with "numhl" highlight.
- char_attr = num_sattr->sat_numhl;
- } else if (wp->w_p_cul
- && lnum == wp->w_cursor.lnum
- && (wp->w_p_culopt_flags & CULOPT_NBR)
- && (row == startrow
- || wp->w_p_culopt_flags & CULOPT_LINE)
- && filler_todo == 0) {
- // When 'cursorline' is set highlight the line number of
- // the current line differently.
- // When 'cursorlineopt' has "screenline" only highlight
- // the line number itself.
- // TODO(vim): Can we use CursorLine instead of CursorLineNr
- // when CursorLineNr isn't set?
- char_attr = win_hl_attr(wp, HLF_CLN);
- }
+ char_attr = get_line_number_attr(wp, lnum, row, startrow, filler_lines, sattrs);
}
}
}
@@ -2932,7 +2804,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_rl) {
n_extra = col + 1;
} else {
- n_extra = grid->Columns - col;
+ n_extra = grid->cols - col;
}
char_attr = 0;
} else if (filler_todo > 0) {
@@ -2947,7 +2819,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_rl) {
n_extra = col + 1;
} else {
- n_extra = grid->Columns - col;
+ n_extra = grid->cols - col;
}
char_attr = win_hl_attr(wp, HLF_DED);
}
@@ -3005,7 +2877,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) {
line_attr_lowprio = cul_attr;
} else {
- if (!(State & INSERT) && bt_quickfix(wp->w_buffer)
+ if (!(State & MODE_INSERT) && bt_quickfix(wp->w_buffer)
&& qf_current_entry(wp) == lnum) {
line_attr = hl_combine_attr(cul_attr, line_attr);
} else {
@@ -3021,15 +2893,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& vcol >= (long)wp->w_virtcol)
|| (number_only && draw_state > WL_NR))
&& filler_todo <= 0) {
- draw_virt_text(buf, win_col_offset, &col, grid->Columns);
- grid_put_linebuf(grid, row, 0, col, -grid->Columns, wp->w_p_rl, wp,
+ draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row);
+ grid_put_linebuf(grid, row, 0, col, -grid->cols, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
row = wp->w_cline_row + wp->w_cline_height;
} else {
- row = grid->Rows;
+ row = grid->rows;
}
break;
}
@@ -3057,19 +2929,19 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (draw_state == WL_LINE
&& has_fold
- && col < grid->Columns
+ && col < grid->cols
&& n_extra == 0
&& row == startrow) {
// fill rest of line with 'fold'
c_extra = wp->w_p_fcs_chars.fold;
c_final = NUL;
- n_extra = wp->w_p_rl ? (col + 1) : (grid->Columns - col);
+ n_extra = wp->w_p_rl ? (col + 1) : (grid->cols - col);
}
if (draw_state == WL_LINE
&& has_fold
- && col >= grid->Columns
+ && col >= grid->cols
&& n_extra != 0
&& row == startrow) {
// Truncate the folding.
@@ -3080,7 +2952,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// handle Visual or match highlighting in this line
if (vcol == fromcol
|| (vcol + 1 == fromcol && n_extra == 0
- && utf_ptr2cells(ptr) > 1)
+ && utf_ptr2cells((char *)ptr) > 1)
|| ((int)vcol_prev == fromcol_prev
&& vcol_prev < vcol // not at margin
&& vcol < tocol)) {
@@ -3096,115 +2968,13 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
if (!n_extra) {
- /*
- * Check for start/end of search pattern match.
- * After end, check for start/end of next match.
- * When another match, have to check for start again.
- * Watch out for matching an empty string!
- * Do this for 'search_hl' and the match list (ordered by
- * priority).
- */
+ // Check for start/end of 'hlsearch' and other matches.
+ // After end, check for start/end of next match.
+ // When another match, have to check for start again.
v = (ptr - line);
- cur = wp->w_match_head;
- shl_flag = false;
- while (cur != NULL || !shl_flag) {
- if (!shl_flag
- && (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) {
- shl = &search_hl;
- shl_flag = true;
- } else {
- shl = &cur->hl;
- }
- if (cur != NULL) {
- cur->pos.cur = 0;
- }
- bool pos_inprogress = true; // mark that a position match search is
- // in progress
- while (shl->rm.regprog != NULL
- || (cur != NULL && pos_inprogress)) {
- if (shl->startcol != MAXCOL
- && v >= (long)shl->startcol
- && v < (long)shl->endcol) {
- int tmp_col = v + utfc_ptr2len(ptr);
-
- if (shl->endcol < tmp_col) {
- shl->endcol = tmp_col;
- }
- shl->attr_cur = shl->attr;
- // Match with the "Conceal" group results in hiding
- // the match.
- if (cur != NULL
- && shl != &search_hl
- && syn_name2id("Conceal") == cur->hlg_id) {
- has_match_conc = v == (long)shl->startcol ? 2 : 1;
- match_conc = cur->conceal_char;
- } else {
- has_match_conc = 0;
- }
- } else if (v == (long)shl->endcol) {
- shl->attr_cur = 0;
-
- next_search_hl(wp, shl, lnum, (colnr_T)v,
- shl == &search_hl ? NULL : cur);
- pos_inprogress = !(cur == NULL || cur->pos.cur == 0);
-
- // Need to get the line again, a multi-line regexp
- // may have made it invalid.
- line = ml_get_buf(wp->w_buffer, lnum, false);
- ptr = line + v;
-
- if (shl->lnum == lnum) {
- shl->startcol = shl->rm.startpos[0].col;
- if (shl->rm.endpos[0].lnum == 0) {
- shl->endcol = shl->rm.endpos[0].col;
- } else {
- shl->endcol = MAXCOL;
- }
-
- if (shl->startcol == shl->endcol) {
- // highlight empty match, try again after it
- shl->endcol += utfc_ptr2len(line + shl->endcol);
- }
-
- // Loop to check if the match starts at the
- // current position
- continue;
- }
- }
- break;
- }
- if (shl != &search_hl && cur != NULL) {
- cur = cur->next;
- }
- }
-
- /* Use attributes from match with highest priority among
- * 'search_hl' and the match list. */
- search_attr_from_match = false;
- search_attr = search_hl.attr_cur;
- cur = wp->w_match_head;
- shl_flag = false;
- while (cur != NULL || !shl_flag) {
- if (!shl_flag
- && (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) {
- shl = &search_hl;
- shl_flag = true;
- } else {
- shl = &cur->hl;
- }
- if (shl->attr_cur != 0) {
- search_attr = shl->attr_cur;
- search_attr_from_match = shl != &search_hl;
- }
- if (shl != &search_hl && cur != NULL) {
- cur = cur->next;
- }
- }
- // Only highlight one character after the last column.
- if (*ptr == NUL
- && (wp->w_p_list && lcs_eol_one == -1)) {
- search_attr = 0;
- }
+ search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, &search_hl, &has_match_conc,
+ &match_conc, lcs_eol_one, &search_attr_from_match);
+ ptr = line + v; // "line" may have been changed
// Do not allow a conceal over EOL otherwise EOL will be missed
// and bad things happen.
@@ -3237,6 +3007,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (area_attr != 0) {
char_attr = hl_combine_attr(line_attr, area_attr);
+ if (!highlight_match) {
+ // let search highlight show in Visual area if possible
+ char_attr = hl_combine_attr(search_attr, char_attr);
+ }
} else if (search_attr != 0) {
char_attr = hl_combine_attr(line_attr, search_attr);
}
@@ -3282,7 +3056,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
mb_c = c;
// If the UTF-8 character is more than one byte:
// Decode it into "mb_c".
- mb_l = utfc_ptr2len(p_extra);
+ mb_l = utfc_ptr2len((char *)p_extra);
mb_utf8 = false;
if (mb_l > n_extra) {
mb_l = 1;
@@ -3296,7 +3070,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
// If a double-width char doesn't fit display a '>' in the last column.
- if ((wp->w_p_rl ? (col <= 0) : (col >= grid->Columns - 1))
+ if ((wp->w_p_rl ? (col <= 0) : (col >= grid->cols - 1))
&& utf_char2cells(mb_c) == 2) {
c = '>';
mb_c = c;
@@ -3335,7 +3109,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
mb_c = c;
// If the UTF-8 character is more than one byte: Decode it
// into "mb_c".
- mb_l = utfc_ptr2len(ptr);
+ mb_l = utfc_ptr2len((char *)ptr);
mb_utf8 = false;
if (mb_l > 1) {
mb_c = utfc_ptr2char(ptr, u8cc);
@@ -3383,7 +3157,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
} else if (mb_l == 0) { // at the NUL at end-of-line
mb_l = 1;
- } else if (p_arshape && !p_tbidi && arabic_char(mb_c)) {
+ } else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c)) {
// Do Arabic shaping.
int pc, pc1, nc;
int pcc[MAX_MCO];
@@ -3393,7 +3167,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_rl) {
pc = prev_c;
pc1 = prev_c1;
- nc = utf_ptr2char(ptr + mb_l);
+ nc = utf_ptr2char((char *)ptr + mb_l);
prev_c1 = u8cc[0];
} else {
pc = utfc_ptr2char(ptr + mb_l, pcc);
@@ -3410,7 +3184,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// last column; the character is displayed at the start of the
// next line.
if ((wp->w_p_rl ? (col <= 0) :
- (col >= grid->Columns - 1))
+ (col >= grid->cols - 1))
&& utf_char2cells(mb_c) == 2) {
c = '>';
mb_c = c;
@@ -3465,6 +3239,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
did_emsg = save_did_emsg;
}
+ if (wp->w_s->b_syn_slow) {
+ has_syntax = false;
+ }
+
// Need to get the line again, a multi-line regexp may
// have made it invalid.
line = ml_get_buf(wp->w_buffer, lnum, false);
@@ -3526,7 +3304,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
/* In Insert mode only highlight a word that
* doesn't touch the cursor. */
if (spell_hlf != HLF_COUNT
- && (State & INSERT) != 0
+ && (State & MODE_INSERT)
&& wp->w_cursor.lnum == lnum
&& wp->w_cursor.col >=
(colnr_T)(prev_ptr - line)
@@ -3578,7 +3356,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (has_decor && v > 0) {
bool selected = (area_active || (area_highlighting && noinvcur
&& (colnr_T)vcol == wp->w_virtcol));
- int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1, off,
+ int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off,
selected, &decor_state);
if (extmark_attr != 0) {
if (!attr_pri) {
@@ -3587,6 +3365,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
char_attr = hl_combine_attr(extmark_attr, char_attr);
}
}
+
+ decor_conceal = decor_state.conceal;
+ if (decor_conceal && decor_state.conceal_char) {
+ decor_conceal = 2; // really??
+ }
}
// Found last space before word: check for line break.
@@ -3606,7 +3389,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- if (c == TAB && n_extra + col > grid->Columns) {
+ if (c == TAB && n_extra + col > grid->cols) {
n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
wp->w_buffer->b_p_vts_array) - 1;
}
@@ -3664,10 +3447,22 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- if ((trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
- || (leadcol != 0 && ptr < line + leadcol && c == ' ')) {
- c = (ptr > line + trailcol) ? wp->w_p_lcs_chars.trail
- : wp->w_p_lcs_chars.lead;
+ if (c == ' ' && ((trailcol != MAXCOL && ptr > line + trailcol)
+ || (leadcol != 0 && ptr < line + leadcol))) {
+ if (leadcol != 0 && in_multispace && ptr < line + leadcol
+ && wp->w_p_lcs_chars.leadmultispace != NULL) {
+ c = wp->w_p_lcs_chars.leadmultispace[multispace_pos++];
+ if (wp->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
+ multispace_pos = 0;
+ }
+ } else if (ptr > line + trailcol && wp->w_p_lcs_chars.trail) {
+ c = wp->w_p_lcs_chars.trail;
+ } else if (ptr < line + leadcol && wp->w_p_lcs_chars.lead) {
+ c = wp->w_p_lcs_chars.lead;
+ } else if (leadcol != 0 && wp->w_p_lcs_chars.space) {
+ c = wp->w_p_lcs_chars.space;
+ }
+
n_attr = 1;
extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = char_attr; // save current attr
@@ -3720,10 +3515,13 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
tab_len += n_extra - tab_len;
}
- // if n_extra > 0, it gives the number of chars
+ // If n_extra > 0, it gives the number of chars
// to use for a tab, else we need to calculate the width
- // for a tab
+ // for a tab.
int len = (tab_len * utf_char2len(wp->w_p_lcs_chars.tab2));
+ if (wp->w_p_lcs_chars.tab3) {
+ len += utf_char2len(wp->w_p_lcs_chars.tab3);
+ }
if (n_extra > 0) {
len += n_extra - tab_len;
}
@@ -3740,13 +3538,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
int lcs = wp->w_p_lcs_chars.tab2;
- // if tab3 is given, need to change the char
- // for tab
+ // if tab3 is given, use it for the last char
if (wp->w_p_lcs_chars.tab3 && i == tab_len - 1) {
lcs = wp->w_p_lcs_chars.tab3;
}
- utf_char2bytes(lcs, p);
- p += utf_char2len(lcs);
+ p += utf_char2bytes(lcs, (char *)p);
n_extra += utf_char2len(lcs) - (saved_nextra > 0 ? 1 : 0);
}
p_extra = p_extra_free;
@@ -3808,7 +3604,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|| ((fromcol >= 0 || fromcol_prev >= 0)
&& tocol > vcol
&& VIsual_mode != Ctrl_V
- && (wp->w_p_rl ? (col >= 0) : (col < grid->Columns))
+ && (wp->w_p_rl ? (col >= 0) : (col < grid->cols))
&& !(noinvcur
&& lnum == wp->w_cursor.lnum
&& (colnr_T)vcol == wp->w_virtcol)))
@@ -3880,28 +3676,33 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& virtual_active()
&& tocol != MAXCOL
&& vcol < tocol
- && (wp->w_p_rl ? (col >= 0) : (col < grid->Columns))) {
+ && (wp->w_p_rl ? (col >= 0) : (col < grid->cols))) {
c = ' ';
ptr--; // put it back at the NUL
}
}
if (wp->w_p_cole > 0
- && (wp != curwin || lnum != wp->w_cursor.lnum
- || conceal_cursor_line(wp))
- && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0)
- && !(lnum_in_visual_area
- && vim_strchr(wp->w_p_cocu, 'v') == NULL)) {
+ && (wp != curwin || lnum != wp->w_cursor.lnum || conceal_cursor_line(wp))
+ && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0 || decor_conceal > 0)
+ && !(lnum_in_visual_area && vim_strchr((char *)wp->w_p_cocu, 'v') == NULL)) {
char_attr = conceal_attr;
- if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1)
+ if (((prev_syntax_id != syntax_seqnr && (syntax_flags & HL_CONCEAL) != 0)
+ || has_match_conc > 1 || decor_conceal > 1)
&& (syn_get_sub_char() != NUL
|| (has_match_conc && match_conc)
+ || (decor_conceal && decor_state.conceal_char)
|| wp->w_p_cole == 1)
&& wp->w_p_cole != 3) {
// First time at this concealed item: display one
// character.
if (has_match_conc && match_conc) {
c = match_conc;
+ } else if (decor_conceal && decor_state.conceal_char) {
+ c = decor_state.conceal_char;
+ if (decor_state.conceal_attr) {
+ char_attr = decor_state.conceal_attr;
+ }
} else if (syn_get_sub_char() != NUL) {
c = syn_get_sub_char();
} else if (wp->w_p_lcs_chars.conceal != NUL) {
@@ -3957,7 +3758,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& conceal_cursor_line(wp)
&& (int)wp->w_virtcol <= vcol + n_skip) {
if (wp->w_p_rl) {
- wp->w_wcol = grid->Columns - col + boguscols - 1;
+ wp->w_wcol = grid->cols - col + boguscols - 1;
} else {
wp->w_wcol = col - boguscols;
}
@@ -4006,30 +3807,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// At end of the text line or just after the last character.
if (c == NUL && eol_hl_off == 0) {
- long prevcol = (ptr - line) - 1;
-
- // we're not really at that column when skipping some text
- if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) {
- prevcol++;
- }
+ // flag to indicate whether prevcol equals startcol of search_hl or
+ // one of the matches
+ bool prevcol_hl_flag = get_prevcol_hl_flag(wp, &search_hl,
+ (long)(ptr - line) - 1);
// Invert at least one char, used for Visual and empty line or
// highlight match at end of line. If it's beyond the last
// char on the screen, just overwrite that one (tricky!) Not
// needed when a '$' was displayed for 'list'.
- prevcol_hl_flag = false;
- if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol) {
- prevcol_hl_flag = true;
- } else {
- cur = wp->w_match_head;
- while (cur != NULL) {
- if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol) {
- prevcol_hl_flag = true;
- break;
- }
- cur = cur->next;
- }
- }
if (wp->w_p_lcs_chars.eol == lcs_eol_one
&& ((area_attr != 0 && vcol == fromcol
&& (VIsual_mode != Ctrl_V
@@ -4044,7 +3830,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
n = 1;
}
} else {
- if (col >= grid->Columns) {
+ if (col >= grid->cols) {
n = -1;
}
}
@@ -4060,25 +3846,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (area_attr == 0 && !has_fold) {
// Use attributes from match with highest priority among
// 'search_hl' and the match list.
- char_attr = search_hl.attr;
- cur = wp->w_match_head;
- shl_flag = false;
- while (cur != NULL || !shl_flag) {
- if (!shl_flag
- && (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) {
- shl = &search_hl;
- shl_flag = true;
- } else {
- shl = &cur->hl;
- }
- if ((ptr - line) - 1 == (long)shl->startcol
- && (shl == &search_hl || !shl->is_addpos)) {
- char_attr = shl->attr;
- }
- if (shl != &search_hl && cur != NULL) {
- cur = cur->next;
- }
- }
+ get_search_match_hl(wp, &search_hl, (long)(ptr - line), &char_attr);
}
int eol_attr = char_attr;
@@ -4130,7 +3898,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (((wp->w_p_cuc
&& (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
&& (int)wp->w_virtcol <
- (long)grid->Columns * (row - startrow + 1) + v
+ (long)grid->cols * (row - startrow + 1) + v
&& lnum != wp->w_cursor.lnum)
|| draw_color_col || line_attr_lowprio || line_attr
|| diff_hlf != (hlf_T)0 || has_virttext)) {
@@ -4168,7 +3936,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
int col_stride = wp->w_p_rl ? -1 : 1;
- while (wp->w_p_rl ? col >= 0 : col < grid->Columns) {
+ while (wp->w_p_rl ? col >= 0 : col < grid->cols) {
schar_from_ascii(linebuf_char[off], ' ');
col += col_stride;
if (draw_color_col) {
@@ -4204,7 +3972,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// terminal buffers may need to highlight beyond the end of the
// logical line
int n = wp->w_p_rl ? -1 : 1;
- while (col >= 0 && col < grid->Columns) {
+ while (col >= 0 && col < grid->cols) {
schar_from_ascii(linebuf_char[off], ' ');
linebuf_attr[off] = vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[vcol];
off += n;
@@ -4213,8 +3981,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- draw_virt_text(buf, win_col_offset, &col, grid->Columns);
- grid_put_linebuf(grid, row, 0, col, grid->Columns, wp->w_p_rl, wp,
+ draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row);
+ grid_put_linebuf(grid, row, 0, col, grid->cols, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
row++;
@@ -4235,10 +4003,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// Show "extends" character from 'listchars' if beyond the line end and
// 'list' is set.
if (wp->w_p_lcs_chars.ext != NUL
+ && draw_state == WL_LINE
&& wp->w_p_list
&& !wp->w_p_wrap
&& filler_todo <= 0
- && (wp->w_p_rl ? col == 0 : col == grid->Columns - 1)
+ && (wp->w_p_rl ? col == 0 : col == grid->cols - 1)
&& !has_fold
&& (*ptr != NUL
|| lcs_eol_one > 0
@@ -4373,7 +4142,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
n_attr = 0;
}
-
if (utf_char2cells(mb_c) > 1) {
// Need to fill two screen columns.
if (wp->w_p_rl) {
@@ -4428,9 +4196,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
* At end of screen line and there is more to come: Display the line
* so far. If there is no more to display it is caught above.
*/
- if ((wp->w_p_rl ? (col < 0) : (col >= grid->Columns))
+ if ((wp->w_p_rl ? (col < 0) : (col >= grid->cols))
&& foldinfo.fi_lines == 0
- && (*ptr != NUL
+ && (draw_state != WL_LINE
+ || *ptr != NUL
|| filler_todo > 0
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
&& p_extra != at_end_str)
@@ -4440,7 +4209,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& filler_todo <= 0 // Not drawing diff filler lines.
&& lcs_eol_one != -1 // Haven't printed the lcs_eol character.
&& row != endrow - 1 // Not the last line being displayed.
- && (grid->Columns == Columns // Window spans the width of the screen,
+ && (grid->cols == Columns // Window spans the width of the screen,
|| ui_has(kUIMultigrid)) // or has dedicated grid.
&& !wp->w_p_rl; // Not right-to-left.
@@ -4452,21 +4221,21 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
assert(i >= 0);
int offset = kv_A(virt_lines, i).left_col ? 0 : win_col_offset;
draw_virt_text_item(buf, offset, kv_A(virt_lines, i).line,
- kHlModeReplace, grid->Columns, offset);
+ kHlModeReplace, grid->cols, offset);
}
} else {
- draw_virt_text(buf, win_col_offset, &draw_col, grid->Columns);
+ draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, row);
}
- grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl,
+ grid_put_linebuf(grid, row, 0, draw_col, grid->cols, wp->w_p_rl,
wp, wp->w_hl_attr_normal, wrap);
if (wrap) {
ScreenGrid *current_grid = grid;
int current_row = row, dummy_col = 0; // dummy_col unused
- screen_adjust_grid(&current_grid, &current_row, &dummy_col);
+ grid_adjust(&current_grid, &current_row, &dummy_col);
// Force a redraw of the first column of the next line.
- current_grid->attrs[current_grid->line_offset[current_row+1]] = -1;
+ current_grid->attrs[current_grid->line_offset[current_row + 1]] = -1;
// Remember that the line wraps, used for modeless copy.
current_grid->line_wraps[current_row] = true;
@@ -4485,7 +4254,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// When the window is too narrow draw all "@" lines.
if (draw_state != WL_LINE && filler_todo <= 0) {
- win_draw_end(wp, '@', ' ', true, row, wp->w_grid.Rows, HLF_AT);
+ win_draw_end(wp, '@', ' ', true, row, wp->w_grid.rows, HLF_AT);
row = endrow;
}
@@ -4498,7 +4267,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
col = 0;
off = 0;
if (wp->w_p_rl) {
- col = grid->Columns - 1; // col is not used if breaking!
+ col = grid->cols - 1; // col is not used if breaking!
off += col;
}
@@ -4524,7 +4293,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
} // for every character in the line
// After an empty line check first word for capital.
- if (*skipwhite(line) == NUL) {
+ if (*skipwhite((char *)line) == NUL) {
capcol_lnum = lnum + 1;
cap_col = 0;
}
@@ -4534,14 +4303,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
return row;
}
-void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col)
+void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int max_col, int win_row)
{
DecorState *state = &decor_state;
int right_pos = max_col;
bool do_eol = state->eol_col > -1;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange *item = &kv_A(state->active, i);
- if (!(item->start_row == state->row && kv_size(item->decor.virt_text))) {
+ if (!(item->start_row == state->row
+ && (kv_size(item->decor.virt_text) || item->decor.ui_watched))) {
continue;
}
if (item->win_col == -1) {
@@ -4551,18 +4321,26 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col)
} else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
item->win_col = state->eol_col;
} else if (item->decor.virt_text_pos == kVTWinCol) {
- item->win_col = MAX(item->decor.col+col_off, 0);
+ item->win_col = MAX(item->decor.col + col_off, 0);
}
}
if (item->win_col < 0) {
continue;
}
-
- int col = draw_virt_text_item(buf, item->win_col, item->decor.virt_text,
- item->decor.hl_mode, max_col, item->win_col-col_off);
+ int col;
+ if (item->decor.ui_watched) {
+ // send mark position to UI
+ col = item->win_col;
+ WinExtmark m = { item->ns_id, item->mark_id, win_row, col };
+ kv_push(win_extmark_arr, m);
+ }
+ if (kv_size(item->decor.virt_text)) {
+ col = draw_virt_text_item(buf, item->win_col, item->decor.virt_text,
+ item->decor.hl_mode, max_col, item->win_col - col_off);
+ }
item->win_col = -2; // deactivate
if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
- state->eol_col = col+1;
+ state->eol_col = col + 1;
}
*end_col = MAX(*end_col, col);
@@ -4593,6 +4371,9 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
break;
}
}
+ if (!*s.p) {
+ continue;
+ }
int attr;
bool through = false;
if (hl_mode == kHlModeCombine) {
@@ -4605,7 +4386,7 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
}
schar_T dummy[2];
int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col],
- max_col-col, false, vcol);
+ max_col - col, false, vcol);
// if we failed to emit a char, we still need to advance
cells = MAX(cells, 1);
@@ -4617,25 +4398,6 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
return col;
}
-/// Determine if dedicated window grid should be used or the default_grid
-///
-/// If UI did not request multigrid support, draw all windows on the
-/// default_grid.
-///
-/// NB: this function can only been used with window grids in a context where
-/// win_grid_alloc already has been called!
-///
-/// If the default_grid is used, adjust window relative positions to global
-/// screen positions.
-void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off)
-{
- if ((*grid)->target) {
- *row_off += (*grid)->row_offset;
- *col_off += (*grid)->col_offset;
- *grid = (*grid)->target;
- }
-}
-
// Return true if CursorLineSign highlight is to be used.
static bool use_cursor_line_sign(win_T *wp, linenr_T lnum)
{
@@ -4644,18 +4406,65 @@ static bool use_cursor_line_sign(win_T *wp, linenr_T lnum)
&& (wp->w_p_culopt_flags & CULOPT_NBR);
}
+/// Return true if CursorLineNr highlight is to be used for the number column.
+///
+/// - 'cursorline' must be set
+/// - lnum must be the cursor line
+/// - 'cursorlineopt' has "number"
+/// - don't highlight filler lines (when in diff mode)
+/// - When line is wrapped and 'cursorlineopt' does not have "line", only highlight the line number
+/// itself on the first screenline of the wrapped line, otherwise highlight the number column of
+/// all screenlines of the wrapped line.
+static bool use_cursor_line_nr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines)
+{
+ return wp->w_p_cul
+ && lnum == wp->w_cursor.lnum
+ && (wp->w_p_culopt_flags & CULOPT_NBR)
+ && (row == startrow + filler_lines
+ || (row > startrow + filler_lines
+ && (wp->w_p_culopt_flags & CULOPT_LINE)));
+}
+
+static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines,
+ sign_attrs_T *sattrs)
+{
+ sign_attrs_T *num_sattr = sign_get_attr(SIGN_NUMHL, sattrs, 0, 1);
+ if (num_sattr != NULL) {
+ // :sign defined with "numhl" highlight.
+ return num_sattr->sat_numhl;
+ }
+
+ if (wp->w_p_rnu) {
+ if (lnum < wp->w_cursor.lnum) {
+ // Use LineNrAbove
+ return win_hl_attr(wp, HLF_LNA);
+ }
+ if (lnum > wp->w_cursor.lnum) {
+ // Use LineNrBelow
+ return win_hl_attr(wp, HLF_LNB);
+ }
+ }
+
+ if (use_cursor_line_nr(wp, lnum, row, startrow, filler_lines)) {
+ // TODO(vim): Can we use CursorLine instead of CursorLineNr
+ // when CursorLineNr isn't set?
+ return win_hl_attr(wp, HLF_CLN);
+ }
+
+ return win_hl_attr(wp, HLF_N);
+}
+
// Get information needed to display the sign in line 'lnum' in window 'wp'.
// If 'nrcol' is TRUE, the sign is going to be displayed in the number column.
// Otherwise the sign is going to be displayed in the sign column.
//
// @param count max number of signs
// @param[out] n_extrap number of characters from pp_extra to display
-// @param[in, out] sign_idxp Index of the displayed sign
+// @param sign_idxp Index of the displayed sign
static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_attrs_T sattrs[],
int row, int startrow, int filler_lines, int filler_todo,
- int count, int *c_extrap, int *c_finalp, char_u *extra,
- size_t extra_size, char_u **pp_extra, int *n_extrap,
- int *char_attrp, int *draw_statep, int *sign_idxp)
+ int *c_extrap, int *c_finalp, char_u *extra, size_t extra_size,
+ char_u **pp_extra, int *n_extrap, int *char_attrp, int sign_idx)
{
// Draw cells with the sign value or blank.
*c_extrap = ' ';
@@ -4672,7 +4481,7 @@ static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_att
}
if (row == startrow + filler_lines && filler_todo <= 0) {
- sign_attrs_T *sattr = sign_get_attr(SIGN_TEXT, sattrs, *sign_idxp, count);
+ sign_attrs_T *sattr = sign_get_attr(SIGN_TEXT, sattrs, sign_idx, wp->w_scwidth);
if (sattr != NULL) {
*pp_extra = sattr->sat_text;
if (*pp_extra != NULL) {
@@ -4694,10 +4503,10 @@ static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_att
// TODO(oni-link): Is sign text already extended to
// full cell width?
- assert((size_t)win_signcol_width(wp) >= mb_string2cells(*pp_extra));
+ assert((size_t)win_signcol_width(wp) >= mb_string2cells((char *)(*pp_extra)));
// symbol(s) bytes + (filling spaces) (one byte each)
*n_extrap = symbol_blen +
- (win_signcol_width(wp) - mb_string2cells(*pp_extra));
+ (win_signcol_width(wp) - mb_string2cells((char *)(*pp_extra)));
assert(extra_size > (size_t)symbol_blen);
memset(extra, ' ', extra_size);
@@ -4715,205 +4524,6 @@ static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_att
}
}
}
-
- (*sign_idxp)++;
- if (*sign_idxp < count) {
- *draw_statep = WL_SIGN - 1;
- } else {
- *sign_idxp = 0;
- }
-}
-
-
-/*
- * Check whether the given character needs redrawing:
- * - the (first byte of the) character is different
- * - the attributes are different
- * - the character is multi-byte and the next byte is different
- * - the character is two cells wide and the second cell differs.
- */
-static int grid_char_needs_redraw(ScreenGrid *grid, int off_from, int off_to, int cols)
-{
- return (cols > 0
- && ((schar_cmp(linebuf_char[off_from], grid->chars[off_to])
- || linebuf_attr[off_from] != grid->attrs[off_to]
- || (line_off2cells(linebuf_char, off_from, off_from + cols) > 1
- && schar_cmp(linebuf_char[off_from + 1],
- grid->chars[off_to + 1])))
- || rdb_flags & RDB_NODELTA));
-}
-
-/// Move one buffered line to the window grid, but only the characters that
-/// have actually changed. Handle insert/delete character.
-/// "coloff" gives the first column on the grid for this line.
-/// "endcol" gives the columns where valid characters are.
-/// "clear_width" is the width of the window. It's > 0 if the rest of the line
-/// needs to be cleared, negative otherwise.
-/// "rlflag" is TRUE in a rightleft window:
-/// When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
-/// When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
-/// If "wrap" is true, then hint to the UI that "row" contains a line
-/// which has wrapped into the next row.
-static void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int clear_width,
- int rlflag, win_T *wp, int bg_attr, bool wrap)
-{
- unsigned off_from;
- unsigned off_to;
- unsigned max_off_from;
- unsigned max_off_to;
- int col = 0;
- bool redraw_this; // Does character need redraw?
- bool redraw_next; // redraw_this for next character
- bool clear_next = false;
- int char_cells; // 1: normal char
- // 2: occupies two display cells
- int start_dirty = -1, end_dirty = 0;
-
- // TODO(bfredl): check all callsites and eliminate
- // Check for illegal row and col, just in case
- if (row >= grid->Rows) {
- row = grid->Rows - 1;
- }
- if (endcol > grid->Columns) {
- endcol = grid->Columns;
- }
-
- screen_adjust_grid(&grid, &row, &coloff);
-
- // Safety check. Avoids clang warnings down the call stack.
- if (grid->chars == NULL || row >= grid->Rows || coloff >= grid->Columns) {
- DLOG("invalid state, skipped");
- return;
- }
-
- off_from = 0;
- off_to = grid->line_offset[row] + coloff;
- max_off_from = linebuf_size;
- max_off_to = grid->line_offset[row] + grid->Columns;
-
- if (rlflag) {
- // Clear rest first, because it's left of the text.
- if (clear_width > 0) {
- while (col <= endcol && grid->chars[off_to][0] == ' '
- && grid->chars[off_to][1] == NUL
- && grid->attrs[off_to] == bg_attr) {
- ++off_to;
- ++col;
- }
- if (col <= endcol) {
- grid_fill(grid, row, row + 1, col + coloff, endcol + coloff + 1,
- ' ', ' ', bg_attr);
- }
- }
- col = endcol + 1;
- off_to = grid->line_offset[row] + col + coloff;
- off_from += col;
- endcol = (clear_width > 0 ? clear_width : -clear_width);
- }
-
- if (bg_attr) {
- for (int c = col; c < endcol; c++) {
- linebuf_attr[off_from+c] =
- hl_combine_attr(bg_attr, linebuf_attr[off_from+c]);
- }
- }
-
- redraw_next = grid_char_needs_redraw(grid, off_from, off_to, endcol - col);
-
- while (col < endcol) {
- char_cells = 1;
- if (col + 1 < endcol) {
- char_cells = line_off2cells(linebuf_char, off_from, max_off_from);
- }
- redraw_this = redraw_next;
- redraw_next = grid_char_needs_redraw(grid, off_from + char_cells,
- off_to + char_cells,
- endcol - col - char_cells);
-
- if (redraw_this) {
- if (start_dirty == -1) {
- start_dirty = col;
- }
- end_dirty = col + char_cells;
- // When writing a single-width character over a double-width
- // character and at the end of the redrawn text, need to clear out
- // the right half of the old character.
- // Also required when writing the right half of a double-width
- // char over the left half of an existing one
- if (col + char_cells == endcol
- && ((char_cells == 1
- && grid_off2cells(grid, off_to, max_off_to) > 1)
- || (char_cells == 2
- && grid_off2cells(grid, off_to, max_off_to) == 1
- && grid_off2cells(grid, off_to + 1, max_off_to) > 1))) {
- clear_next = true;
- }
-
- schar_copy(grid->chars[off_to], linebuf_char[off_from]);
- if (char_cells == 2) {
- schar_copy(grid->chars[off_to+1], linebuf_char[off_from+1]);
- }
-
- grid->attrs[off_to] = linebuf_attr[off_from];
- // For simplicity set the attributes of second half of a
- // double-wide character equal to the first half.
- if (char_cells == 2) {
- grid->attrs[off_to + 1] = linebuf_attr[off_from];
- }
- }
-
- off_to += char_cells;
- off_from += char_cells;
- col += char_cells;
- }
-
- if (clear_next) {
- // Clear the second half of a double-wide character of which the left
- // half was overwritten with a single-wide character.
- schar_from_ascii(grid->chars[off_to], ' ');
- end_dirty++;
- }
-
- int clear_end = -1;
- if (clear_width > 0 && !rlflag) {
- // blank out the rest of the line
- // TODO(bfredl): we could cache winline widths
- while (col < clear_width) {
- if (grid->chars[off_to][0] != ' '
- || grid->chars[off_to][1] != NUL
- || grid->attrs[off_to] != bg_attr) {
- grid->chars[off_to][0] = ' ';
- grid->chars[off_to][1] = NUL;
- grid->attrs[off_to] = bg_attr;
- if (start_dirty == -1) {
- start_dirty = col;
- end_dirty = col;
- } else if (clear_end == -1) {
- end_dirty = endcol;
- }
- clear_end = col+1;
- }
- col++;
- off_to++;
- }
- }
-
- if (clear_width > 0 || wp->w_width != grid->Columns) {
- // If we cleared after the end of the line, it did not wrap.
- // For vsplit, line wrapping is not possible.
- grid->line_wraps[row] = false;
- }
-
- if (clear_end < end_dirty) {
- clear_end = end_dirty;
- }
- if (start_dirty == -1) {
- start_dirty = end_dirty;
- }
- if (clear_end > start_dirty) {
- ui_line(grid, row, coloff+start_dirty, coloff+end_dirty, coloff+clear_end,
- bg_attr, wrap);
- }
}
/*
@@ -4932,30 +4542,34 @@ void rl_mirror(char_u *str)
}
}
-/*
- * mark all status lines for redraw; used after first :cd
- */
+/// Mark all status lines and window bars for redraw; used after first :cd
void status_redraw_all(void)
{
+ bool is_stl_global = global_stl_height() != 0;
+
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_status_height) {
+ 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);
}
}
}
-/// Marks all status lines of the current buffer for redraw.
+/// Marks all status lines and window bars of the current buffer for redraw.
void status_redraw_curbuf(void)
{
status_redraw_buf(curbuf);
}
-/// Marks all status lines of the specified buffer for redraw.
+/// Marks all status lines and window bars of the given buffer for redraw.
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_status_height != 0 && wp->w_buffer == 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);
}
@@ -4969,6 +4583,7 @@ void redraw_statuslines(void)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_redr_status) {
+ win_redr_winbar(wp);
win_redr_status(wp);
}
}
@@ -4999,10 +4614,8 @@ void win_redraw_last_status(const frame_T *frp)
}
}
-/*
- * Draw the verticap separator right of window "wp" starting with line "row".
- */
-static void draw_vsep_win(win_T *wp, int row)
+/// Draw the vertical separator right of window "wp"
+static void draw_vsep_win(win_T *wp)
{
int hl;
int c;
@@ -5010,15 +4623,97 @@ static void draw_vsep_win(win_T *wp, int row)
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 + row, W_ENDROW(wp),
+ 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);
+ }
+}
+
+/// Get the separator connector for specified window corner of window "wp"
+static int 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
+ if (vsep_connected(wp, corner)) {
+ if (hsep_connected(wp, corner)) {
+ return wp->w_p_fcs_chars.verthoriz;
+ } else if (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) {
+ return wp->w_p_fcs_chars.vertright;
+ } else {
+ return wp->w_p_fcs_chars.vertleft;
+ }
+ } else if (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) {
+ return wp->w_p_fcs_chars.horizdown;
+ } else {
+ return wp->w_p_fcs_chars.horizup;
+ }
+}
-/*
- * Get the length of an item as it will be shown in the status line.
- */
+/// Draw separator connecting characters on the corners of window "wp"
+static void draw_sep_connectors_win(win_T *wp)
+{
+ // Don't draw separator connectors unless global statusline is enabled and the window has
+ // either a horizontal or vertical separator
+ if (global_stl_height() == 0 || !(wp->w_hsep_height == 1 || wp->w_vsep_width == 1)) {
+ return;
+ }
+
+ int hl = win_hl_attr(wp, HLF_C);
+
+ // Determine which edges of the screen the window is located on so we can avoid drawing separators
+ // on corners contained in those edges
+ bool win_at_top;
+ bool win_at_bottom = wp->w_hsep_height == 0;
+ bool win_at_left;
+ bool win_at_right = wp->w_vsep_width == 0;
+ frame_T *frp;
+
+ for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
+ if (frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL) {
+ break;
+ }
+ }
+ win_at_top = frp->fr_parent == NULL;
+ for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
+ if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) {
+ break;
+ }
+ }
+ win_at_left = frp->fr_parent == NULL;
+
+ // Draw the appropriate separator connector in every corner where drawing them is necessary
+ if (!(win_at_top || win_at_left)) {
+ grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_TOP_LEFT),
+ wp->w_winrow - 1, wp->w_wincol - 1, hl);
+ }
+ if (!(win_at_top || win_at_right)) {
+ grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_TOP_RIGHT),
+ wp->w_winrow - 1, W_ENDCOL(wp), hl);
+ }
+ if (!(win_at_bottom || win_at_left)) {
+ grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_BOTTOM_LEFT),
+ W_ENDROW(wp), wp->w_wincol - 1, hl);
+ }
+ if (!(win_at_bottom || win_at_right)) {
+ grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_BOTTOM_RIGHT),
+ W_ENDROW(wp), W_ENDCOL(wp), hl);
+ }
+}
+
+/// Get the length of an item as it will be shown in the status line.
static int status_match_len(expand_T *xp, char_u *s)
{
int len = 0;
@@ -5027,13 +4722,13 @@ static int status_match_len(expand_T *xp, char_u *s)
|| xp->xp_context == EXPAND_MENUNAMES);
// Check for menu separators - replace with '|'.
- if (emenu && menu_is_separator(s)) {
+ if (emenu && menu_is_separator((char *)s)) {
return 1;
}
while (*s != NUL) {
s += skip_status_match_char(xp, s);
- len += ptr2cells(s);
+ len += ptr2cells((char *)s);
MB_PTR_ADV(s);
}
@@ -5153,7 +4848,7 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
clen = len;
i = first_match;
- while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns) {
+ while (clen + status_match_len(xp, L_MATCH(i)) + 2 < Columns) {
if (i == match) {
selstart = buf + len;
selstart_col = clen;
@@ -5163,7 +4858,7 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
// Check for menu separators - replace with '|'
emenu = (xp->xp_context == EXPAND_MENUS
|| xp->xp_context == EXPAND_MENUNAMES);
- if (emenu && menu_is_separator(s)) {
+ if (emenu && menu_is_separator((char *)s)) {
STRCPY(buf + len, transchar('|'));
l = (int)STRLEN(buf + len);
len += l;
@@ -5171,8 +4866,8 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
} else {
for (; *s != NUL; ++s) {
s += skip_status_match_char(xp, s);
- clen += ptr2cells(s);
- if ((l = utfc_ptr2len(s)) > 1) {
+ clen += ptr2cells((char *)s);
+ if ((l = utfc_ptr2len((char *)s)) > 1) {
STRNCPY(buf + len, s, l); // NOLINT(runtime/printf)
s += l - 1;
len += l;
@@ -5219,7 +4914,7 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
// Create status line if needed by setting 'laststatus' to 2.
// Set 'winminheight' to zero to avoid that the window is
// resized.
- if (lastwin->w_status_height == 0) {
+ if (lastwin->w_status_height == 0 && global_stl_height() == 0) {
save_p_ls = p_ls;
save_p_wmh = p_wmh;
p_ls = 2;
@@ -5255,12 +4950,15 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
static void win_redr_status(win_T *wp)
{
int row;
+ int col;
char_u *p;
int len;
int fillchar;
int attr;
+ int width;
int this_ru_col;
- static int busy = FALSE;
+ bool is_stl_global = global_stl_height() > 0;
+ static int busy = false;
// May get here recursively when 'statusline' (indirectly)
// invokes ":redrawstatus". Simply ignore the call then.
@@ -5271,9 +4969,9 @@ static void win_redr_status(win_T *wp)
}
busy = true;
- wp->w_redr_status = FALSE;
- if (wp->w_status_height == 0) {
- // no status line, can only be last window
+ wp->w_redr_status = false;
+ if (wp->w_status_height == 0 && !(is_stl_global && wp == curwin)) {
+ // no status line, either global statusline is enabled or the window is a last window
redraw_cmdline = true;
} else if (!redrawing()) {
// Don't redraw right now, do it later. Don't update status line when
@@ -5284,6 +4982,7 @@ static void win_redr_status(win_T *wp)
redraw_custom_statusline(wp);
} else {
fillchar = fillchar_status(&attr, wp);
+ width = is_stl_global ? Columns : wp->w_width;
get_trans_bufname(wp->w_buffer);
p = NameBuff;
@@ -5296,25 +4995,25 @@ static void win_redr_status(win_T *wp)
*(p + len++) = ' ';
}
if (bt_help(wp->w_buffer)) {
- STRCPY(p + len, _("[Help]"));
+ snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Help]"));
len += (int)STRLEN(p + len);
}
if (wp->w_p_pvw) {
- STRCPY(p + len, _("[Preview]"));
+ snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Preview]"));
len += (int)STRLEN(p + len);
}
if (bufIsChanged(wp->w_buffer)) {
- STRCPY(p + len, "[+]");
- len += 3;
+ snprintf((char *)p + len, MAXPATHL - len, "%s", "[+]");
+ len += (int)STRLEN(p + len);
}
if (wp->w_buffer->b_p_ro) {
- STRCPY(p + len, _("[RO]"));
+ snprintf((char *)p + len, MAXPATHL - len, "%s", _("[RO]"));
// len += (int)STRLEN(p + len); // dead assignment
}
- this_ru_col = ru_col - (Columns - wp->w_width);
- if (this_ru_col < (wp->w_width + 1) / 2) {
- this_ru_col = (wp->w_width + 1) / 2;
+ this_ru_col = ru_col - (Columns - width);
+ if (this_ru_col < (width + 1) / 2) {
+ this_ru_col = (width + 1) / 2;
}
if (this_ru_col <= 1) {
p = (char_u *)"<"; // No room for file name!
@@ -5323,13 +5022,13 @@ static void win_redr_status(win_T *wp)
int clen = 0, i;
// Count total number of display cells.
- clen = (int)mb_string2cells(p);
+ clen = (int)mb_string2cells((char *)p);
// Find first character that will fit.
// Going from start to end is much faster for DBCS.
for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
- i += utfc_ptr2len(p + i)) {
- clen -= utf_ptr2cells(p + i);
+ i += utfc_ptr2len((char *)p + i)) {
+ clen -= utf_ptr2cells((char *)p + i);
}
len = clen;
if (i > 0) {
@@ -5339,12 +5038,13 @@ static void win_redr_status(win_T *wp)
}
}
- row = W_ENDROW(wp);
- grid_puts(&default_grid, p, row, wp->w_wincol, attr);
- grid_fill(&default_grid, row, row + 1, len + wp->w_wincol,
- this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
+ row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
+ col = is_stl_global ? 0 : wp->w_wincol;
+ grid_puts(&default_grid, p, row, col, attr);
+ grid_fill(&default_grid, row, row + 1, len + col,
+ this_ru_col + col, fillchar, fillchar, attr);
- if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
+ if (get_keymap_str(wp, "<%s>", (char *)NameBuff, MAXPATHL)
&& this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) {
grid_puts(&default_grid, NameBuff, row,
(int)(this_ru_col - STRLEN(NameBuff) - 1), attr);
@@ -5384,12 +5084,12 @@ static void redraw_custom_statusline(win_T *wp)
entered = true;
did_emsg = false;
- win_redr_custom(wp, false);
+ win_redr_custom(wp, false, false);
if (did_emsg) {
// When there is an error disable the statusline, otherwise the
// display is messed up with errors and a redraw triggers the problem
// again and again.
- set_string_option_direct("statusline", -1, (char_u *)"",
+ set_string_option_direct("statusline", -1, "",
OPT_FREE | (*wp->w_p_stl != NUL
? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
}
@@ -5397,6 +5097,37 @@ static void redraw_custom_statusline(win_T *wp)
entered = false;
}
+static void win_redr_winbar(win_T *wp)
+{
+ static bool entered = false;
+
+ // Return when called recursively. This can happen when the winbar contains an expression
+ // that triggers a redraw.
+ if (entered) {
+ return;
+ }
+ entered = true;
+
+ if (wp->w_winbar_height == 0 || !redrawing()) {
+ // Do nothing.
+ } else if (*p_wbr != NUL || *wp->w_p_wbr != NUL) {
+ int saved_did_emsg = did_emsg;
+
+ did_emsg = false;
+ win_redr_custom(wp, true, false);
+ if (did_emsg) {
+ // When there is an error disable the winbar, otherwise the
+ // display is messed up with errors and a redraw triggers the problem
+ // again and again.
+ set_string_option_direct("winbar", -1, "",
+ OPT_FREE | (*wp->w_p_stl != NUL
+ ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
+ }
+ did_emsg |= saved_did_emsg;
+ }
+ entered = false;
+}
+
/// Only call if (wp->w_vsep_width != 0).
///
/// @return true if the status line of window "wp" is connected to the status
@@ -5421,15 +5152,85 @@ bool stl_connected(win_T *wp)
return false;
}
+/// Check if horizontal separator of window "wp" at specified window corner is connected to the
+/// horizontal separator of another window
+/// Assumes global statusline is enabled
+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);
+ frame_T *fr = wp->w_frame;
+
+ while (fr->fr_parent != NULL) {
+ if (fr->fr_parent->fr_layout == FR_ROW && (before ? fr->fr_prev : fr->fr_next) != NULL) {
+ fr = before ? fr->fr_prev : fr->fr_next;
+ break;
+ }
+ fr = fr->fr_parent;
+ }
+ if (fr->fr_parent == NULL) {
+ return false;
+ }
+ while (fr->fr_layout != FR_LEAF) {
+ fr = fr->fr_child;
+ if (fr->fr_parent->fr_layout == FR_ROW && before) {
+ while (fr->fr_next != NULL) {
+ fr = fr->fr_next;
+ }
+ } else {
+ while (fr->fr_next != NULL && frame2win(fr)->w_winrow + fr->fr_height < sep_row) {
+ fr = fr->fr_next;
+ }
+ }
+ }
+
+ return (sep_row == fr->fr_win->w_winrow - 1 || sep_row == W_ENDROW(fr->fr_win));
+}
+
+/// Check if vertical separator of window "wp" at specified window corner is connected to the
+/// vertical separator of another window
+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);
+ frame_T *fr = wp->w_frame;
+
+ while (fr->fr_parent != NULL) {
+ if (fr->fr_parent->fr_layout == FR_COL && (before ? fr->fr_prev : fr->fr_next) != NULL) {
+ fr = before ? fr->fr_prev : fr->fr_next;
+ break;
+ }
+ fr = fr->fr_parent;
+ }
+ if (fr->fr_parent == NULL) {
+ return false;
+ }
+ while (fr->fr_layout != FR_LEAF) {
+ fr = fr->fr_child;
+ if (fr->fr_parent->fr_layout == FR_COL && before) {
+ while (fr->fr_next != NULL) {
+ fr = fr->fr_next;
+ }
+ } else {
+ while (fr->fr_next != NULL && frame2win(fr)->w_wincol + fr->fr_width < sep_col) {
+ fr = fr->fr_next;
+ }
+ }
+ }
+
+ return (sep_col == fr->fr_win->w_wincol - 1 || sep_col == W_ENDCOL(fr->fr_win));
+}
/// Get the value to show for the language mappings, active 'keymap'.
///
/// @param fmt format string containing one %s item
/// @param buf buffer for the result
/// @param len length of buffer
-bool get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len)
+bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len)
{
- char_u *p;
+ char *p;
if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP) {
return false;
@@ -5438,7 +5239,7 @@ bool get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len)
{
buf_T *old_curbuf = curbuf;
win_T *old_curwin = curwin;
- char_u *s;
+ char *s;
curbuf = wp->w_buffer;
curwin = wp;
@@ -5450,12 +5251,12 @@ bool get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len)
curwin = old_curwin;
if (p == NULL || *p == NUL) {
if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED) {
- p = wp->w_buffer->b_p_keymap;
+ p = (char *)wp->w_buffer->b_p_keymap;
} else {
- p = (char_u *)"lang";
+ p = "lang";
}
}
- if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1) {
+ if (vim_snprintf(buf, len, fmt, p) > len - 1) {
buf[0] = NUL;
}
xfree(s);
@@ -5463,11 +5264,9 @@ bool get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len)
return buf[0] != NUL;
}
-/*
- * Redraw the status line or ruler of window "wp".
- * When "wp" is NULL redraw the tab pages line from 'tabline'.
- */
-static void win_redr_custom(win_T *wp, bool draw_ruler)
+/// Redraw the status line, window bar or ruler of window "wp".
+/// When "wp" is NULL redraw the tab pages line from 'tabline'.
+static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
{
static bool entered = false;
int attr;
@@ -5479,14 +5278,15 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
int n;
int len;
int fillchar;
- char_u buf[MAXPATHL];
+ char buf[MAXPATHL];
char_u *stl;
- char_u *p;
+ char *p;
stl_hlrec_t *hltab;
StlClickRecord *tabtab;
int use_sandbox = false;
win_T *ewp;
int p_crb_save;
+ bool is_stl_global = global_stl_height() > 0;
ScreenGrid *grid = &default_grid;
@@ -5507,10 +5307,41 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
attr = HL_ATTR(HLF_TPF);
maxwidth = Columns;
use_sandbox = was_set_insecurely(wp, "tabline", 0);
+ } else if (draw_winbar) {
+ stl = (char_u *)((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr);
+ row = -1; // row zero is first row of text
+ col = 0;
+ grid = &wp->w_grid;
+ grid_adjust(&grid, &row, &col);
+
+ if (row < 0) {
+ return;
+ }
+
+ fillchar = wp->w_p_fcs_chars.wbr;
+ attr = (wp == curwin) ? win_hl_attr(wp, HLF_WBR) : win_hl_attr(wp, HLF_WBRNC);
+ maxwidth = wp->w_width_inner;
+ use_sandbox = was_set_insecurely(wp, "winbar", 0);
+
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ // Allocate / resize the click definitions array for winbar if needed.
+ if (wp->w_winbar_height && wp->w_winbar_click_defs_size < (size_t)maxwidth) {
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = (size_t)maxwidth;
+ wp->w_winbar_click_defs = xcalloc(wp->w_winbar_click_defs_size, sizeof(StlClickRecord));
+ }
} else {
- row = W_ENDROW(wp);
+ row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
fillchar = fillchar_status(&attr, wp);
- maxwidth = wp->w_width;
+ maxwidth = is_stl_global ? Columns : wp->w_width;
+
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ // Allocate / resize the click definitions array for statusline if needed.
+ if (wp->w_status_click_defs_size < (size_t)maxwidth) {
+ xfree(wp->w_status_click_defs);
+ wp->w_status_click_defs_size = maxwidth;
+ wp->w_status_click_defs = xcalloc(wp->w_status_click_defs_size, sizeof(StlClickRecord));
+ }
if (draw_ruler) {
stl = p_ruf;
@@ -5528,12 +5359,12 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
stl = p_ruf;
}
}
- col = ru_col - (Columns - wp->w_width);
- if (col < (wp->w_width + 1) / 2) {
- col = (wp->w_width + 1) / 2;
+ col = ru_col - (Columns - maxwidth);
+ if (col < (maxwidth + 1) / 2) {
+ col = (maxwidth + 1) / 2;
}
- maxwidth = wp->w_width - col;
- if (!wp->w_status_height) {
+ maxwidth = maxwidth - col;
+ if (!wp->w_status_height && !is_stl_global) {
grid = &msg_grid_adj;
row = Rows - 1;
maxwidth--; // writing in last column may cause scrolling
@@ -5551,7 +5382,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
use_sandbox = was_set_insecurely(wp, "statusline", *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
}
- col += wp->w_wincol;
+ col += is_stl_global ? 0 : wp->w_wincol;
}
if (maxwidth <= 0) {
@@ -5568,13 +5399,13 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
* might change the option value and free the memory. */
stl = vim_strsave(stl);
width =
- build_stl_str_hl(ewp, buf, sizeof(buf), stl, use_sandbox,
+ build_stl_str_hl(ewp, buf, sizeof(buf), (char *)stl, use_sandbox,
fillchar, maxwidth, &hltab, &tabtab);
xfree(stl);
ewp->w_p_crb = p_crb_save;
// Make all characters printable.
- p = (char_u *)transstr((const char *)buf, true);
+ p = transstr(buf, true);
len = STRLCPY(buf, p, sizeof(buf));
len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1;
xfree(p);
@@ -5595,8 +5426,8 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
p = buf;
for (n = 0; hltab[n].start != NULL; n++) {
int textlen = (int)(hltab[n].start - p);
- grid_puts_len(grid, p, textlen, row, col, curattr);
- col += vim_strnsize(p, textlen);
+ grid_puts_len(grid, (char_u *)p, textlen, row, col, curattr);
+ col += vim_strnsize((char_u *)p, textlen);
p = hltab[n].start;
if (hltab[n].userhl == 0) {
@@ -5610,31 +5441,43 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
}
}
// Make sure to use an empty string instead of p, if p is beyond buf + len.
- grid_puts(grid, p >= buf + len ? (char_u *)"" : p, row, col,
+ grid_puts(grid, p >= buf + len ? (char_u *)"" : (char_u *)p, row, col,
curattr);
grid_puts_line_flush(false);
- if (wp == NULL) {
- // Fill the tab_page_click_defs array for clicking in the tab pages line.
- col = 0;
- len = 0;
- p = buf;
- StlClickDefinition cur_click_def = {
- .type = kStlClickDisabled,
- };
- for (n = 0; tabtab[n].start != NULL; n++) {
- len += vim_strnsize(p, (int)(tabtab[n].start - (char *)p));
- while (col < len) {
- tab_page_click_defs[col++] = cur_click_def;
- }
- p = (char_u *)tabtab[n].start;
- cur_click_def = tabtab[n].def;
+ // Fill the tab_page_click_defs, w_status_click_defs or w_winbar_click_defs array for clicking
+ // in the tab page line, status line or window bar
+ StlClickDefinition *click_defs = (wp == NULL) ? tab_page_click_defs
+ : draw_winbar ? wp->w_winbar_click_defs
+ : wp->w_status_click_defs;
+
+ if (click_defs == NULL) {
+ goto theend;
+ }
+
+ col = 0;
+ len = 0;
+ p = buf;
+ StlClickDefinition cur_click_def = {
+ .type = kStlClickDisabled,
+ };
+ for (n = 0; tabtab[n].start != NULL; n++) {
+ len += vim_strnsize((char_u *)p, (int)(tabtab[n].start - p));
+ while (col < len) {
+ click_defs[col++] = cur_click_def;
}
- while (col < Columns) {
- tab_page_click_defs[col++] = cur_click_def;
+ p = (char *)tabtab[n].start;
+ cur_click_def = tabtab[n].def;
+ if ((wp != NULL) && !(cur_click_def.type == kStlClickDisabled
+ || cur_click_def.type == kStlClickFuncRun)) {
+ // window bar and status line only support click functions
+ cur_click_def.type = kStlClickDisabled;
}
}
+ while (col < maxwidth) {
+ click_defs[col++] = cur_click_def;
+ }
theend:
entered = false;
@@ -5653,9 +5496,9 @@ static void win_redr_border(win_T *wp)
int *attrs = wp->w_float_config.border_attr;
int *adj = wp->w_border_adj;
- int irow = wp->w_height_inner, icol = wp->w_width_inner;
+ int irow = wp->w_height_inner + wp->w_winbar_height, icol = wp->w_width_inner;
- char_u* title = wp->w_float_config.title;
+ char* title = wp->w_float_config.title;
size_t n_title = wp->w_float_config.n_title;
stl_hlrec_t* title_hl = wp->w_float_config.title_hl;
@@ -5691,7 +5534,7 @@ static void win_redr_border(win_T *wp)
int attr;
// Draw the title if in the correct position.
if (i > title_pos && n_title > 0 && i < icol - 2) {
- cc = utfc_ptr2char(title, m8);
+ cc = utfc_ptr2char((char_u*) title, m8);
len = utfc_ptr2len(title);
n_title -= len;
title += len;
@@ -5709,373 +5552,44 @@ static void win_redr_border(win_T *wp)
memcpy(ch, chars[1], sizeof(schar_T));
attr = attrs[1];
}
- grid_put_schar(grid, 0, i+adj[3], ch, attr);
+ grid_put_schar(grid, 0, i + adj[3], ch, attr);
}
if (adj[1]) {
- grid_put_schar(grid, 0, icol+adj[3], chars[2], attrs[2]);
+ grid_put_schar(grid, 0, icol + adj[3], chars[2], attrs[2]);
}
grid_puts_line_flush(false);
}
for (int i = 0; i < irow; i++) {
if (adj[3]) {
- grid_puts_line_start(grid, i+adj[0]);
- grid_put_schar(grid, i+adj[0], 0, chars[7], attrs[7]);
+ grid_puts_line_start(grid, i + adj[0]);
+ grid_put_schar(grid, i + adj[0], 0, chars[7], attrs[7]);
grid_puts_line_flush(false);
}
if (adj[1]) {
int ic = (i == 0 && !adj[0] && chars[2][0]) ? 2 : 3;
- grid_puts_line_start(grid, i+adj[0]);
- grid_put_schar(grid, i+adj[0], icol+adj[3], chars[ic], attrs[ic]);
+ grid_puts_line_start(grid, i + adj[0]);
+ grid_put_schar(grid, i + adj[0], icol + adj[3], chars[ic], attrs[ic]);
grid_puts_line_flush(false);
}
}
if (adj[2]) {
- grid_puts_line_start(grid, irow+adj[0]);
+ grid_puts_line_start(grid, irow + adj[0]);
if (adj[3]) {
- grid_put_schar(grid, irow+adj[0], 0, chars[6], attrs[6]);
+ grid_put_schar(grid, irow + adj[0], 0, chars[6], attrs[6]);
}
for (int i = 0; i < icol; i++) {
int ic = (i == 0 && !adj[3] && chars[6][0]) ? 6 : 5;
- grid_put_schar(grid, irow+adj[0], i+adj[3], chars[ic], attrs[ic]);
+ grid_put_schar(grid, irow + adj[0], i + adj[3], chars[ic], attrs[ic]);
}
if (adj[1]) {
- grid_put_schar(grid, irow+adj[0], icol+adj[3], chars[4], attrs[4]);
+ grid_put_schar(grid, irow + adj[0], icol + adj[3], chars[4], attrs[4]);
}
grid_puts_line_flush(false);
}
}
-// Low-level functions to manipulate individual character cells on the
-// screen grid.
-
-/// Put a ASCII character in a screen cell.
-static void schar_from_ascii(char_u *p, const char c)
-{
- p[0] = c;
- p[1] = 0;
-}
-
-/// Put a unicode character in a screen cell.
-static int schar_from_char(char_u *p, int c)
-{
- int len = utf_char2bytes(c, p);
- p[len] = NUL;
- return len;
-}
-
-/// Put a unicode char, and up to MAX_MCO composing chars, in a screen cell.
-static int schar_from_cc(char_u *p, int c, int u8cc[MAX_MCO])
-{
- int len = utf_char2bytes(c, p);
- for (int i = 0; i < MAX_MCO; i++) {
- if (u8cc[i] == 0) {
- break;
- }
- len += utf_char2bytes(u8cc[i], p + len);
- }
- p[len] = 0;
- return len;
-}
-
-/// compare the contents of two screen cells.
-static int schar_cmp(char_u *sc1, char_u *sc2)
-{
- return STRNCMP(sc1, sc2, sizeof(schar_T));
-}
-
-/// copy the contents of screen cell `sc2` into cell `sc1`
-static void schar_copy(char_u *sc1, char_u *sc2)
-{
- STRLCPY(sc1, sc2, sizeof(schar_T));
-}
-
-static int line_off2cells(schar_T *line, size_t off, size_t max_off)
-{
- return (off + 1 < max_off && line[off + 1][0] == 0) ? 2 : 1;
-}
-
-/// Return number of display cells for char at grid->chars[off].
-/// We make sure that the offset used is less than "max_off".
-static int grid_off2cells(ScreenGrid *grid, size_t off, size_t max_off)
-{
- return line_off2cells(grid->chars, off, max_off);
-}
-
-/// Return true if the character at "row"/"col" on the screen is the left side
-/// of a double-width character.
-///
-/// Caller must make sure "row" and "col" are not invalid!
-bool grid_lefthalve(ScreenGrid *grid, int row, int col)
-{
- screen_adjust_grid(&grid, &row, &col);
-
- return grid_off2cells(grid, grid->line_offset[row] + col,
- grid->line_offset[row] + grid->Columns) > 1;
-}
-
-/// Correct a position on the screen, if it's the right half of a double-wide
-/// char move it to the left half. Returns the corrected column.
-int grid_fix_col(ScreenGrid *grid, int col, int row)
-{
- int coloff = 0;
- screen_adjust_grid(&grid, &row, &coloff);
-
- col += coloff;
- if (grid->chars != NULL && col > 0
- && grid->chars[grid->line_offset[row] + col][0] == 0) {
- return col - 1 - coloff;
- }
- return col - coloff;
-}
-
-/// output a single character directly to the grid
-void grid_putchar(ScreenGrid *grid, int c, int row, int col, int attr)
-{
- char_u buf[MB_MAXBYTES + 1];
-
- buf[utf_char2bytes(c, buf)] = NUL;
- grid_puts(grid, buf, row, col, attr);
-}
-
-/// get a single character directly from grid.chars into "bytes[]".
-/// Also return its attribute in *attrp;
-void grid_getbytes(ScreenGrid *grid, int row, int col, char_u *bytes, int *attrp)
-{
- unsigned off;
-
- screen_adjust_grid(&grid, &row, &col);
-
- // safety check
- if (grid->chars != NULL && row < grid->Rows && col < grid->Columns) {
- off = grid->line_offset[row] + col;
- *attrp = grid->attrs[off];
- schar_copy(bytes, grid->chars[off]);
- }
-}
-
-
-/// put string '*text' on the window grid at position 'row' and 'col', with
-/// attributes 'attr', and update chars[] and attrs[].
-/// Note: only outputs within one row, message is truncated at grid boundary!
-/// Note: if grid, row and/or col is invalid, nothing is done.
-void grid_puts(ScreenGrid *grid, char_u *text, int row, int col, int attr)
-{
- grid_puts_len(grid, text, -1, row, col, attr);
-}
-
-static ScreenGrid *put_dirty_grid = NULL;
-static int put_dirty_row = -1;
-static int put_dirty_first = INT_MAX;
-static int put_dirty_last = 0;
-
-/// Start a group of grid_puts_len calls that builds a single grid line.
-///
-/// Must be matched with a grid_puts_line_flush call before moving to
-/// another line.
-void grid_puts_line_start(ScreenGrid *grid, int row)
-{
- int col = 0; // unused
- screen_adjust_grid(&grid, &row, &col);
- assert(put_dirty_row == -1);
- put_dirty_row = row;
- put_dirty_grid = grid;
-}
-
-void grid_put_schar(ScreenGrid *grid, int row, int col, char_u *schar, int attr)
-{
- assert(put_dirty_row == row);
- unsigned int off = grid->line_offset[row] + col;
- if (grid->attrs[off] != attr || schar_cmp(grid->chars[off], schar)) {
- schar_copy(grid->chars[off], schar);
- grid->attrs[off] = attr;
-
- put_dirty_first = MIN(put_dirty_first, col);
- // TODO(bfredl): Y U NO DOUBLEWIDTH?
- put_dirty_last = MAX(put_dirty_last, col+1);
- }
-}
-
-/// like grid_puts(), but output "text[len]". When "len" is -1 output up to
-/// a NUL.
-void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col, int attr)
-{
- unsigned off;
- char_u *ptr = text;
- int len = textlen;
- int c;
- unsigned max_off;
- int mbyte_blen = 1;
- int mbyte_cells = 1;
- int u8c = 0;
- int u8cc[MAX_MCO];
- int clear_next_cell = FALSE;
- int prev_c = 0; // previous Arabic character
- int pc, nc, nc1;
- int pcc[MAX_MCO];
- int need_redraw;
- bool do_flush = false;
-
- screen_adjust_grid(&grid, &row, &col);
-
- // Safety check. The check for negative row and column is to fix issue
- // vim/vim#4102. TODO(neovim): find out why row/col could be negative.
- if (grid->chars == NULL
- || row >= grid->Rows || row < 0
- || col >= grid->Columns || col < 0) {
- return;
- }
-
- if (put_dirty_row == -1) {
- grid_puts_line_start(grid, row);
- do_flush = true;
- } else {
- if (grid != put_dirty_grid || row != put_dirty_row) {
- abort();
- }
- }
- off = grid->line_offset[row] + col;
-
- // When drawing over the right half of a double-wide char clear out the
- // left half. Only needed in a terminal.
- if (grid != &default_grid && col == 0 && grid_invalid_row(grid, row)) {
- // redraw the previous cell, make it empty
- put_dirty_first = -1;
- put_dirty_last = MAX(put_dirty_last, 1);
- }
-
- max_off = grid->line_offset[row] + grid->Columns;
- while (col < grid->Columns
- && (len < 0 || (int)(ptr - text) < len)
- && *ptr != NUL) {
- c = *ptr;
- // check if this is the first byte of a multibyte
- if (len > 0) {
- mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
- } else {
- mbyte_blen = utfc_ptr2len(ptr);
- }
- if (len >= 0) {
- u8c = utfc_ptr2char_len(ptr, u8cc, (int)((text + len) - ptr));
- } else {
- u8c = utfc_ptr2char(ptr, u8cc);
- }
- mbyte_cells = utf_char2cells(u8c);
- if (p_arshape && !p_tbidi && arabic_char(u8c)) {
- // Do Arabic shaping.
- if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len) {
- // Past end of string to be displayed.
- nc = NUL;
- nc1 = NUL;
- } else {
- nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
- (int)((text + len) - ptr - mbyte_blen));
- nc1 = pcc[0];
- }
- pc = prev_c;
- prev_c = u8c;
- u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
- } else {
- prev_c = u8c;
- }
- if (col + mbyte_cells > grid->Columns) {
- // Only 1 cell left, but character requires 2 cells:
- // display a '>' in the last column to avoid wrapping. */
- c = '>';
- u8c = '>';
- u8cc[0] = 0;
- mbyte_cells = 1;
- }
-
- schar_T buf;
- schar_from_cc(buf, u8c, u8cc);
-
-
- need_redraw = schar_cmp(grid->chars[off], buf)
- || (mbyte_cells == 2 && grid->chars[off + 1][0] != 0)
- || grid->attrs[off] != attr
- || exmode_active;
-
- if (need_redraw) {
- // When at the end of the text and overwriting a two-cell
- // character with a one-cell character, need to clear the next
- // cell. Also when overwriting the left half of a two-cell char
- // with the right half of a two-cell char. Do this only once
- // (utf8_off2cells() may return 2 on the right half).
- if (clear_next_cell) {
- clear_next_cell = false;
- } else if ((len < 0 ? ptr[mbyte_blen] == NUL
- : ptr + mbyte_blen >= text + len)
- && ((mbyte_cells == 1
- && grid_off2cells(grid, off, max_off) > 1)
- || (mbyte_cells == 2
- && grid_off2cells(grid, off, max_off) == 1
- && grid_off2cells(grid, off + 1, max_off) > 1))) {
- clear_next_cell = true;
- }
-
- // When at the start of the text and overwriting the right half of a
- // two-cell character in the same grid, truncate that into a '>'.
- if (ptr == text && col > 0 && grid->chars[off][0] == 0) {
- grid->chars[off - 1][0] = '>';
- grid->chars[off - 1][1] = 0;
- }
-
- schar_copy(grid->chars[off], buf);
- grid->attrs[off] = attr;
- if (mbyte_cells == 2) {
- grid->chars[off + 1][0] = 0;
- grid->attrs[off + 1] = attr;
- }
- put_dirty_first = MIN(put_dirty_first, col);
- put_dirty_last = MAX(put_dirty_last, col+mbyte_cells);
- }
-
- off += mbyte_cells;
- col += mbyte_cells;
- ptr += mbyte_blen;
- if (clear_next_cell) {
- // This only happens at the end, display one space next.
- ptr = (char_u *)" ";
- len = -1;
- }
- }
-
- if (do_flush) {
- grid_puts_line_flush(true);
- }
-}
-
-/// End a group of grid_puts_len calls and send the screen buffer to the UI
-/// layer.
-///
-/// @param set_cursor Move the visible cursor to the end of the changed region.
-/// This is a workaround for not yet refactored code paths
-/// and shouldn't be used in new code.
-void grid_puts_line_flush(bool set_cursor)
-{
- assert(put_dirty_row != -1);
- if (put_dirty_first < put_dirty_last) {
- if (set_cursor) {
- ui_grid_cursor_goto(put_dirty_grid->handle, put_dirty_row,
- MIN(put_dirty_last, put_dirty_grid->Columns-1));
- }
- if (!put_dirty_grid->throttled) {
- ui_line(put_dirty_grid, put_dirty_row, put_dirty_first, put_dirty_last,
- put_dirty_last, 0, false);
- } else if (put_dirty_grid->dirty_col) {
- if (put_dirty_last > put_dirty_grid->dirty_col[put_dirty_row]) {
- put_dirty_grid->dirty_col[put_dirty_row] = put_dirty_last;
- }
- }
- put_dirty_first = INT_MAX;
- put_dirty_last = 0;
- }
- put_dirty_row = -1;
- put_dirty_grid = NULL;
-}
-
/*
* Prepare for 'hlsearch' highlighting.
*/
@@ -6100,372 +5614,6 @@ static void end_search_hl(void)
}
}
-
-/*
- * Init for calling prepare_search_hl().
- */
-static void init_search_hl(win_T *wp)
- FUNC_ATTR_NONNULL_ALL
-{
- // Setup for match and 'hlsearch' highlighting. Disable any previous
- // match
- matchitem_T *cur = wp->w_match_head;
- while (cur != NULL) {
- cur->hl.rm = cur->match;
- if (cur->hlg_id == 0) {
- cur->hl.attr = 0;
- } else {
- cur->hl.attr = syn_id2attr(cur->hlg_id);
- }
- cur->hl.buf = wp->w_buffer;
- cur->hl.lnum = 0;
- cur->hl.first_lnum = 0;
- // Set the time limit to 'redrawtime'.
- cur->hl.tm = profile_setlimit(p_rdt);
- cur = cur->next;
- }
- search_hl.buf = wp->w_buffer;
- search_hl.lnum = 0;
- search_hl.first_lnum = 0;
- search_hl.attr = win_hl_attr(wp, HLF_L);
-
- // time limit is set at the toplevel, for all windows
-}
-
-/*
- * Advance to the match in window "wp" line "lnum" or past it.
- */
-static void prepare_search_hl(win_T *wp, linenr_T lnum)
- FUNC_ATTR_NONNULL_ALL
-{
- matchitem_T *cur; // points to the match list
- match_T *shl; // points to search_hl or a match
- bool shl_flag; // flag to indicate whether search_hl
- // has been processed or not
-
- // When using a multi-line pattern, start searching at the top
- // of the window or just after a closed fold.
- // Do this both for search_hl and the match list.
- cur = wp->w_match_head;
- shl_flag = false;
- while (cur != NULL || shl_flag == false) {
- if (shl_flag == false) {
- shl = &search_hl;
- shl_flag = true;
- } else {
- shl = &cur->hl; // -V595
- }
- if (shl->rm.regprog != NULL
- && shl->lnum == 0
- && re_multiline(shl->rm.regprog)) {
- if (shl->first_lnum == 0) {
- for (shl->first_lnum = lnum;
- shl->first_lnum > wp->w_topline;
- shl->first_lnum--) {
- if (hasFoldingWin(wp, shl->first_lnum - 1, NULL, NULL, true, NULL)) {
- break;
- }
- }
- }
- if (cur != NULL) {
- cur->pos.cur = 0;
- }
- bool pos_inprogress = true; // mark that a position match search is
- // in progress
- int n = 0;
- while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
- || (cur != NULL && pos_inprogress))) {
- next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n,
- shl == &search_hl ? NULL : cur);
- pos_inprogress = !(cur == NULL || cur->pos.cur == 0);
- if (shl->lnum != 0) {
- shl->first_lnum = shl->lnum
- + shl->rm.endpos[0].lnum
- - shl->rm.startpos[0].lnum;
- n = shl->rm.endpos[0].col;
- } else {
- ++shl->first_lnum;
- n = 0;
- }
- }
- }
- if (shl != &search_hl && cur != NULL) {
- cur = cur->next;
- }
- }
-}
-
-/// Search for a next 'hlsearch' or match.
-/// Uses shl->buf.
-/// Sets shl->lnum and shl->rm contents.
-/// Note: Assumes a previous match is always before "lnum", unless
-/// shl->lnum is zero.
-/// Careful: Any pointers for buffer lines will become invalid.
-///
-/// @param shl points to search_hl or a match
-/// @param mincol minimal column for a match
-/// @param cur to retrieve match positions if any
-static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol,
- matchitem_T *cur)
- FUNC_ATTR_NONNULL_ARG(2)
-{
- linenr_T l;
- colnr_T matchcol;
- long nmatched = 0;
- int save_called_emsg = called_emsg;
-
- // for :{range}s/pat only highlight inside the range
- if (lnum < search_first_line || lnum > search_last_line) {
- shl->lnum = 0;
- return;
- }
-
- if (shl->lnum != 0) {
- // Check for three situations:
- // 1. If the "lnum" is below a previous match, start a new search.
- // 2. If the previous match includes "mincol", use it.
- // 3. Continue after the previous match.
- l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
- if (lnum > l) {
- shl->lnum = 0;
- } else if (lnum < l || shl->rm.endpos[0].col > mincol) {
- return;
- }
- }
-
- /*
- * Repeat searching for a match until one is found that includes "mincol"
- * or none is found in this line.
- */
- called_emsg = FALSE;
- for (;;) {
- // Stop searching after passing the time limit.
- if (profile_passed_limit(shl->tm)) {
- shl->lnum = 0; // no match found in time
- break;
- }
- // Three situations:
- // 1. No useful previous match: search from start of line.
- // 2. Not Vi compatible or empty match: continue at next character.
- // Break the loop if this is beyond the end of the line.
- // 3. Vi compatible searching: continue at end of previous match.
- if (shl->lnum == 0) {
- matchcol = 0;
- } else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
- || (shl->rm.endpos[0].lnum == 0
- && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) {
- char_u *ml;
-
- matchcol = shl->rm.startpos[0].col;
- ml = ml_get_buf(shl->buf, lnum, false) + matchcol;
- if (*ml == NUL) {
- ++matchcol;
- shl->lnum = 0;
- break;
- }
- matchcol += utfc_ptr2len(ml);
- } else {
- matchcol = shl->rm.endpos[0].col;
- }
-
- shl->lnum = lnum;
- if (shl->rm.regprog != NULL) {
- // Remember whether shl->rm is using a copy of the regprog in
- // cur->match.
- bool regprog_is_copy = (shl != &search_hl
- && cur != NULL
- && shl == &cur->hl
- && cur->match.regprog == cur->hl.rm.regprog);
- int timed_out = false;
-
- nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol,
- &(shl->tm), &timed_out);
- // Copy the regprog, in case it got freed and recompiled.
- if (regprog_is_copy) {
- cur->match.regprog = cur->hl.rm.regprog;
- }
- if (called_emsg || got_int || timed_out) {
- // Error while handling regexp: stop using this regexp.
- if (shl == &search_hl) {
- // don't free regprog in the match list, it's a copy
- vim_regfree(shl->rm.regprog);
- set_no_hlsearch(true);
- }
- shl->rm.regprog = NULL;
- shl->lnum = 0;
- got_int = FALSE; // avoid the "Type :quit to exit Vim" message
- break;
- }
- } else if (cur != NULL) {
- nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
- }
- if (nmatched == 0) {
- shl->lnum = 0; // no match found
- break;
- }
- if (shl->rm.startpos[0].lnum > 0
- || shl->rm.startpos[0].col >= mincol
- || nmatched > 1
- || shl->rm.endpos[0].col > mincol) {
- shl->lnum += shl->rm.startpos[0].lnum;
- break; // useful match found
- }
-
- // Restore called_emsg for assert_fails().
- called_emsg = save_called_emsg;
- }
-}
-
-/// @param shl points to a match. Fill on match.
-/// @param posmatch match positions
-/// @param mincol minimal column for a match
-///
-/// @return one on match, otherwise return zero.
-static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *posmatch, colnr_T mincol)
- FUNC_ATTR_NONNULL_ALL
-{
- int i;
- int found = -1;
-
- shl->lnum = 0;
- for (i = posmatch->cur; i < MAXPOSMATCH; i++) {
- llpos_T *pos = &posmatch->pos[i];
-
- if (pos->lnum == 0) {
- break;
- }
- if (pos->len == 0 && pos->col < mincol) {
- continue;
- }
- if (pos->lnum == lnum) {
- if (found >= 0) {
- // if this match comes before the one at "found" then swap
- // them
- if (pos->col < posmatch->pos[found].col) {
- llpos_T tmp = *pos;
-
- *pos = posmatch->pos[found];
- posmatch->pos[found] = tmp;
- }
- } else {
- found = i;
- }
- }
- }
- posmatch->cur = 0;
- if (found >= 0) {
- colnr_T start = posmatch->pos[found].col == 0
- ? 0: posmatch->pos[found].col - 1;
- colnr_T end = posmatch->pos[found].col == 0
- ? MAXCOL : start + posmatch->pos[found].len;
-
- shl->lnum = lnum;
- shl->rm.startpos[0].lnum = 0;
- shl->rm.startpos[0].col = start;
- shl->rm.endpos[0].lnum = 0;
- shl->rm.endpos[0].col = end;
- shl->is_addpos = true;
- posmatch->cur = found + 1;
- return 1;
- }
- return 0;
-}
-
-
-/// Fill the grid from 'start_row' to 'end_row', from 'start_col' to 'end_col'
-/// with character 'c1' in first column followed by 'c2' in the other columns.
-/// Use attributes 'attr'.
-void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int end_col, int c1,
- int c2, int attr)
-{
- schar_T sc;
-
- int row_off = 0, col_off = 0;
- screen_adjust_grid(&grid, &row_off, &col_off);
- start_row += row_off;
- end_row += row_off;
- start_col += col_off;
- end_col += col_off;
-
- // safety check
- if (end_row > grid->Rows) {
- end_row = grid->Rows;
- }
- if (end_col > grid->Columns) {
- end_col = grid->Columns;
- }
-
- // nothing to do
- if (start_row >= end_row || start_col >= end_col) {
- return;
- }
-
- for (int row = start_row; row < end_row; row++) {
- // When drawing over the right half of a double-wide char clear
- // out the left half. When drawing over the left half of a
- // double wide-char clear out the right half. Only needed in a
- // terminal.
- if (start_col > 0 && grid_fix_col(grid, start_col, row) != start_col) {
- grid_puts_len(grid, (char_u *)" ", 1, row, start_col - 1, 0);
- }
- if (end_col < grid->Columns
- && grid_fix_col(grid, end_col, row) != end_col) {
- grid_puts_len(grid, (char_u *)" ", 1, row, end_col, 0);
- }
-
- // if grid was resized (in ext_multigrid mode), the UI has no redraw updates
- // for the newly resized grid. It is better mark everything as dirty and
- // send all the updates.
- int dirty_first = INT_MAX;
- int dirty_last = 0;
-
- int col = start_col;
- schar_from_char(sc, c1);
- int lineoff = grid->line_offset[row];
- for (col = start_col; col < end_col; col++) {
- int off = lineoff + col;
- if (schar_cmp(grid->chars[off], sc)
- || grid->attrs[off] != attr) {
- schar_copy(grid->chars[off], sc);
- grid->attrs[off] = attr;
- if (dirty_first == INT_MAX) {
- dirty_first = col;
- }
- dirty_last = col+1;
- }
- if (col == start_col) {
- schar_from_char(sc, c2);
- }
- }
- if (dirty_last > dirty_first) {
- // TODO(bfredl): support a cleared suffix even with a batched line?
- if (put_dirty_row == row) {
- put_dirty_first = MIN(put_dirty_first, dirty_first);
- put_dirty_last = MAX(put_dirty_last, dirty_last);
- } else if (grid->throttled) {
- // Note: assumes msg_grid is the only throttled grid
- assert(grid == &msg_grid);
- int dirty = 0;
- if (attr != HL_ATTR(HLF_MSG) || c2 != ' ') {
- dirty = dirty_last;
- } else if (c1 != ' ') {
- dirty = dirty_first + 1;
- }
- if (grid->dirty_col && dirty > grid->dirty_col[row]) {
- grid->dirty_col[row] = dirty;
- }
- } else {
- int last = c2 != ' ' ? dirty_last : dirty_first + (c1 != ' ');
- ui_line(grid, row, dirty_first, last, dirty_last, attr, false);
- }
- }
-
- if (end_col == grid->Columns) {
- grid->line_wraps[row] = false;
- }
- }
-}
-
/// Check if there should be a delay. Used before clearing or redrawing the
/// screen or the command line.
void check_for_delay(bool check_msg_scroll)
@@ -6482,95 +5630,15 @@ void check_for_delay(bool check_msg_scroll)
}
}
-/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
-/// Updates size, offsets and handle for the grid regardless.
-///
-/// If "doclear" is true, don't try to copy from the old grid rather clear the
-/// resized grid.
-void win_grid_alloc(win_T *wp)
-{
- ScreenGrid *grid = &wp->w_grid;
- ScreenGrid *grid_allocated = &wp->w_grid_alloc;
-
- int rows = wp->w_height_inner;
- int cols = wp->w_width_inner;
- int total_rows = wp->w_height_outer;
- int total_cols = wp->w_width_outer;
-
- bool want_allocation = ui_has(kUIMultigrid) || wp->w_floating;
- bool has_allocation = (grid_allocated->chars != NULL);
-
- if (grid->Rows != rows) {
- wp->w_lines_valid = 0;
- xfree(wp->w_lines);
- wp->w_lines = xcalloc(rows+1, sizeof(wline_T));
- }
-
- int was_resized = false;
- if (want_allocation && (!has_allocation
- || grid_allocated->Rows != total_rows
- || grid_allocated->Columns != total_cols)) {
- grid_alloc(grid_allocated, total_rows, total_cols,
- wp->w_grid_alloc.valid, false);
- grid_allocated->valid = true;
- if (wp->w_floating && wp->w_float_config.border) {
- wp->w_redr_border = true;
- }
- was_resized = true;
- } else if (!want_allocation && has_allocation) {
- // Single grid mode, all rendering will be redirected to default_grid.
- // Only keep track of the size and offset of the window.
- grid_free(grid_allocated);
- grid_allocated->valid = false;
- was_resized = true;
- } else if (want_allocation && has_allocation && !wp->w_grid_alloc.valid) {
- grid_invalidate(grid_allocated);
- grid_allocated->valid = true;
- }
-
- grid->Rows = rows;
- grid->Columns = cols;
-
- if (want_allocation) {
- grid->target = grid_allocated;
- grid->row_offset = wp->w_border_adj[0];
- grid->col_offset = wp->w_border_adj[3];
- } else {
- grid->target = &default_grid;
- grid->row_offset = wp->w_winrow;
- grid->col_offset = wp->w_wincol;
- }
-
- // send grid resize event if:
- // - a grid was just resized
- // - screen_resize was called and all grid sizes must be sent
- // - the UI wants multigrid event (necessary)
- if ((send_grid_resize || was_resized) && want_allocation) {
- ui_call_grid_resize(grid_allocated->handle,
- grid_allocated->Columns, grid_allocated->Rows);
- }
-}
-
-/// assign a handle to the grid. The grid need not be allocated.
-void grid_assign_handle(ScreenGrid *grid)
-{
- static int last_grid_handle = DEFAULT_GRID_HANDLE;
-
- // only assign a grid handle if not already
- if (grid->handle == 0) {
- grid->handle = ++last_grid_handle;
- }
-}
-
/// Resize the screen to Rows and Columns.
///
/// Allocate default_grid.chars[] and other grid arrays.
///
/// 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 shell size. Always use default_grid.Rows and
+/// (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 shell is
+/// and Columns for positioning text etc. where the final size of the screen is
/// needed.
void screenalloc(void)
{
@@ -6589,8 +5657,8 @@ retry:
// 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.Columns
+ && Rows == default_grid.rows
+ && Columns == default_grid.cols
)
|| Rows == 0
|| Columns == 0
@@ -6605,14 +5673,14 @@ retry:
*/
++RedrawingDisabled;
- // win_new_shellsize will recompute floats position, but tell the
+ // 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;
}
- win_new_shellsize(); // fit the windows in the new sized shell
+ win_new_screensize(); // fit the windows in the new sized screen
comp_col(); // recompute columns for shown command and ruler
@@ -6630,7 +5698,7 @@ retry:
StlClickDefinition *new_tab_page_click_defs =
xcalloc((size_t)Columns, sizeof(*new_tab_page_click_defs));
- clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ 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;
@@ -6661,90 +5729,19 @@ retry:
resizing = false;
}
-void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
-{
- int new_row;
- ScreenGrid new = *grid;
- assert(rows >= 0 && columns >= 0);
- size_t ncells = (size_t)rows * columns;
- new.chars = xmalloc(ncells * sizeof(schar_T));
- new.attrs = xmalloc(ncells * sizeof(sattr_T));
- new.line_offset = xmalloc((size_t)(rows * sizeof(unsigned)));
- new.line_wraps = xmalloc((size_t)(rows * sizeof(char_u)));
-
- new.Rows = rows;
- new.Columns = columns;
-
- for (new_row = 0; new_row < new.Rows; new_row++) {
- new.line_offset[new_row] = new_row * new.Columns;
- new.line_wraps[new_row] = false;
-
- grid_clear_line(&new, new.line_offset[new_row], columns, valid);
-
- if (copy) {
- // If the screen is not going to be cleared, copy as much as
- // possible from the old screen to the new one and clear the rest
- // (used when resizing the window at the "--more--" prompt or when
- // executing an external command, for the GUI).
- if (new_row < grid->Rows && grid->chars != NULL) {
- int len = MIN(grid->Columns, new.Columns);
- memmove(new.chars + new.line_offset[new_row],
- grid->chars + grid->line_offset[new_row],
- (size_t)len * sizeof(schar_T));
- memmove(new.attrs + new.line_offset[new_row],
- grid->attrs + grid->line_offset[new_row],
- (size_t)len * sizeof(sattr_T));
- }
- }
- }
- grid_free(grid);
- *grid = new;
-
- // Share a single scratch buffer for all grids, by
- // ensuring it is as wide as the widest grid.
- if (linebuf_size < (size_t)columns) {
- xfree(linebuf_char);
- xfree(linebuf_attr);
- linebuf_char = xmalloc(columns * sizeof(schar_T));
- linebuf_attr = xmalloc(columns * sizeof(sattr_T));
- linebuf_size = columns;
- }
-}
-
-void grid_free(ScreenGrid *grid)
-{
- xfree(grid->chars);
- xfree(grid->attrs);
- xfree(grid->line_offset);
- xfree(grid->line_wraps);
-
- grid->chars = NULL;
- grid->attrs = NULL;
- grid->line_offset = NULL;
- grid->line_wraps = NULL;
-}
-
-/// Doesn't allow reinit, so must only be called by free_all_mem!
-void screen_free_all_mem(void)
-{
- grid_free(&default_grid);
- xfree(linebuf_char);
- xfree(linebuf_attr);
-}
-
-/// Clear tab_page_click_defs table
+/// Clear status line, window bar or tab page line click definition table
///
/// @param[out] tpcd Table to clear.
/// @param[in] tpcd_size Size of the table.
-void clear_tab_page_click_defs(StlClickDefinition *const tpcd, const long tpcd_size)
+void stl_clear_click_defs(StlClickDefinition *const click_defs, const long click_defs_size)
{
- if (tpcd != NULL) {
- for (long i = 0; i < tpcd_size; i++) {
- if (i == 0 || tpcd[i].func != tpcd[i - 1].func) {
- xfree(tpcd[i].func);
+ if (click_defs != NULL) {
+ for (long i = 0; i < click_defs_size; i++) {
+ if (i == 0 || click_defs[i].func != click_defs[i - 1].func) {
+ xfree(click_defs[i].func);
}
}
- memset(tpcd, 0, (size_t)tpcd_size * sizeof(tpcd[0]));
+ memset(click_defs, 0, (size_t)click_defs_size * sizeof(click_defs[0]));
}
}
@@ -6760,9 +5757,9 @@ void screenclear(void)
}
// blank out the default grid
- for (i = 0; i < default_grid.Rows; i++) {
+ for (i = 0; i < default_grid.rows; i++) {
grid_clear_line(&default_grid, default_grid.line_offset[i],
- default_grid.Columns, true);
+ default_grid.cols, true);
default_grid.line_wraps[i] = false;
}
@@ -6799,28 +5796,6 @@ void screenclear(void)
}
}
-/// clear a line in the grid starting at "off" until "width" characters
-/// are cleared.
-void grid_clear_line(ScreenGrid *grid, unsigned off, int width, bool valid)
-{
- for (int col = 0; col < width; col++) {
- schar_from_ascii(grid->chars[off + col], ' ');
- }
- int fill = valid ? 0 : -1;
- (void)memset(grid->attrs + off, fill, (size_t)width * sizeof(sattr_T));
-}
-
-void grid_invalidate(ScreenGrid *grid)
-{
- (void)memset(grid->attrs, -1, sizeof(sattr_T) * grid->Rows * grid->Columns);
-}
-
-bool grid_invalid_row(ScreenGrid *grid, int row)
-{
- return grid->attrs[grid->line_offset[row]] < 0;
-}
-
-
/// Copy part of a grid line for vertically split window.
static void linecopy(ScreenGrid *grid, int to, int from, int col, int width)
{
@@ -6833,12 +5808,17 @@ static void linecopy(ScreenGrid *grid, int to, int from, int col, int width)
width * sizeof(sattr_T));
}
-/*
- * Set cursor to its position in the current window.
- */
+/// Set cursor to its position in the current window.
void setcursor(void)
{
- if (redrawing()) {
+ setcursor_mayforce(false);
+}
+
+/// Set cursor to its position in the current window.
+/// @param force when true, also when not redrawing.
+void setcursor_mayforce(bool force)
+{
+ if (force || redrawing()) {
validate_cursor();
ScreenGrid *grid = &curwin->w_grid;
@@ -6848,11 +5828,11 @@ void setcursor(void)
// 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
+ - ((utf_ptr2cells((char *)get_cursor_pos_ptr()) == 2
&& vim_isprintc(gchar_cursor())) ? 2 : 1);
}
- screen_adjust_grid(&grid, &row, &col);
+ grid_adjust(&grid, &row, &col);
ui_grid_cursor_goto(grid->handle, row, col);
}
}
@@ -6868,16 +5848,16 @@ void win_scroll_lines(win_T *wp, int row, int line_count)
}
// No lines are being moved, just draw over the entire area
- if (row + abs(line_count) >= wp->w_grid.Rows) {
+ if (row + abs(line_count) >= wp->w_grid.rows) {
return;
}
if (line_count < 0) {
grid_del_lines(&wp->w_grid, row, -line_count,
- wp->w_grid.Rows, 0, wp->w_grid.Columns);
+ 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.Columns);
+ wp->w_grid.rows, 0, wp->w_grid.cols);
}
}
@@ -6891,7 +5871,6 @@ void win_scroll_lines(win_T *wp, int row, int line_count)
* screen changes, and in the meantime, everything still works.
*/
-
/// insert lines on the screen and move the existing lines down
/// 'line_count' is the number of lines to be inserted.
/// 'end' is the line after the scrolled part. Normally it is Rows.
@@ -6905,7 +5884,7 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
unsigned temp;
int row_off = 0;
- screen_adjust_grid(&grid, &row_off, &col);
+ grid_adjust(&grid, &row_off, &col);
row += row_off;
end += row_off;
@@ -6916,7 +5895,7 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
// Shift line_offset[] line_count down to reflect the inserted lines.
// Clear the inserted lines.
for (i = 0; i < line_count; i++) {
- if (width != grid->Columns) {
+ if (width != grid->cols) {
// need to copy part of a line
j = end - 1 - i;
while ((j -= line_count) >= row) {
@@ -6934,15 +5913,13 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
}
grid->line_offset[j + line_count] = temp;
grid->line_wraps[j + line_count] = false;
- grid_clear_line(grid, temp, grid->Columns, false);
+ grid_clear_line(grid, temp, grid->cols, false);
}
}
if (!grid->throttled) {
- ui_call_grid_scroll(grid->handle, row, end, col, col+width, -line_count, 0);
+ ui_call_grid_scroll(grid->handle, row, end, col, col + width, -line_count, 0);
}
-
- return;
}
/// delete lines on the screen and move lines up.
@@ -6956,7 +5933,7 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
unsigned temp;
int row_off = 0;
- screen_adjust_grid(&grid, &row_off, &col);
+ grid_adjust(&grid, &row_off, &col);
row += row_off;
end += row_off;
@@ -6967,7 +5944,7 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
// Now shift line_offset[] line_count up to reflect the deleted lines.
// Clear the inserted lines.
for (i = 0; i < line_count; i++) {
- if (width != grid->Columns) {
+ if (width != grid->cols) {
// need to copy part of a line
j = row + i;
while ((j += line_count) <= end - 1) {
@@ -6986,18 +5963,15 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
}
grid->line_offset[j - line_count] = temp;
grid->line_wraps[j - line_count] = false;
- grid_clear_line(grid, temp, grid->Columns, false);
+ grid_clear_line(grid, temp, grid->cols, false);
}
}
if (!grid->throttled) {
- ui_call_grid_scroll(grid->handle, row, end, col, col+width, line_count, 0);
+ ui_call_grid_scroll(grid->handle, row, end, col, col + width, line_count, 0);
}
-
- return;
}
-
// Show the current mode and ruler.
//
// If clear_cmdline is true, clear the rest of the cmdline.
@@ -7022,8 +5996,8 @@ int showmode(void)
msg_grid_validate();
do_mode = ((p_smd && msg_silent == 0)
- && ((State & TERM_FOCUS)
- || (State & INSERT)
+ && ((State & MODE_TERMINAL)
+ || (State & MODE_INSERT)
|| restart_edit != NUL
|| VIsual_active));
if (do_mode || reg_recording != 0) {
@@ -7069,13 +6043,13 @@ int showmode(void)
length = (Rows - msg_row) * Columns - 3;
}
if (edit_submode_extra != NULL) {
- length -= vim_strsize(edit_submode_extra);
+ length -= vim_strsize((char *)edit_submode_extra);
}
if (length > 0) {
if (edit_submode_pre != NULL) {
- length -= vim_strsize(edit_submode_pre);
+ length -= vim_strsize((char *)edit_submode_pre);
}
- if (length - vim_strsize(edit_submode) > 0) {
+ if (length - vim_strsize((char *)edit_submode) > 0) {
if (edit_submode_pre != NULL) {
msg_puts_attr((const char *)edit_submode_pre, attr);
}
@@ -7092,13 +6066,13 @@ int showmode(void)
}
}
} else {
- if (State & TERM_FOCUS) {
+ if (State & MODE_TERMINAL) {
msg_puts_attr(_(" TERMINAL"), attr);
} else if (State & VREPLACE_FLAG) {
msg_puts_attr(_(" VREPLACE"), attr);
} else if (State & REPLACE_FLAG) {
msg_puts_attr(_(" REPLACE"), attr);
- } else if (State & INSERT) {
+ } else if (State & MODE_INSERT) {
if (p_ri) {
msg_puts_attr(_(" REVERSE"), attr);
}
@@ -7114,15 +6088,15 @@ int showmode(void)
if (p_hkmap) {
msg_puts_attr(_(" Hebrew"), attr);
}
- if (State & LANGMAP) {
+ if (State & MODE_LANGMAP) {
if (curwin->w_p_arab) {
msg_puts_attr(_(" Arabic"), attr);
- } else if (get_keymap_str(curwin, (char_u *)" (%s)",
- NameBuff, MAXPATHL)) {
+ } else if (get_keymap_str(curwin, " (%s)",
+ (char *)NameBuff, MAXPATHL)) {
msg_puts_attr((char *)NameBuff, attr);
}
}
- if ((State & INSERT) && p_paste) {
+ if ((State & MODE_INSERT) && p_paste) {
msg_puts_attr(_(" (paste)"), attr);
}
@@ -7184,10 +6158,10 @@ int showmode(void)
clear_showcmd();
}
- // If the last window has no status line, the ruler is after the mode
- // message and must be redrawn
+ // If the last window has no status line and global statusline is disabled,
+ // the ruler is after the mode message and must be redrawn
win_T *last = lastwin_nofloating();
- if (redrawing() && last->w_status_height == 0) {
+ if (redrawing() && last->w_status_height == 0 && global_stl_height() == 0) {
win_redr_ruler(last, true);
}
redraw_cmdline = false;
@@ -7221,6 +6195,10 @@ void unshowmode(bool force)
// Clear the mode message.
void clearmode(void)
{
+ if (p_ch <= 0 && !ui_has(kUIMessages)) {
+ return;
+ }
+
const int save_msg_row = msg_row;
const int save_msg_col = msg_col;
@@ -7238,6 +6216,10 @@ void clearmode(void)
static void recording_mode(int attr)
{
+ if (p_ch <= 0 && !ui_has(kUIMessages)) {
+ return;
+ }
+
msg_puts_attr(_("recording"), attr);
if (!shortmess(SHM_RECORDING)) {
char s[4];
@@ -7283,10 +6265,9 @@ void draw_tabline(void)
return;
}
-
// Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
assert(Columns == tab_page_click_defs_size);
- clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
// Use the 'tabline' option if it's set.
if (*p_tal != NUL) {
@@ -7295,10 +6276,9 @@ void draw_tabline(void)
// Check for an error. If there is one we would loop in redrawing the
// screen. Avoid that by making 'tabline' empty.
did_emsg = false;
- win_redr_custom(NULL, false);
+ win_redr_custom(NULL, false, false);
if (did_emsg) {
- set_string_option_direct("tabline", -1,
- (char_u *)"", OPT_FREE, SID_ERROR);
+ set_string_option_direct("tabline", -1, "", OPT_FREE, SID_ERROR);
}
did_emsg |= saved_did_emsg;
} else {
@@ -7332,7 +6312,6 @@ void draw_tabline(void)
wp = tp->tp_firstwin;
}
-
if (tp->tp_topframe == topframe) {
attr = win_hl_attr(cwp, HLF_TPS);
}
@@ -7354,7 +6333,6 @@ void draw_tabline(void)
}
}
-
if (modified || wincount > 1) {
if (wincount > 1) {
vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
@@ -7376,11 +6354,11 @@ void draw_tabline(void)
if (room > 0) {
// Get buffer name in NameBuff[]
get_trans_bufname(cwp->w_buffer);
- (void)shorten_dir(NameBuff);
- len = vim_strsize(NameBuff);
+ shorten_dir(NameBuff);
+ len = vim_strsize((char *)NameBuff);
p = NameBuff;
while (len > room) {
- len -= ptr2cells(p);
+ len -= ptr2cells((char *)p);
MB_PTR_ADV(p);
}
if (len > Columns - col - 1) {
@@ -7429,35 +6407,49 @@ void draw_tabline(void)
void ui_ext_tabline_update(void)
{
- Array tabs = ARRAY_DICT_INIT;
+ Arena arena = ARENA_EMPTY;
+ arena_start(&arena, &ui_ext_fixblk);
+
+ size_t n_tabs = 0;
FOR_ALL_TABS(tp) {
- Dictionary tab_info = ARRAY_DICT_INIT;
- PUT(tab_info, "tab", TABPAGE_OBJ(tp->handle));
+ n_tabs++;
+ }
+
+ Array tabs = arena_array(&arena, n_tabs);
+ FOR_ALL_TABS(tp) {
+ Dictionary tab_info = arena_dict(&arena, 2);
+ PUT_C(tab_info, "tab", TABPAGE_OBJ(tp->handle));
win_T *cwp = (tp == curtab) ? curwin : tp->tp_curwin;
get_trans_bufname(cwp->w_buffer);
- PUT(tab_info, "name", STRING_OBJ(cstr_to_string((char *)NameBuff)));
+ PUT_C(tab_info, "name", STRING_OBJ(arena_string(&arena, cstr_as_string((char *)NameBuff))));
- ADD(tabs, DICTIONARY_OBJ(tab_info));
+ ADD_C(tabs, DICTIONARY_OBJ(tab_info));
+ }
+
+ size_t n_buffers = 0;
+ FOR_ALL_BUFFERS(buf) {
+ n_buffers += buf->b_p_bl ? 1 : 0;
}
- Array buffers = ARRAY_DICT_INIT;
+ Array buffers = arena_array(&arena, n_buffers);
FOR_ALL_BUFFERS(buf) {
// Do not include unlisted buffers
if (!buf->b_p_bl) {
continue;
}
- Dictionary buffer_info = ARRAY_DICT_INIT;
- PUT(buffer_info, "buffer", BUFFER_OBJ(buf->handle));
+ Dictionary buffer_info = arena_dict(&arena, 2);
+ PUT_C(buffer_info, "buffer", BUFFER_OBJ(buf->handle));
get_trans_bufname(buf);
- PUT(buffer_info, "name", STRING_OBJ(cstr_to_string((char *)NameBuff)));
+ PUT_C(buffer_info, "name", STRING_OBJ(arena_string(&arena, cstr_as_string((char *)NameBuff))));
- ADD(buffers, DICTIONARY_OBJ(buffer_info));
+ ADD_C(buffers, DICTIONARY_OBJ(buffer_info));
}
ui_call_tabline_update(curtab->handle, tabs, curbuf->handle, buffers);
+ arena_mem_free(arena_finish(&arena), &ui_ext_fixblk);
}
/*
@@ -7469,9 +6461,9 @@ void get_trans_bufname(buf_T *buf)
if (buf_spname(buf) != NULL) {
STRLCPY(NameBuff, buf_spname(buf), MAXPATHL);
} else {
- home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
+ home_replace(buf, buf->b_fname, (char *)NameBuff, MAXPATHL, true);
}
- trans_characters(NameBuff, MAXPATHL);
+ trans_characters((char *)NameBuff, MAXPATHL);
}
/*
@@ -7502,16 +6494,22 @@ int fillchar_status(int *attr, win_T *wp)
return '=';
}
-/*
- * Get the character to use in a separator between vertically split windows.
- * Get its attributes in "*attr".
- */
+/// Get the character to use in a separator between vertically split windows.
+/// Get its attributes in "*attr".
static int fillchar_vsep(win_T *wp, int *attr)
{
*attr = win_hl_attr(wp, HLF_C);
return wp->w_p_fcs_chars.vert;
}
+/// Get the character to use in a separator between horizontally split windows.
+/// Get its attributes in "*attr".
+static int fillchar_hsep(win_T *wp, int *attr)
+{
+ *attr = win_hl_attr(wp, HLF_C);
+ return wp->w_p_fcs_chars.horiz;
+}
+
/*
* Return TRUE if redrawing should currently be done.
*/
@@ -7526,7 +6524,8 @@ int redrawing(void)
*/
int messaging(void)
{
- return !(p_lz && char_avail() && !KeyTyped);
+ return !(p_lz && char_avail() && !KeyTyped)
+ && (p_ch > 0 || ui_has(kUIMessages));
}
/// Show current status info in ruler and various other places
@@ -7537,11 +6536,15 @@ void showruler(bool always)
if (!always && !redrawing()) {
return;
}
- if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) {
+ if ((*p_stl != NUL || *curwin->w_p_stl != NUL)
+ && (curwin->w_status_height || global_stl_height())) {
redraw_custom_statusline(curwin);
} else {
win_redr_ruler(curwin, always);
}
+ if (*p_wbr != NUL || *curwin->w_p_wbr != NUL) {
+ win_redr_winbar(curwin);
+ }
if (need_maketitle
|| (p_icon && (stl_syntax & STL_IN_ICON))
@@ -7556,6 +6559,7 @@ void showruler(bool always)
static void win_redr_ruler(win_T *wp, bool always)
{
+ bool is_stl_global = global_stl_height() > 0;
static bool did_show_ext_ruler = false;
// If 'ruler' off or redrawing disabled, don't do anything
@@ -7573,32 +6577,25 @@ static void win_redr_ruler(win_T *wp, bool always)
// Don't draw the ruler while doing insert-completion, it might overwrite
// the (long) mode message.
- if (wp == lastwin && lastwin->w_status_height == 0) {
+ if (wp == lastwin && lastwin->w_status_height == 0 && !is_stl_global) {
if (edit_submode != NULL) {
return;
}
}
- if (*p_ruf) {
- int save_called_emsg = called_emsg;
-
- called_emsg = false;
- win_redr_custom(wp, true);
- if (called_emsg) {
- set_string_option_direct("rulerformat", -1, (char_u *)"",
- OPT_FREE, SID_ERROR);
+ if (*p_ruf && p_ch > 0 && !ui_has(kUIMessages)) {
+ const int called_emsg_before = called_emsg;
+ win_redr_custom(wp, false, true);
+ if (called_emsg > called_emsg_before) {
+ set_string_option_direct("rulerformat", -1, "", OPT_FREE, SID_ERROR);
}
- called_emsg |= save_called_emsg;
return;
}
- /*
- * Check if not in Insert mode and the line is empty (will show "0-1").
- */
- int empty_line = FALSE;
- if (!(State & INSERT)
- && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL) {
- empty_line = TRUE;
+ // Check if not in Insert mode and the line is empty (will show "0-1").
+ int empty_line = false;
+ if ((State & MODE_INSERT) == 0 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, false) == NUL) {
+ empty_line = true;
}
/*
@@ -7628,6 +6625,12 @@ static void win_redr_ruler(win_T *wp, bool always)
off = wp->w_wincol;
width = wp->w_width;
part_of_status = true;
+ } else if (is_stl_global) {
+ row = Rows - p_ch - 1;
+ fillchar = fillchar_status(&attr, wp);
+ off = 0;
+ width = Columns;
+ part_of_status = true;
} else {
row = Rows - 1;
fillchar = ' ';
@@ -7636,6 +6639,10 @@ static void win_redr_ruler(win_T *wp, bool always)
off = 0;
}
+ if (!part_of_status && p_ch < 1 && !ui_has(kUIMessages)) {
+ return;
+ }
+
// In list mode virtcol needs to be recomputed
colnr_T virtcol = wp->w_virtcol;
if (wp->w_p_list && wp->w_p_lcs_chars.tab1 == NUL) {
@@ -7645,13 +6652,13 @@ static void win_redr_ruler(win_T *wp, bool always)
}
#define RULER_BUF_LEN 70
- char_u buffer[RULER_BUF_LEN];
+ char buffer[RULER_BUF_LEN];
/*
* Some sprintfs return the length, some return a pointer.
* To avoid portability problems we use strlen() here.
*/
- vim_snprintf((char *)buffer, RULER_BUF_LEN, "%" PRId64 ",",
+ vim_snprintf(buffer, RULER_BUF_LEN, "%" PRId64 ",",
(wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? (int64_t)0L
: (int64_t)wp->w_cursor.lnum);
size_t len = STRLEN(buffer);
@@ -7667,7 +6674,7 @@ static void win_redr_ruler(win_T *wp, bool always)
int i = (int)STRLEN(buffer);
get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
int o = i + vim_strsize(buffer + i + 1);
- if (wp->w_status_height == 0) { // can't use last char of screen
+ if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen
o++;
}
int this_ru_col = ru_col - (Columns - width);
@@ -7689,11 +6696,11 @@ static void win_redr_ruler(win_T *wp, bool always)
}
if (ui_has(kUIMessages) && !part_of_status) {
- Array content = ARRAY_DICT_INIT;
- Array chunk = ARRAY_DICT_INIT;
- ADD(chunk, INTEGER_OBJ(attr));
- ADD(chunk, STRING_OBJ(cstr_to_string((char *)buffer)));
- ADD(content, ARRAY_OBJ(chunk));
+ MAXSIZE_TEMP_ARRAY(content, 1);
+ MAXSIZE_TEMP_ARRAY(chunk, 2);
+ ADD_C(chunk, INTEGER_OBJ(attr));
+ ADD_C(chunk, STRING_OBJ(cstr_as_string((char *)buffer)));
+ ADD_C(content, ARRAY_OBJ(chunk));
ui_call_msg_ruler(content);
did_show_ext_ruler = true;
} else {
@@ -7712,7 +6719,7 @@ static void win_redr_ruler(win_T *wp, bool always)
}
ScreenGrid *grid = part_of_status ? &default_grid : &msg_grid_adj;
- grid_puts(grid, buffer, row, this_ru_col + off, attr);
+ grid_puts(grid, (char_u *)buffer, row, this_ru_col + off, attr);
grid_fill(grid, row, row + 1,
this_ru_col + off + (int)STRLEN(buffer), off + width, fillchar,
fillchar, attr);
@@ -7815,14 +6822,12 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col)
prev_col_off = cur_col_off;
}
-/// Set dimensions of the Nvim application "shell".
+/// Set dimensions of the Nvim application "screen".
void screen_resize(int width, int height)
{
- static bool recursive = false;
-
// Avoid recursiveness, can happen when setting the window size causes
// another window-changed signal.
- if (updating_screen || recursive) {
+ if (updating_screen || resizing_screen) {
return;
}
@@ -7830,9 +6835,9 @@ void screen_resize(int width, int height)
return;
}
- if (State == HITRETURN || State == SETWSIZE) {
+ if (State == MODE_HITRETURN || State == MODE_SETWSIZE) {
// postpone the resizing
- State = SETWSIZE;
+ State = MODE_SETWSIZE;
return;
}
@@ -7844,13 +6849,13 @@ void screen_resize(int width, int height)
return;
}
- recursive = true;
+ resizing_screen = true;
Rows = height;
Columns = width;
- check_shellsize();
+ check_screensize();
int max_p_ch = Rows - min_rows() + 1;
- if (!ui_has(kUIMessages) && p_ch > max_p_ch) {
+ if (!ui_has(kUIMessages) && p_ch > 0 && p_ch > max_p_ch) {
p_ch = max_p_ch ? max_p_ch : 1;
}
height = Rows;
@@ -7861,11 +6866,11 @@ void screen_resize(int width, int height)
send_grid_resize = true;
- /* The window layout used to be adjusted here, but it now happens in
- * screenalloc() (also invoked from screenclear()). That is because the
- * "recursive" check above may skip this, but not screenalloc(). */
+ /// 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().
- if (State != ASKMORE && State != EXTERNCMD && State != CONFIRM) {
+ if (State != MODE_ASKMORE && State != MODE_EXTERNCMD && State != MODE_CONFIRM) {
screenclear();
}
@@ -7884,7 +6889,7 @@ void screen_resize(int width, int height)
* Always need to call update_screen() or screenalloc(), to make
* sure Rows/Columns and the size of the screen is correct!
*/
- if (State == ASKMORE || State == EXTERNCMD || State == CONFIRM
+ if (State == MODE_ASKMORE || State == MODE_EXTERNCMD || State == MODE_CONFIRM
|| exmode_active) {
screenalloc();
if (msg_grid.chars) {
@@ -7898,7 +6903,7 @@ void screen_resize(int width, int height)
if (curwin->w_p_scb) {
do_check_scrollbind(true);
}
- if (State & CMDLINE) {
+ if (State & MODE_CMDLINE) {
redraw_popupmenu = false;
update_screen(NOT_VALID);
redrawcmdline();
@@ -7922,52 +6927,26 @@ void screen_resize(int width, int height)
}
ui_flush();
}
- recursive = false;
+ resizing_screen = false;
}
-/// Check if the new Nvim application "shell" dimensions are valid.
+/// Check if the new Nvim application "screen" dimensions are valid.
/// Correct it if it's too small or way too big.
-void check_shellsize(void)
+void check_screensize(void)
{
+ // Limit Rows and Columns to avoid an overflow in Rows * Columns.
if (Rows < min_rows()) {
// need room for one window and command line
Rows = min_rows();
+ } else if (Rows > 1000) {
+ Rows = 1000;
}
- limit_screen_size();
-}
-// Limit Rows and Columns to avoid an overflow in Rows * Columns.
-void limit_screen_size(void)
-{
if (Columns < MIN_COLUMNS) {
Columns = MIN_COLUMNS;
} else if (Columns > 10000) {
Columns = 10000;
}
-
- if (Rows > 1000) {
- Rows = 1000;
- }
-}
-
-void win_new_shellsize(void)
-{
- static long old_Rows = 0;
- static long old_Columns = 0;
-
- if (old_Rows != Rows) {
- // If 'window' uses the whole screen, keep it using that.
- // Don't change it when set with "-w size" on the command line.
- if (p_window == old_Rows - 1 || (old_Rows == 0 && p_window == 0)) {
- p_window = Rows - 1;
- }
- old_Rows = Rows;
- shell_new_rows(); // update window sizes
- }
- if (old_Columns != Columns) {
- old_Columns = Columns;
- shell_new_columns(); // update window sizes
- }
}
win_T *get_win_by_grid_handle(handle_T handle)
@@ -7979,4 +6958,3 @@ win_T *get_win_by_grid_handle(handle_T handle)
}
return NULL;
}
-