aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/extmark.c1
-rw-r--r--src/nvim/api/vim.c1
-rw-r--r--src/nvim/autocmd.c3
-rw-r--r--src/nvim/charset.c10
-rw-r--r--src/nvim/decoration.c53
-rw-r--r--src/nvim/decoration.h19
-rw-r--r--src/nvim/decoration_provider.c231
-rw-r--r--src/nvim/decoration_provider.h26
-rw-r--r--src/nvim/highlight.c1
-rw-r--r--src/nvim/main.c1
-rw-r--r--src/nvim/mark.c2
-rw-r--r--src/nvim/memory.c2
-rw-r--r--src/nvim/normal.c1
-rw-r--r--src/nvim/option.c6
-rw-r--r--src/nvim/popupmnu.c7
-rw-r--r--src/nvim/regexp.c10
-rw-r--r--src/nvim/screen.c148
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim16
-rw-r--r--src/nvim/tui/tui.c4
19 files changed, 322 insertions, 220 deletions
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 0ee8134ec4..e355f82f4d 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -8,6 +8,7 @@
#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/decoration_provider.h"
#include "nvim/extmark.h"
#include "nvim/lua/executor.h"
#include "nvim/memline.h"
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b2d866ae0e..ebf4f65c91 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -22,6 +22,7 @@
#include "nvim/charset.h"
#include "nvim/context.h"
#include "nvim/decoration.h"
+#include "nvim/decoration_provider.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index a850e5c1a0..dfcdfd8203 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -2428,9 +2428,8 @@ char *aucmd_exec_default_desc(AucmdExecutable acc)
default:
return NULL;
}
-
- abort();
}
+
char *aucmd_exec_to_string(AutoCmd *ac, AucmdExecutable acc)
{
switch (acc.type) {
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 97aac67627..3383dd2a76 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -928,10 +928,12 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en
// continue until the NUL
posptr = NULL;
} else {
- // Special check for an empty line, which can happen on exit, when
- // ml_get_buf() always returns an empty string.
- if (*ptr == NUL) {
- pos->col = 0;
+ // In a few cases the position can be beyond the end of the line.
+ for (colnr_T i = 0; i < pos->col; i++) {
+ if (ptr[i] == NUL) {
+ pos->col = i;
+ break;
+ }
}
posptr = ptr + pos->col;
posptr -= utf_head_off(line, posptr);
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index b533f4c46f..94bf1feeee 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -523,59 +523,6 @@ void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col,
}
-DecorProvider *get_decor_provider(NS ns_id, bool force)
-{
- size_t i;
- size_t len = kv_size(decor_providers);
- for (i = 0; i < len; i++) {
- DecorProvider *item = &kv_A(decor_providers, i);
- if (item->ns_id == ns_id) {
- return item;
- } else if (item->ns_id > ns_id) {
- break;
- }
- }
-
- if (!force) {
- return NULL;
- }
-
- // Adding a new provider, so allocate room in the vector
- (void)kv_a(decor_providers, len);
- if (i < len) {
- // New ns_id needs to be inserted between existing providers to maintain
- // ordering, so shift other providers with larger ns_id
- memmove(&kv_A(decor_providers, i + 1),
- &kv_A(decor_providers, i),
- (len - i) * sizeof(kv_a(decor_providers, i)));
- }
- DecorProvider *item = &kv_a(decor_providers, i);
- *item = DECORATION_PROVIDER_INIT(ns_id);
-
- return item;
-}
-
-void decor_provider_clear(DecorProvider *p)
-{
- if (p == NULL) {
- return;
- }
- NLUA_CLEAR_REF(p->redraw_start);
- NLUA_CLEAR_REF(p->redraw_buf);
- NLUA_CLEAR_REF(p->redraw_win);
- NLUA_CLEAR_REF(p->redraw_line);
- NLUA_CLEAR_REF(p->redraw_end);
- p->active = false;
-}
-
-void decor_free_all_mem(void)
-{
- for (size_t i = 0; i < kv_size(decor_providers); i++) {
- decor_provider_clear(&kv_A(decor_providers, i));
- }
- kv_destroy(decor_providers);
-}
-
int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines)
{
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index c186a1b1fd..8df53caa0a 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -82,26 +82,7 @@ typedef struct {
int eol_col;
} DecorState;
-typedef struct {
- NS ns_id;
- bool active;
- LuaRef redraw_start;
- LuaRef redraw_buf;
- LuaRef redraw_win;
- LuaRef redraw_line;
- LuaRef redraw_end;
- LuaRef hl_def;
- int hl_valid;
-} DecorProvider;
-
-EXTERN kvec_t(DecorProvider) decor_providers INIT(= KV_INITIAL_VALUE);
EXTERN DecorState decor_state INIT(= { 0 });
-EXTERN bool provider_active INIT(= false);
-
-#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
- { ns_id, false, LUA_NOREF, LUA_NOREF, \
- LUA_NOREF, LUA_NOREF, LUA_NOREF, \
- LUA_NOREF, -1 }
static inline bool decor_has_sign(Decoration *decor)
{
diff --git a/src/nvim/decoration_provider.c b/src/nvim/decoration_provider.c
new file mode 100644
index 0000000000..6efcb08b9d
--- /dev/null
+++ b/src/nvim/decoration_provider.c
@@ -0,0 +1,231 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+#include "nvim/api/extmark.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/buffer.h"
+#include "nvim/decoration.h"
+#include "nvim/decoration_provider.h"
+#include "nvim/highlight.h"
+#include "nvim/lua/executor.h"
+
+static kvec_t(DecorProvider) decor_providers = KV_INITIAL_VALUE;
+
+#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
+ { ns_id, false, LUA_NOREF, LUA_NOREF, \
+ LUA_NOREF, LUA_NOREF, LUA_NOREF, \
+ LUA_NOREF, -1 }
+
+static bool decor_provider_invoke(NS ns_id, const char *name, LuaRef ref,
+ Array args, bool default_true, char **perr)
+{
+ 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 && perr && *perr == NULL) {
+ static char errbuf[IOSIZE];
+ snprintf(errbuf, sizeof errbuf, "%s: %s", ns_name, err.msg);
+ *perr = xstrdup(errbuf);
+ }
+ }
+
+ api_free_object(ret);
+ return false;
+}
+
+/// For each provider invoke the 'start' callback
+///
+/// @param[out] providers Decoration providers
+/// @param[out] err Provider err
+void decor_providers_start(DecorProviders *providers, int type, char **err)
+{
+ 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((int)display_tick);
+ args.items[1] = INTEGER_OBJ(type);
+ active = decor_provider_invoke(p->ns_id, "start", p->redraw_start, args, true, err);
+ } else {
+ active = true;
+ }
+
+ if (active) {
+ kvi_push(*providers, p);
+ }
+ }
+}
+
+/// For each provider run 'win'. If result is not false, then collect the
+/// 'on_line' callback to call inside win_line
+///
+/// @param wp Window
+/// @param providers Decoration providers
+/// @param[out] line_providers Enabled line providers to invoke in win_line
+/// @param[out] err Provider error
+void decor_providers_invoke_win(win_T *wp, DecorProviders *providers,
+ DecorProviders *line_providers, char **err)
+{
+ kvi_init(*line_providers);
+
+ linenr_T knownmax = ((wp->w_valid & VALID_BOTLINE)
+ ? wp->w_botline
+ : (wp->w_topline + wp->w_height_inner));
+
+ 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(wp->w_buffer->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 (decor_provider_invoke(p->ns_id, "win", p->redraw_win, args, true, err)) {
+ kvi_push(*line_providers, p);
+ }
+ }
+ }
+
+ win_check_ns_hl(wp);
+}
+
+/// For each provider invoke the 'line' callback for a given window row.
+///
+/// @param wp Window
+/// @param providers Decoration providers
+/// @param row Row to invoke line callback for
+/// @param[out] has_decor Set when at least one provider invokes a line callback
+/// @param[out] err Provider error
+void providers_invoke_line(win_T *wp, DecorProviders *providers, int row, bool *has_decor,
+ char **err)
+{
+ 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(wp->w_buffer->handle);
+ args.items[2] = INTEGER_OBJ(row);
+ if (decor_provider_invoke(p->ns_id, "line", p->redraw_line, args, true, err)) {
+ *has_decor = true;
+ } else {
+ // return 'false' or error: skip rest of this window
+ kv_A(*providers, k) = NULL;
+ }
+
+ win_check_ns_hl(wp);
+ }
+ }
+}
+
+
+/// For each provider invoke the 'buf' callback for a given buffer.
+///
+/// @param buf Buffer
+/// @param providers Decoration providers
+/// @param[out] err Provider error
+void decor_providers_invoke_buf(buf_T *buf, DecorProviders *providers, char **err)
+{
+ 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);
+ decor_provider_invoke(p->ns_id, "buf", p->redraw_buf, args, true, err);
+ }
+ }
+}
+
+
+/// For each provider invoke the 'end' callback
+///
+/// @param providers Decoration providers
+/// @param displaytick Display tick
+/// @param[out] err Provider error
+void decor_providers_invoke_end(DecorProviders *providers, char **err)
+{
+ for (size_t i = 0; i < kv_size(*providers); i++) {
+ DecorProvider *p = kv_A(*providers, i);
+ if (p && p->active && p->redraw_end != LUA_NOREF) {
+ FIXED_TEMP_ARRAY(args, 1);
+ args.items[0] = INTEGER_OBJ((int)display_tick);
+ decor_provider_invoke(p->ns_id, "end", p->redraw_end, args, true, err);
+ }
+ }
+}
+
+DecorProvider *get_decor_provider(NS ns_id, bool force)
+{
+ size_t i;
+ size_t len = kv_size(decor_providers);
+ for (i = 0; i < len; i++) {
+ DecorProvider *item = &kv_A(decor_providers, i);
+ if (item->ns_id == ns_id) {
+ return item;
+ } else if (item->ns_id > ns_id) {
+ break;
+ }
+ }
+
+ if (!force) {
+ return NULL;
+ }
+
+ // Adding a new provider, so allocate room in the vector
+ (void)kv_a(decor_providers, len);
+ if (i < len) {
+ // New ns_id needs to be inserted between existing providers to maintain
+ // ordering, so shift other providers with larger ns_id
+ memmove(&kv_A(decor_providers, i + 1),
+ &kv_A(decor_providers, i),
+ (len - i) * sizeof(kv_a(decor_providers, i)));
+ }
+ DecorProvider *item = &kv_a(decor_providers, i);
+ *item = DECORATION_PROVIDER_INIT(ns_id);
+
+ return item;
+}
+
+void decor_provider_clear(DecorProvider *p)
+{
+ if (p == NULL) {
+ return;
+ }
+ NLUA_CLEAR_REF(p->redraw_start);
+ NLUA_CLEAR_REF(p->redraw_buf);
+ NLUA_CLEAR_REF(p->redraw_win);
+ NLUA_CLEAR_REF(p->redraw_line);
+ NLUA_CLEAR_REF(p->redraw_end);
+ p->active = false;
+}
+
+void decor_free_all_mem(void)
+{
+ for (size_t i = 0; i < kv_size(decor_providers); i++) {
+ decor_provider_clear(&kv_A(decor_providers, i));
+ }
+ kv_destroy(decor_providers);
+}
+
diff --git a/src/nvim/decoration_provider.h b/src/nvim/decoration_provider.h
new file mode 100644
index 0000000000..3ec7c80357
--- /dev/null
+++ b/src/nvim/decoration_provider.h
@@ -0,0 +1,26 @@
+#ifndef NVIM_DECORATION_PROVIDER_H
+#define NVIM_DECORATION_PROVIDER_H
+
+#include "nvim/buffer_defs.h"
+
+typedef struct {
+ NS ns_id;
+ bool active;
+ LuaRef redraw_start;
+ LuaRef redraw_buf;
+ LuaRef redraw_win;
+ LuaRef redraw_line;
+ LuaRef redraw_end;
+ LuaRef hl_def;
+ int hl_valid;
+} DecorProvider;
+
+typedef kvec_withinit_t(DecorProvider *, 4) DecorProviders;
+
+EXTERN bool provider_active INIT(= false);
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "decoration_provider.h.generated.h"
+#endif
+
+#endif // NVIM_DECORATION_PROVIDER_H
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 3aa9190db6..abbda1e9fa 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -5,6 +5,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/decoration_provider.h"
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/lua/executor.h"
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 7281809c06..a575aba50a 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -14,6 +14,7 @@
#include "nvim/channel.h"
#include "nvim/charset.h"
#include "nvim/decoration.h"
+#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 8b29aa3676..b770fef05c 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -630,7 +630,7 @@ static char_u *mark_line(pos_T *mp, int lead_len)
if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count) {
return vim_strsave((char_u *)"-invalid-");
}
- assert(Columns >= 0 && (size_t)Columns <= SIZE_MAX);
+ assert(Columns >= 0);
// Allow for up to 5 bytes per character.
s = vim_strnsave(skipwhite(ml_get(mp->lnum)), (size_t)Columns * 5);
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 677ff8f522..d68ca6b62e 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -10,7 +10,7 @@
#include "nvim/api/extmark.h"
#include "nvim/context.h"
-#include "nvim/decoration.h"
+#include "nvim/decoration_provider.h"
#include "nvim/eval.h"
#include "nvim/highlight.h"
#include "nvim/lua/executor.h"
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 5c39e9c8bf..0e5e0ab403 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -3568,7 +3568,6 @@ static void nv_zet(cmdarg_T *cap)
bool undo = false;
int l_p_siso = (int)get_sidescrolloff_value(curwin);
- assert(l_p_siso <= INT_MAX);
if (ascii_isdigit(nchar)) {
/*
diff --git a/src/nvim/option.c b/src/nvim/option.c
index a0706dfa14..191b635dc0 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -5664,12 +5664,10 @@ void comp_col(void)
}
}
assert(sc_col >= 0
- && INT_MIN + sc_col <= Columns
- && Columns - sc_col <= INT_MAX);
+ && INT_MIN + sc_col <= Columns);
sc_col = Columns - sc_col;
assert(ru_col >= 0
- && INT_MIN + ru_col <= Columns
- && Columns - ru_col <= INT_MAX);
+ && INT_MIN + ru_col <= Columns);
ru_col = Columns - ru_col;
if (sc_col <= 0) { // screen too narrow, will become a mess
sc_col = 1;
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index d7726409b5..e354a589a5 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -289,8 +289,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
if (pum_rl) {
pum_width = pum_col - pum_scrollbar + 1;
} else {
- assert(Columns - pum_col - pum_scrollbar >= INT_MIN
- && Columns - pum_col - pum_scrollbar <= INT_MAX);
+ assert(Columns - pum_col - pum_scrollbar >= 0);
pum_width = Columns - pum_col - pum_scrollbar;
}
@@ -356,7 +355,6 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
} else {
pum_col = 0;
}
- assert(Columns - 1 >= INT_MIN);
pum_width = Columns - 1;
} else {
if (max_width > p_pw) {
@@ -367,8 +365,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
if (pum_rl) {
pum_col = max_width - 1;
} else {
- assert(Columns - max_width >= INT_MIN
- && Columns - max_width <= INT_MAX);
+ assert(Columns - max_width >= 0);
pum_col = Columns - max_width;
}
pum_width = max_width - pum_scrollbar;
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 412cdac21b..009a26d4e0 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -1136,8 +1136,8 @@ static bool reg_match_visual(void)
return false;
}
+ col = (colnr_T)(rex.input - rex.line);
if (mode == 'v') {
- col = (colnr_T)(rex.input - rex.line);
if ((lnum == top.lnum && col < top.col)
|| (lnum == bot.lnum && col >= bot.col + (*p_sel != 'e'))) {
return false;
@@ -1152,8 +1152,12 @@ static bool reg_match_visual(void)
if (top.col == MAXCOL || bot.col == MAXCOL || curswant == MAXCOL) {
end = MAXCOL;
}
- unsigned int cols_u = win_linetabsize(wp, rex.line,
- (colnr_T)(rex.input - rex.line));
+
+ // getvvcol() flushes rex.line, need to get it again
+ rex.line = reg_getline(rex.lnum);
+ rex.input = rex.line + col;
+
+ unsigned int cols_u = win_linetabsize(wp, rex.line, col);
assert(cols_u <= MAXCOL);
colnr_T cols = (colnr_T)cols_u;
if (cols < start || cols > end - (*p_sel == 'e')) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index c8092c3503..0a1f388456 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -75,6 +75,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"
@@ -126,8 +127,6 @@
#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
@@ -168,36 +167,6 @@ static bool resizing = false;
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.
@@ -501,28 +470,8 @@ int update_screen(int type)
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)) {
@@ -591,14 +540,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;
}
}
@@ -668,18 +610,7 @@ 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);
@@ -766,7 +697,7 @@ 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)
{
buf_T *buf = wp->w_buffer;
int type;
@@ -1377,30 +1308,8 @@ static void win_update(win_T *wp, Providers *providers)
decor_redraw_reset(buf, &decor_state);
- Providers line_providers;
- kvi_init(line_providers);
-
- linenr_T knownmax = ((wp->w_valid & VALID_BOTLINE)
- ? wp->w_botline
- : (wp->w_topline + wp->w_height_inner));
-
- 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);
- }
- }
- }
-
- win_check_ns_hl(wp);
-
+ DecorProviders line_providers;
+ decor_providers_invoke_win(wp, providers, &line_providers, &provider_err);
for (;;) {
/* stop updating when reached the end of the window (check for _past_
@@ -2028,6 +1937,17 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
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((char_u *)err);
+ decor_add_ephemeral(lnum-1, 0, lnum-1, 0, &err_decor);
+}
+
/// Display line "lnum" of window 'wp' on the screen.
/// wp->w_virtcol needs to be valid.
///
@@ -2043,7 +1963,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)
@@ -2231,34 +2151,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
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) {
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index a92f7e1192..a0f5ebfb9f 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -795,4 +795,20 @@ func Test_using_mark_position()
bwipe!
endfunc
+func Test_using_visual_position()
+ " this was using freed memory
+ new
+ exe "norm 0o\<Esc>\<C-V>k\<C-X>o0"
+ /\%V
+ bwipe!
+endfunc
+
+func Test_using_invalid_visual_position()
+ " this was going beyond the end of the line
+ new
+ exe "norm 0o000\<Esc>0\<C-V>$s0"
+ /\%V
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 1ad82b7290..79a6b9ed0e 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1475,8 +1475,8 @@ static void tui_guess_size(UI *ui)
// 1 - look for non-default 'columns' and 'lines' options during startup
if (data->is_starting && (Columns != DFLT_COLS || Rows != DFLT_ROWS)) {
did_user_set_dimensions = true;
- assert(Columns >= INT_MIN && Columns <= INT_MAX);
- assert(Rows >= INT_MIN && Rows <= INT_MAX);
+ assert(Columns >= 0);
+ assert(Rows >= 0);
width = Columns;
height = Rows;
goto end;