aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clint.py2
-rw-r--r--src/man/nvim.14
-rw-r--r--src/nvim/api/buffer.c12
-rw-r--r--src/nvim/api/command.c4
-rw-r--r--src/nvim/api/deprecated.c2
-rw-r--r--src/nvim/api/extmark.c157
-rw-r--r--src/nvim/api/extmark.h15
-rw-r--r--src/nvim/api/keysets_defs.h5
-rw-r--r--src/nvim/api/options.c9
-rw-r--r--src/nvim/api/private/validate.c2
-rw-r--r--src/nvim/api/vim.c3
-rw-r--r--src/nvim/api/vimscript.c2
-rw-r--r--src/nvim/api/win_config.c1
-rw-r--r--src/nvim/api/window.c1
-rw-r--r--src/nvim/arglist.c1
-rw-r--r--src/nvim/autocmd.c13
-rw-r--r--src/nvim/base64.c4
-rw-r--r--src/nvim/buffer.c14
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/bufwrite.c3
-rw-r--r--src/nvim/change.c4
-rw-r--r--src/nvim/channel.c79
-rw-r--r--src/nvim/channel.h8
-rw-r--r--src/nvim/channel_defs.h2
-rw-r--r--src/nvim/charset.c4
-rw-r--r--src/nvim/cmdexpand.c13
-rw-r--r--src/nvim/cmdhist.c1
-rw-r--r--src/nvim/context.c4
-rw-r--r--src/nvim/debugger.c11
-rw-r--r--src/nvim/decoration.c26
-rw-r--r--src/nvim/diff.c67
-rw-r--r--src/nvim/digraph.c1
-rw-r--r--src/nvim/drawline.c3
-rw-r--r--src/nvim/drawscreen.c23
-rw-r--r--src/nvim/edit.c30
-rw-r--r--src/nvim/errors.h193
-rw-r--r--src/nvim/eval.c21
-rw-r--r--src/nvim/eval.lua55
-rw-r--r--src/nvim/eval/encode.c6
-rw-r--r--src/nvim/eval/executor.c1
-rw-r--r--src/nvim/eval/funcs.c11
-rw-r--r--src/nvim/eval/typval.c3
-rw-r--r--src/nvim/eval/userfunc.c5
-rw-r--r--src/nvim/eval/vars.c1
-rw-r--r--src/nvim/eval/window.c3
-rw-r--r--src/nvim/event/defs.h41
-rw-r--r--src/nvim/event/libuv_process.c8
-rw-r--r--src/nvim/event/process.c49
-rw-r--r--src/nvim/event/process.h4
-rw-r--r--src/nvim/event/rstream.c201
-rw-r--r--src/nvim/event/socket.c18
-rw-r--r--src/nvim/event/stream.c29
-rw-r--r--src/nvim/event/wstream.c7
-rw-r--r--src/nvim/ex_cmds.c17
-rw-r--r--src/nvim/ex_cmds2.c1
-rw-r--r--src/nvim/ex_docmd.c61
-rw-r--r--src/nvim/ex_eval.c9
-rw-r--r--src/nvim/ex_getln.c14
-rw-r--r--src/nvim/ex_session.c1
-rw-r--r--src/nvim/extmark.c4
-rw-r--r--src/nvim/file_search.c60
-rw-r--r--src/nvim/fileio.c7
-rw-r--r--src/nvim/fold.c3
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua1
-rw-r--r--src/nvim/generators/gen_api_ui_events.lua8
-rw-r--r--src/nvim/generators/gen_options.lua2
-rw-r--r--src/nvim/getchar.c5
-rw-r--r--src/nvim/globals.h196
-rw-r--r--src/nvim/help.c11
-rw-r--r--src/nvim/highlight.h2
-rw-r--r--src/nvim/highlight_defs.h2
-rw-r--r--src/nvim/highlight_group.c65
-rw-r--r--src/nvim/indent.c58
-rw-r--r--src/nvim/insexpand.c159
-rw-r--r--src/nvim/keycodes.c3
-rw-r--r--src/nvim/linematch.c3
-rw-r--r--src/nvim/log.c10
-rw-r--r--src/nvim/lua/api_wrappers.c1
-rw-r--r--src/nvim/lua/executor.c1
-rw-r--r--src/nvim/lua/secure.c5
-rw-r--r--src/nvim/lua/spell.c1
-rw-r--r--src/nvim/lua/stdlib.c100
-rw-r--r--src/nvim/lua/treesitter.c2
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/mapping.c29
-rw-r--r--src/nvim/mark.c1
-rw-r--r--src/nvim/marktree.c2
-rw-r--r--src/nvim/marktree.h20
-rw-r--r--src/nvim/match.c1
-rw-r--r--src/nvim/mbyte.c46
-rw-r--r--src/nvim/memfile.c1
-rw-r--r--src/nvim/memline.c4
-rw-r--r--src/nvim/memory.c18
-rw-r--r--src/nvim/memory.h2
-rw-r--r--src/nvim/menu.c27
-rw-r--r--src/nvim/message.c7
-rw-r--r--src/nvim/move.c1
-rw-r--r--src/nvim/msgpack_rpc/channel.c38
-rw-r--r--src/nvim/msgpack_rpc/packer.c1
-rw-r--r--src/nvim/msgpack_rpc/server.c3
-rw-r--r--src/nvim/normal.c3
-rw-r--r--src/nvim/ops.c17
-rw-r--r--src/nvim/option.c47
-rw-r--r--src/nvim/option_vars.h13
-rw-r--r--src/nvim/options.lua30
-rw-r--r--src/nvim/optionstr.c38
-rw-r--r--src/nvim/os/env.c28
-rw-r--r--src/nvim/os/fileio.c276
-rw-r--r--src/nvim/os/fileio_defs.h10
-rw-r--r--src/nvim/os/fs.c7
-rw-r--r--src/nvim/os/input.c131
-rw-r--r--src/nvim/os/pty_process_unix.c6
-rw-r--r--src/nvim/os/pty_process_win.c10
-rw-r--r--src/nvim/os/shell.c139
-rw-r--r--src/nvim/os/stdpaths.c2
-rw-r--r--src/nvim/path.c4
-rw-r--r--src/nvim/plines.c3
-rw-r--r--src/nvim/popupmenu.c8
-rw-r--r--src/nvim/popupmenu.h9
-rw-r--r--src/nvim/profile.c9
-rw-r--r--src/nvim/quickfix.c7
-rw-r--r--src/nvim/rbuffer.c247
-rw-r--r--src/nvim/rbuffer.h71
-rw-r--r--src/nvim/rbuffer_defs.h45
-rw-r--r--src/nvim/regexp.c11
-rw-r--r--src/nvim/runtime.c13
-rw-r--r--src/nvim/search.c27
-rw-r--r--src/nvim/sha256.c5
-rw-r--r--src/nvim/shada.c1
-rw-r--r--src/nvim/sign.c97
-rw-r--r--src/nvim/spell.c181
-rw-r--r--src/nvim/spellfile.c27
-rw-r--r--src/nvim/spellsuggest.c19
-rw-r--r--src/nvim/statusline.c2
-rw-r--r--src/nvim/strings.c27
-rw-r--r--src/nvim/syntax.c15
-rw-r--r--src/nvim/tag.c31
-rw-r--r--src/nvim/terminal.c83
-rw-r--r--src/nvim/testing.c1
-rw-r--r--src/nvim/textformat.c2
-rw-r--r--src/nvim/tui/input.c171
-rw-r--r--src/nvim/tui/input.h13
-rw-r--r--src/nvim/tui/terminfo.c2
-rw-r--r--src/nvim/tui/tui.c16
-rw-r--r--src/nvim/undo.c1
-rw-r--r--src/nvim/usercmd.c16
-rw-r--r--src/nvim/window.c3
-rw-r--r--src/nvim/winfloat.c1
148 files changed, 2106 insertions, 2022 deletions
diff --git a/src/clint.py b/src/clint.py
index 41058469b1..051f0e91e5 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -1995,7 +1995,7 @@ def CheckLanguage(filename, clean_lines, linenum, error):
if match:
error(filename, linenum, 'runtime/printf', 4,
'Use xstrlcpy, xmemcpyz or snprintf instead of %s' % match.group(1))
- match = Search(r'\b(STRNCAT|strncat|strcat|vim_strcat)\b', line)
+ match = Search(r'\b(STRNCAT|strncat|vim_strcat)\b', line)
if match:
error(filename, linenum, 'runtime/printf', 4,
'Use xstrlcat or snprintf instead of %s' % match.group(1))
diff --git a/src/man/nvim.1 b/src/man/nvim.1
index 4dc099f98c..9b7680d011 100644
--- a/src/man/nvim.1
+++ b/src/man/nvim.1
@@ -387,10 +387,10 @@ features like
.El
.Sh FILES
.Bl -tag -width "~/.config/nvim/init.vim"
-.It Pa ~/.config/nvim/init.vim
+.It Pa ~/.config/nvim/init.lua
User-local
.Nm
-configuration file.
+Lua configuration file.
.It Pa ~/.config/nvim
User-local
.Nm
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 7e64808709..a0678dc3e4 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1183,12 +1183,12 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena,
return rv;
}
-/// call a function with buffer as temporary current buffer
+/// Call a function with buffer as temporary current buffer.
///
/// This temporarily switches current buffer to "buffer".
-/// If the current window already shows "buffer", the window is not switched
+/// If the current window already shows "buffer", the window is not switched.
/// If a window inside the current tabpage (including a float) already shows the
-/// buffer One of these windows will be set as current window temporarily.
+/// buffer, then one of these windows will be set as current window temporarily.
/// Otherwise a temporary scratch window (called the "autocmd window" for
/// historical reasons) will be used.
///
@@ -1375,7 +1375,7 @@ static inline void init_line_array(lua_State *lstate, Array *a, size_t size, Are
/// @param s String to push
/// @param len Size of string
/// @param idx 0-based index to place s (only used for Lua)
-/// @param replace_nl Replace newlines ('\n') with null ('\0')
+/// @param replace_nl Replace newlines ('\n') with null (NUL)
static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, int idx,
bool replace_nl, Arena *arena)
{
@@ -1384,7 +1384,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len,
if (s && replace_nl && strchr(s, '\n')) {
// TODO(bfredl): could manage scratch space in the arena, for the NUL case
char *tmp = xmemdupz(s, len);
- strchrsub(tmp, '\n', '\0');
+ strchrsub(tmp, '\n', NUL);
lua_pushlstring(lstate, tmp, len);
xfree(tmp);
} else {
@@ -1397,7 +1397,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len,
str = CBUF_TO_ARENA_STR(arena, s, len);
if (replace_nl) {
// Vim represents NULs as NLs, but this may confuse clients.
- strchrsub(str.data, '\n', '\0');
+ strchrsub(str.data, '\n', NUL);
}
}
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 779e216c74..5ad439af9c 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -193,7 +193,7 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err
} else {
nargs[0] = '0';
}
- nargs[1] = '\0';
+ nargs[1] = NUL;
PUT_KEY(result, cmd, nargs, CSTR_TO_ARENA_OBJ(arena, nargs));
char *addr;
@@ -391,7 +391,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
case kObjectTypeBoolean:
data_str = arena_alloc(arena, 2, false);
data_str[0] = elem.data.boolean ? '1' : '0';
- data_str[1] = '\0';
+ data_str[1] = NUL;
ADD_C(args, CSTR_AS_OBJ(data_str));
break;
case kObjectTypeBuffer:
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index af3bfe2c03..a1af354577 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -170,7 +170,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A
DecorInline decor = { .ext = true, .data.ext.vt = vt, .data.ext.sh_idx = DECOR_ID_INVALID };
extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, decor, 0, true,
- false, false, false, false, NULL);
+ false, false, false, NULL);
return src_id;
}
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 85cce45560..ab6ff5ff1f 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -18,6 +18,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
#include "nvim/extmark.h"
+#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/highlight_group.h"
#include "nvim/map_defs.h"
@@ -41,6 +42,7 @@ void api_extmark_free_all_mem(void)
xfree(name.data);
})
map_destroy(String, &namespace_ids);
+ set_destroy(uint32_t, &namespace_localscope);
}
/// Creates a new namespace or gets an existing one. [namespace]()
@@ -179,10 +181,6 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na
PUT_C(dict, "invalid", BOOLEAN_OBJ(true));
}
- if (mt_scoped(start)) {
- PUT_C(dict, "scoped", BOOLEAN_OBJ(true));
- }
-
decor_to_dict_legacy(&dict, mt_decor(start), hl_name, arena);
ADD_C(rv, DICTIONARY_OBJ(dict));
@@ -489,8 +487,6 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// used together with virt_text.
/// - url: A URL to associate with this extmark. In the TUI, the OSC 8 control
/// sequence is used to generate a clickable hyperlink to this URL.
-/// - scoped: boolean (EXPERIMENTAL) enables "scoping" for the extmark. See
-/// |nvim__win_add_ns()|
///
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
@@ -749,11 +745,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
if (opts->ephemeral && decor_state.win && decor_state.win->w_buffer == buf) {
- if (opts->scoped) {
- api_set_error(err, kErrorTypeException, "not yet implemented");
- goto error;
- }
-
int r = (int)line;
int c = (int)col;
if (line2 == -1) {
@@ -834,7 +825,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2,
decor, decor_flags, right_gravity, opts->end_right_gravity,
!GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore),
- opts->invalidate, opts->scoped, err);
+ opts->invalidate, err);
if (ERROR_SET(err)) {
decor_free(decor);
return 0;
@@ -960,7 +951,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In
decor.data.hl.hl_id = hl_id;
extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end,
- decor, MT_FLAG_DECOR_HL, true, false, false, false, false, NULL);
+ decor, MT_FLAG_DECOR_HL, true, false, false, false, NULL);
return ns_id;
}
@@ -1038,7 +1029,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start,
/// ```
/// - on_win: called when starting to redraw a specific window.
/// ```
-/// ["win", winid, bufnr, topline, botline]
+/// ["win", winid, bufnr, toprow, botrow]
/// ```
/// - on_line: called for each buffer line being redrawn.
/// (The interaction with fold lines is subject to change)
@@ -1217,77 +1208,119 @@ String nvim__buf_debug_extmarks(Buffer buffer, Boolean keys, Boolean dot, Error
/// EXPERIMENTAL: this API will change in the future.
///
-/// Scopes a namespace to the a window, so extmarks in the namespace will be active only in the
-/// given window.
+/// Set some properties for namespace
///
-/// @param window Window handle, or 0 for current window
/// @param ns_id Namespace
-/// @return true if the namespace was added, else false
-Boolean nvim__win_add_ns(Window window, Integer ns_id, Error *err)
+/// @param opts Optional parameters to set:
+/// - wins: a list of windows to be scoped in
+///
+void nvim__ns_set(Integer ns_id, Dict(ns_opts) *opts, Error *err)
{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return false;
- }
-
VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, {
- return false;
+ return;
});
- set_put(uint32_t, &win->w_ns_set, (uint32_t)ns_id);
+ bool set_scoped = true;
- if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
- changed_window_setting(win);
- }
+ if (HAS_KEY(opts, ns_opts, wins)) {
+ if (opts->wins.size == 0) {
+ set_scoped = false;
+ }
- return true;
-}
+ Set(ptr_t) windows = SET_INIT;
+ for (size_t i = 0; i < opts->wins.size; i++) {
+ Integer win = opts->wins.items[i].data.integer;
-/// EXPERIMENTAL: this API will change in the future.
-///
-/// Gets the namespace scopes for a given window.
-///
-/// @param window Window handle, or 0 for current window
-/// @return a list of namespaces ids
-ArrayOf(Integer) nvim__win_get_ns(Window window, Arena *arena, Error *err)
-{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return (Array)ARRAY_DICT_INIT;
+ win_T *wp = find_window_by_handle((Window)win, err);
+ if (!wp) {
+ return;
+ }
+
+ set_put(ptr_t, &windows, wp);
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(ptr_t, &windows, wp) && !set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ set_put(uint32_t, &wp->w_ns_set, (uint32_t)ns_id);
+
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id) && !set_has(ptr_t, &windows, wp)) {
+ set_del(uint32_t, &wp->w_ns_set, (uint32_t)ns_id);
+
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ }
+
+ set_destroy(ptr_t, &windows);
}
- Array rv = arena_array(arena, set_size(&win->w_ns_set));
- uint32_t i;
- set_foreach(&win->w_ns_set, i, {
- ADD_C(rv, INTEGER_OBJ((Integer)(i)));
- });
+ if (set_scoped && !set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ set_put(uint32_t, &namespace_localscope, (uint32_t)ns_id);
- return rv;
+ // When a namespace becomes scoped, any window which contains
+ // elements associated with namespace needs to be redrawn
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ } else if (!set_scoped && set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ set_del(uint32_t, &namespace_localscope, (uint32_t)ns_id);
+
+ // When a namespace becomes unscoped, any window which does not
+ // contain elements associated with namespace needs to be redrawn
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ }
}
/// EXPERIMENTAL: this API will change in the future.
///
-/// Unscopes a namespace (un-binds it from the given scope).
+/// Get the properties for namespace
///
-/// @param window Window handle, or 0 for current window
-/// @param ns_id the namespace to remove
-/// @return true if the namespace was removed, else false
-Boolean nvim__win_del_ns(Window window, Integer ns_id, Error *err)
+/// @param ns_id Namespace
+/// @return Map defining the namespace properties, see |nvim__ns_set()|
+Dict(ns_opts) nvim__ns_get(Integer ns_id, Arena *arena, Error *err)
{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return false;
+ Dict(ns_opts) opts = KEYDICT_INIT;
+
+ Array windows = ARRAY_DICT_INIT;
+
+ PUT_KEY(opts, ns_opts, wins, windows);
+
+ VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, {
+ return opts;
+ });
+
+ if (!set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ return opts;
}
- if (!set_has(uint32_t, &win->w_ns_set, (uint32_t)ns_id)) {
- return false;
+ size_t count = 0;
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ count++;
+ }
}
- set_del(uint32_t, &win->w_ns_set, (uint32_t)ns_id);
+ windows = arena_array(arena, count);
- if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
- changed_window_setting(win);
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ ADD(windows, INTEGER_OBJ(wp->handle));
+ }
}
- return true;
+ PUT_KEY(opts, ns_opts, wins, windows);
+
+ return opts;
}
diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h
index 124feaabfb..af2d51c95c 100644
--- a/src/nvim/api/extmark.h
+++ b/src/nvim/api/extmark.h
@@ -4,14 +4,29 @@
#include "nvim/api/keysets_defs.h" // IWYU pragma: keep
#include "nvim/api/private/defs.h" // IWYU pragma: keep
+#include "nvim/buffer_defs.h"
#include "nvim/decoration_defs.h" // IWYU pragma: keep
#include "nvim/macros_defs.h"
#include "nvim/map_defs.h"
#include "nvim/types_defs.h"
EXTERN Map(String, int) namespace_ids INIT( = MAP_INIT);
+/// Non-global namespaces. A locally-scoped namespace may be "orphaned" if all
+/// window(s) it was scoped to, are destroyed. Such orphans are tracked here to
+/// avoid being mistaken as "global scope".
+EXTERN Set(uint32_t) namespace_localscope INIT( = SET_INIT);
EXTERN handle_T next_namespace_id INIT( = 1);
+/// Returns true if the namespace is global or scoped in the given window.
+static inline bool ns_in_win(uint32_t ns_id, win_T *wp)
+{
+ if (!set_has(uint32_t, &namespace_localscope, ns_id)) {
+ return true;
+ }
+
+ return set_has(uint32_t, &wp->w_ns_set, ns_id);
+}
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/extmark.h.generated.h"
#endif
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index 00d8aa8428..cc2ef981b5 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -387,3 +387,8 @@ typedef struct {
Window win;
Buffer buf;
} Dict(redraw);
+
+typedef struct {
+ OptionalKeys is_set__ns_opts_;
+ Array wins;
+} Dict(ns_opts);
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index d9bc0ccc92..5adaff8449 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -54,6 +54,10 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
}
if (HAS_KEY_X(opts, buf)) {
+ VALIDATE(!(HAS_KEY_X(opts, scope) && *scope == OPT_GLOBAL), "%s",
+ "cannot use both global 'scope' and 'buf'", {
+ return FAIL;
+ });
*scope = OPT_LOCAL;
*req_scope = kOptReqBuf;
*from = find_buffer_by_handle(opts->buf, err);
@@ -68,11 +72,6 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
return FAIL;
});
- VALIDATE((!HAS_KEY_X(opts, scope) || !HAS_KEY_X(opts, buf)), "%s",
- "cannot use both 'scope' and 'buf'", {
- return FAIL;
- });
-
VALIDATE((!HAS_KEY_X(opts, win) || !HAS_KEY_X(opts, buf)),
"%s", "cannot use both 'buf' and 'win'", {
return FAIL;
diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c
index e198c671eb..9fd7d3bfa6 100644
--- a/src/nvim/api/private/validate.c
+++ b/src/nvim/api/private/validate.c
@@ -17,7 +17,7 @@ void api_err_invalid(Error *err, const char *name, const char *val_s, int64_t va
char *has_space = strchr(name, ' ');
// No value.
- if (val_s && val_s[0] == '\0') {
+ if (val_s && val_s[0] == NUL) {
api_set_error(err, errtype, has_space ? "Invalid %s" : "Invalid '%s'", name);
return;
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 52ab18cbff..26dc223948 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -28,6 +28,7 @@
#include "nvim/cursor.h"
#include "nvim/decoration.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -313,7 +314,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
keys_esc = keys.data;
}
if (lowlevel) {
- input_enqueue_raw(cstr_as_string(keys_esc));
+ input_enqueue_raw(keys_esc, strlen(keys_esc));
} else {
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
insert ? 0 : typebuf.tb_len, !typed, false);
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 477cbe2428..124c26d175 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -109,7 +109,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *
// redir usually (except :echon) prepends a newline.
if (s.data[0] == '\n') {
memmove(s.data, s.data + 1, s.size - 1);
- s.data[s.size - 1] = '\0';
+ s.data[s.size - 1] = NUL;
s.size = s.size - 1;
}
return s; // Caller will free the memory.
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 70235d8db6..f0b90d8512 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -17,6 +17,7 @@
#include "nvim/decoration.h"
#include "nvim/decoration_defs.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/window.h"
#include "nvim/extmark_defs.h"
#include "nvim/globals.h"
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 54a19513db..92dc9dc7e3 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -13,6 +13,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/window.h"
#include "nvim/ex_docmd.h"
#include "nvim/gettext_defs.h"
diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c
index 4d493c9d03..700bfc1655 100644
--- a/src/nvim/arglist.c
+++ b/src/nvim/arglist.c
@@ -13,6 +13,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/window.h"
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index c5d81d4cd2..ebed3e6f03 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -15,6 +15,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
@@ -710,7 +711,7 @@ char *au_event_disable(char *what)
if (*what == ',' && *p_ei == NUL) {
STRCPY(new_ei, what + 1);
} else {
- STRCAT(new_ei, what);
+ strcat(new_ei, what);
}
set_option_direct(kOptEventignore, CSTR_AS_OPTVAL(new_ei), 0, SID_NONE);
xfree(new_ei);
@@ -823,11 +824,11 @@ void do_autocmd(exarg_T *eap, char *arg_in, int forceit)
continue;
}
- invalid_flags |= arg_autocmd_flag_get(&once, &cmd, "++once", 6);
- invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "++nested", 8);
+ invalid_flags |= arg_autocmd_flag_get(&once, &cmd, S_LEN("++once"));
+ invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, S_LEN("++nested"));
// Check the deprecated "nested" flag.
- invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "nested", 6);
+ invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, S_LEN("nested"));
}
if (invalid_flags) {
@@ -1244,7 +1245,7 @@ void ex_doautoall(exarg_T *eap)
bool check_nomodeline(char **argp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- if (strncmp(*argp, "<nomodeline>", 12) == 0) {
+ if (strncmp(*argp, S_LEN("<nomodeline>")) == 0) {
*argp = skipwhite(*argp + 12);
return false;
}
@@ -2358,7 +2359,7 @@ theend:
bool aupat_is_buflocal(const char *pat, int patlen)
FUNC_ATTR_PURE
{
- return patlen >= 8 && strncmp(pat, "<buffer", 7) == 0 && (pat)[patlen - 1] == '>';
+ return patlen >= 8 && strncmp(pat, S_LEN("<buffer")) == 0 && (pat)[patlen - 1] == '>';
}
int aupat_get_buflocal_nr(const char *pat, int patlen)
diff --git a/src/nvim/base64.c b/src/nvim/base64.c
index a645c64fe3..99d3c5a33e 100644
--- a/src/nvim/base64.c
+++ b/src/nvim/base64.c
@@ -4,6 +4,7 @@
#include <string.h>
#include "auto/config.h" // IWYU pragma: keep
+#include "nvim/ascii_defs.h"
#include "nvim/base64.h"
#include "nvim/memory.h"
@@ -125,7 +126,7 @@ char *base64_encode(const char *src, size_t src_len)
dest[out_i] = '=';
}
- dest[out_len] = '\0';
+ dest[out_len] = NUL;
return dest;
}
@@ -141,6 +142,7 @@ char *base64_encode(const char *src, size_t src_len)
/// @param [out] out_lenp Returns the length of the decoded string
/// @return Decoded string
char *base64_decode(const char *src, size_t src_len, size_t *out_lenp)
+ FUNC_ATTR_NONNULL_ALL
{
assert(src != NULL);
assert(out_lenp != NULL);
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 39d0d24d47..3f4e7047f9 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -43,6 +43,7 @@
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
@@ -2076,6 +2077,7 @@ void free_buf_options(buf_T *buf, bool free_p_ff)
clear_string_option(&buf->b_p_lop);
clear_string_option(&buf->b_p_cinsd);
clear_string_option(&buf->b_p_cinw);
+ clear_string_option(&buf->b_p_cot);
clear_string_option(&buf->b_p_cpt);
clear_string_option(&buf->b_p_cfu);
callback_free(&buf->b_cfu_cb);
@@ -3848,8 +3850,8 @@ static int chk_modeline(linenr_T lnum, int flags)
int prev = -1;
for (s = ml_get(lnum); *s != NUL; s++) {
if (prev == -1 || ascii_isspace(prev)) {
- if ((prev != -1 && strncmp(s, "ex:", 3) == 0)
- || strncmp(s, "vi:", 3) == 0) {
+ if ((prev != -1 && strncmp(s, S_LEN("ex:")) == 0)
+ || strncmp(s, S_LEN("vi:")) == 0) {
break;
}
// Accept both "vim" and "Vim".
@@ -3865,7 +3867,7 @@ static int chk_modeline(linenr_T lnum, int flags)
if (*e == ':'
&& (s[0] != 'V'
- || strncmp(skipwhite(e + 1), "set", 3) == 0)
+ || strncmp(skipwhite(e + 1), S_LEN("set")) == 0)
&& (s[3] == ':'
|| (VIM_VERSION_100 >= vers && isdigit((uint8_t)s[3]))
|| (VIM_VERSION_100 < vers && s[3] == '<')
@@ -3914,8 +3916,8 @@ static int chk_modeline(linenr_T lnum, int flags)
// "vi:set opt opt opt: foo" -- foo not interpreted
// "vi:opt opt opt: foo" -- foo interpreted
// Accept "se" for compatibility with Elvis.
- if (strncmp(s, "set ", 4) == 0
- || strncmp(s, "se ", 3) == 0) {
+ if (strncmp(s, S_LEN("set ")) == 0
+ || strncmp(s, S_LEN("se ")) == 0) {
if (*e != ':') { // no terminating ':'?
break;
}
@@ -4207,7 +4209,7 @@ int buf_open_scratch(handle_T bufnr, char *bufname)
bool buf_is_empty(buf_T *buf)
{
- return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == '\0';
+ return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == NUL;
}
/// Increment b:changedtick value
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 512247047c..221a86a907 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -533,6 +533,8 @@ struct file_buffer {
char *b_p_cinsd; ///< 'cinscopedecls'
char *b_p_com; ///< 'comments'
char *b_p_cms; ///< 'commentstring'
+ char *b_p_cot; ///< 'completeopt' local value
+ unsigned b_cot_flags; ///< flags for 'completeopt'
char *b_p_cpt; ///< 'complete'
#ifdef BACKSLASH_IN_FILENAME
char *b_p_csl; ///< 'completeslash'
diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c
index 27de03954a..5522ab1ca3 100644
--- a/src/nvim/bufwrite.c
+++ b/src/nvim/bufwrite.c
@@ -18,6 +18,7 @@
#include "nvim/bufwrite.h"
#include "nvim/change.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds.h"
@@ -1065,7 +1066,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
bool whole = (start == 1 && end == buf->b_ml.ml_line_count);
bool write_undo_file = false;
context_sha256_T sha_ctx;
- unsigned bkc = get_bkc_value(buf);
+ unsigned bkc = get_bkc_flags(buf);
if (fname == NULL || *fname == NUL) { // safety check
return FAIL;
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 05772d39e9..6c979df1fe 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -1723,12 +1723,12 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Below, set_indent(newindent, SIN_INSERT) will insert the
// whitespace needed before the comment char.
for (int i = 0; i < padding; i++) {
- STRCAT(leader, " ");
+ strcat(leader, " ");
less_cols--;
newcol++;
}
}
- STRCAT(leader, p_extra);
+ strcat(leader, p_extra);
p_extra = leader;
did_ai = true; // So truncating blanks works with comments
less_cols -= lead_len;
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 41635747f8..e3df12abbe 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -13,6 +13,7 @@
#include "nvim/autocmd_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/channel.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
@@ -38,8 +39,6 @@
#include "nvim/os/os_defs.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/terminal.h"
#include "nvim/types_defs.h"
@@ -126,19 +125,19 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
*error = e_invstream;
return false;
}
- stream_may_close(&chan->stream.socket);
+ rstream_may_close(&chan->stream.socket);
break;
case kChannelStreamProc:
proc = &chan->stream.proc;
if (part == kChannelPartStdin || close_main) {
- stream_may_close(&proc->in);
+ wstream_may_close(&proc->in);
}
if (part == kChannelPartStdout || close_main) {
- stream_may_close(&proc->out);
+ rstream_may_close(&proc->out);
}
if (part == kChannelPartStderr || part == kChannelPartAll) {
- stream_may_close(&proc->err);
+ rstream_may_close(&proc->err);
}
if (proc->type == kProcessTypePty && part == kChannelPartAll) {
pty_process_close_master(&chan->stream.pty);
@@ -148,10 +147,10 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
case kChannelStreamStdio:
if (part == kChannelPartStdin || close_main) {
- stream_may_close(&chan->stream.stdio.in);
+ rstream_may_close(&chan->stream.stdio.in);
}
if (part == kChannelPartStdout || close_main) {
- stream_may_close(&chan->stream.stdio.out);
+ wstream_may_close(&chan->stream.stdio.out);
}
if (part == kChannelPartStderr) {
*error = e_invstream;
@@ -431,7 +430,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s
wstream_init(&proc->in, 0);
}
if (has_out) {
- rstream_init(&proc->out, 0);
+ rstream_init(&proc->out);
}
if (rpc) {
@@ -446,7 +445,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s
if (has_err) {
callback_reader_start(&chan->on_stderr, "stderr");
- rstream_init(&proc->err, 0);
+ rstream_init(&proc->err);
rstream_start(&proc->err, on_job_stderr, chan);
}
@@ -480,10 +479,10 @@ uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader
return 0;
}
- channel->stream.socket.internal_close_cb = close_cb;
- channel->stream.socket.internal_data = channel;
- wstream_init(&channel->stream.socket, 0);
- rstream_init(&channel->stream.socket, 0);
+ channel->stream.socket.s.internal_close_cb = close_cb;
+ channel->stream.socket.s.internal_data = channel;
+ wstream_init(&channel->stream.socket.s, 0);
+ rstream_init(&channel->stream.socket);
if (rpc) {
rpc_start(channel);
@@ -505,10 +504,10 @@ void channel_from_connection(SocketWatcher *watcher)
{
Channel *channel = channel_alloc(kChannelStreamSocket);
socket_watcher_accept(watcher, &channel->stream.socket);
- channel->stream.socket.internal_close_cb = close_cb;
- channel->stream.socket.internal_data = channel;
- wstream_init(&channel->stream.socket, 0);
- rstream_init(&channel->stream.socket, 0);
+ channel->stream.socket.s.internal_close_cb = close_cb;
+ channel->stream.socket.s.internal_data = channel;
+ wstream_init(&channel->stream.socket.s, 0);
+ rstream_init(&channel->stream.socket);
rpc_start(channel);
channel_create_event(channel, watcher->addr);
}
@@ -553,7 +552,7 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **err
dup2(STDERR_FILENO, STDIN_FILENO);
}
#endif
- rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd, 0);
+ rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd);
wstream_init_fd(&main_loop, &channel->stream.stdio.out, stdout_dup_fd, 0);
if (rpc) {
@@ -640,58 +639,45 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len)
list_T *const l = tv_list_alloc(kListLenMayKnow);
// Empty buffer should be represented by [''], encode_list_write() thinks
// empty list is fine for the case.
- tv_list_append_string(l, "", 0);
+ tv_list_append_string(l, S_LEN(""));
if (len > 0) {
encode_list_write(l, buf, len);
}
return l;
}
-void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+size_t on_channel_data(RStream *stream, const char *buf, size_t count, void *data, bool eof)
{
Channel *chan = data;
- on_channel_output(stream, chan, buf, eof, &chan->on_data);
+ return on_channel_output(stream, chan, buf, count, eof, &chan->on_data);
}
-void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+size_t on_job_stderr(RStream *stream, const char *buf, size_t count, void *data, bool eof)
{
Channel *chan = data;
- on_channel_output(stream, chan, buf, eof, &chan->on_stderr);
+ return on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr);
}
-static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool eof,
- CallbackReader *reader)
+static size_t on_channel_output(RStream *stream, Channel *chan, const char *buf, size_t count,
+ bool eof, CallbackReader *reader)
{
- size_t count;
- char *output = rbuffer_read_ptr(buf, &count);
-
if (chan->term) {
- if (!eof) {
- char *p = output;
- char *end = output + count;
+ if (count) {
+ const char *p = buf;
+ const char *end = buf + count;
while (p < end) {
// Don't pass incomplete UTF-8 sequences to libvterm. #16245
// Composing chars can be passed separately, so utf_ptr2len_len() is enough.
int clen = utf_ptr2len_len(p, (int)(end - p));
if (clen > end - p) {
- count = (size_t)(p - output);
+ count = (size_t)(p - buf);
break;
}
p += clen;
}
}
- terminal_receive(chan->term, output, count);
- }
-
- if (count) {
- rbuffer_consumed(buf, count);
- }
- // Move remaining data to start of buffer, so the buffer can never wrap around.
- rbuffer_reset(buf);
-
- if (callback_reader_set(*reader)) {
- ga_concat_len(&reader->buffer, output, count);
+ terminal_receive(chan->term, buf, count);
}
if (eof) {
@@ -699,8 +685,11 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool
}
if (callback_reader_set(*reader)) {
+ ga_concat_len(&reader->buffer, buf, count);
schedule_channel_event(chan);
}
+
+ return count;
}
/// schedule the necessary callbacks to be invoked as a deferred event
@@ -864,7 +853,7 @@ static void term_resize(uint16_t width, uint16_t height, void *data)
static inline void term_delayed_free(void **argv)
{
Channel *chan = argv[0];
- if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.pending_reqs) {
+ if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.s.pending_reqs) {
multiqueue_put(chan->events, term_delayed_free, chan);
return;
}
diff --git a/src/nvim/channel.h b/src/nvim/channel.h
index 35d369e513..72480db0d5 100644
--- a/src/nvim/channel.h
+++ b/src/nvim/channel.h
@@ -30,7 +30,7 @@ struct Channel {
Process proc;
LibuvProcess uv;
PtyProcess pty;
- Stream socket;
+ RStream socket;
StdioPair stdio;
StderrState err;
InternalState internal;
@@ -73,7 +73,7 @@ static inline Stream *channel_instream(Channel *chan)
return &chan->stream.proc.in;
case kChannelStreamSocket:
- return &chan->stream.socket;
+ return &chan->stream.socket.s;
case kChannelStreamStdio:
return &chan->stream.stdio.out;
@@ -85,10 +85,10 @@ static inline Stream *channel_instream(Channel *chan)
abort();
}
-static inline Stream *channel_outstream(Channel *chan)
+static inline RStream *channel_outstream(Channel *chan)
REAL_FATTR_NONNULL_ALL;
-static inline Stream *channel_outstream(Channel *chan)
+static inline RStream *channel_outstream(Channel *chan)
{
switch (chan->streamtype) {
case kChannelStreamProc:
diff --git a/src/nvim/channel_defs.h b/src/nvim/channel_defs.h
index d4f1895420..2df6edea7a 100644
--- a/src/nvim/channel_defs.h
+++ b/src/nvim/channel_defs.h
@@ -30,7 +30,7 @@ typedef enum {
} ChannelStdinMode;
typedef struct {
- Stream in;
+ RStream in;
Stream out;
} StdioPair;
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index c611d4cfd6..430f6b15fe 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -1470,7 +1470,7 @@ start:
*dst++ = *p++;
}
}
- *dst = '\0';
+ *dst = NUL;
}
}
@@ -1492,6 +1492,6 @@ char *backslash_halve_save(const char *p)
*dst++ = *p++;
}
}
- *dst = '\0';
+ *dst = NUL;
return res;
}
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 808df44941..fdb452aee4 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -19,6 +19,7 @@
#include "nvim/cmdexpand.h"
#include "nvim/cmdhist.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
@@ -2246,7 +2247,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff)
// Does command allow "++argopt" argument?
if (ea.argt & EX_ARGOPT) {
- while (*arg != NUL && strncmp(arg, "++", 2) == 0) {
+ while (*arg != NUL && strncmp(arg, S_LEN("++")) == 0) {
p = arg + 2;
while (*p && !ascii_isspace(*p)) {
MB_PTR_ADV(p);
@@ -2773,7 +2774,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
// When expanding a function name starting with s:, match the <SNR>nr_
// prefix.
char *tofree = NULL;
- if (xp->xp_context == EXPAND_USER_FUNC && strncmp(pat, "^s:", 3) == 0) {
+ if (xp->xp_context == EXPAND_USER_FUNC && strncmp(pat, S_LEN("^s:")) == 0) {
const size_t len = strlen(pat) + 20;
tofree = xmalloc(len);
@@ -3074,7 +3075,7 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
typval_T args[4];
const sctx_T save_current_sctx = current_sctx;
- if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) {
+ if (xp->xp_arg == NULL || xp->xp_arg[0] == NUL || xp->xp_line == NULL) {
return NULL;
}
@@ -3256,7 +3257,7 @@ void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dir
copy_option_part(&path, buf, MAXPATHL, ",");
if (strlen(buf) + strlen(file) + 2 < MAXPATHL) {
add_pathsep(buf);
- STRCAT(buf, file);
+ strcat(buf, file);
char **p;
int num_p = 0;
@@ -3563,7 +3564,7 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (xpc.xp_context == EXPAND_USER_DEFINED) {
// Must be "custom,funcname" pattern
- if (strncmp(type, "custom,", 7) != 0) {
+ if (strncmp(type, S_LEN("custom,")) != 0) {
semsg(_(e_invarg2), type);
return;
}
@@ -3573,7 +3574,7 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (xpc.xp_context == EXPAND_USER_LIST) {
// Must be "customlist,funcname" pattern
- if (strncmp(type, "customlist,", 11) != 0) {
+ if (strncmp(type, S_LEN("customlist,")) != 0) {
semsg(_(e_invarg2), type);
return;
}
diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c
index 983ab8b59b..ab05ae1cfc 100644
--- a/src/nvim/cmdhist.c
+++ b/src/nvim/cmdhist.c
@@ -11,6 +11,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/cmdhist.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
diff --git a/src/nvim/context.c b/src/nvim/context.c
index 95e2618f62..b8eecfbb16 100644
--- a/src/nvim/context.c
+++ b/src/nvim/context.c
@@ -261,7 +261,7 @@ static inline void ctx_save_funcs(Context *ctx, bool scriptonly)
HASHTAB_ITER(func_tbl_get(), hi, {
const char *const name = hi->hi_key;
- bool islambda = (strncmp(name, "<lambda>", 8) == 0);
+ bool islambda = (strncmp(name, S_LEN("<lambda>")) == 0);
bool isscript = ((uint8_t)name[0] == K_SPECIAL);
if (!islambda && (!scriptonly || isscript)) {
@@ -299,7 +299,7 @@ static inline void ctx_restore_funcs(Context *ctx)
static inline Array sbuf_to_array(msgpack_sbuffer sbuf, Arena *arena)
{
list_T *const list = tv_list_alloc(kListLenMayKnow);
- tv_list_append_string(list, "", 0);
+ tv_list_append_string(list, S_LEN(""));
if (sbuf.size > 0) {
encode_list_write(list, sbuf.data, sbuf.size);
}
diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c
index 7d87b61ce5..ffbeee7f7a 100644
--- a/src/nvim/debugger.c
+++ b/src/nvim/debugger.c
@@ -13,6 +13,7 @@
#include "nvim/cmdexpand_defs.h"
#include "nvim/debugger.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -520,18 +521,18 @@ static int dbg_parsearg(char *arg, garray_T *gap)
struct debuggy *bp = &DEBUGGY(gap, gap->ga_len);
// Find "func" or "file".
- if (strncmp(p, "func", 4) == 0) {
+ if (strncmp(p, S_LEN("func")) == 0) {
bp->dbg_type = DBG_FUNC;
- } else if (strncmp(p, "file", 4) == 0) {
+ } else if (strncmp(p, S_LEN("file")) == 0) {
bp->dbg_type = DBG_FILE;
- } else if (gap != &prof_ga && strncmp(p, "here", 4) == 0) {
+ } else if (gap != &prof_ga && strncmp(p, S_LEN("here")) == 0) {
if (curbuf->b_ffname == NULL) {
emsg(_(e_noname));
return FAIL;
}
bp->dbg_type = DBG_FILE;
here = true;
- } else if (gap != &prof_ga && strncmp(p, "expr", 4) == 0) {
+ } else if (gap != &prof_ga && strncmp(p, S_LEN("expr")) == 0) {
bp->dbg_type = DBG_EXPR;
} else {
semsg(_(e_invarg2), p);
@@ -558,7 +559,7 @@ static int dbg_parsearg(char *arg, garray_T *gap)
}
if (bp->dbg_type == DBG_FUNC) {
- bp->dbg_name = xstrdup(strncmp(p, "g:", 2) == 0 ? p + 2 : p);
+ bp->dbg_name = xstrdup(strncmp(p, S_LEN("g:")) == 0 ? p + 2 : p);
} else if (here) {
bp->dbg_name = xstrdup(curbuf->b_ffname);
} else if (bp->dbg_type == DBG_EXPR) {
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 303d0318b5..0cf02d96da 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -15,6 +15,7 @@
#include "nvim/drawscreen.h"
#include "nvim/extmark.h"
#include "nvim/fold.h"
+#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
@@ -88,7 +89,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start
extmark_set(buf, (uint32_t)src_id, NULL,
(int)lnum - 1, hl_start, (int)lnum - 1 + end_off, hl_end,
- decor, MT_FLAG_DECOR_HL, true, false, true, false, false, NULL);
+ decor, MT_FLAG_DECOR_HL, true, false, true, false, NULL);
}
}
@@ -184,6 +185,21 @@ void buf_put_decor(buf_T *buf, DecorInline decor, int row, int row2)
}
}
+/// When displaying signs in the 'number' column, if the width of the number
+/// column is less than 2, then force recomputing the width after placing or
+/// unplacing the first sign in "buf".
+static void may_force_numberwidth_recompute(buf_T *buf, bool unplace)
+{
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf
+ && wp->w_minscwidth == SCL_NUM
+ && (wp->w_p_nu || wp->w_p_rnu)
+ && (unplace || wp->w_nrwidth_width < 2)) {
+ wp->w_nrwidth_line_count = 0;
+ }
+ }
+}
+
static int sign_add_id = 0;
void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
{
@@ -191,6 +207,7 @@ void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
sh->sign_add_id = sign_add_id++;
if (sh->text[0]) {
buf_signcols_count_range(buf, row1, row2, 1, kFalse);
+ may_force_numberwidth_recompute(buf, false);
}
}
}
@@ -218,6 +235,7 @@ void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh)
if (buf_meta_total(buf, kMTMetaSignText)) {
buf_signcols_count_range(buf, row1, row2, -1, kFalse);
} else {
+ may_force_numberwidth_recompute(buf, true);
buf->b_signcols.resized = true;
buf->b_signcols.max = buf->b_signcols.count[0] = 0;
}
@@ -580,7 +598,7 @@ int decor_redraw_col(win_T *wp, int col, int win_col, bool hidden, DecorState *s
break;
}
- if (!mt_scoped_in_win(mark, wp)) {
+ if (!ns_in_win(mark.ns, wp)) {
goto next_mark;
}
@@ -729,7 +747,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[],
break;
}
if (!mt_end(mark) && !mt_invalid(mark) && mt_decor_sign(mark)
- && mt_scoped_in_win(mark, wp)) {
+ && ns_in_win(mark.ns, wp)) {
DecorSignHighlight *sh = decor_find_sign(mt_decor(mark));
num_text += (sh->text[0] != NUL);
kv_push(signs, ((SignItem){ sh, mark.id }));
@@ -909,7 +927,7 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo
while (true) {
MTKey mark = marktree_itr_current(itr);
DecorVirtText *vt = mt_decor_virt(mark);
- if (mt_scoped_in_win(mark, wp)) {
+ if (ns_in_win(mark.ns, wp)) {
while (vt) {
if (vt->flags & kVTIsLines) {
bool above = vt->flags & kVTLinesAbove;
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index ea846b46ec..750f0c3525 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -26,6 +26,7 @@
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
@@ -1019,7 +1020,7 @@ static int check_external_diff(diffio_T *diffio)
if (fd == NULL) {
io_error = true;
} else {
- if (fwrite("line1\n", 6, 1, fd) != 1) {
+ if (fwrite(S_LEN("line1\n"), 1, fd) != 1) {
io_error = true;
}
fclose(fd);
@@ -1028,7 +1029,7 @@ static int check_external_diff(diffio_T *diffio)
if (fd == NULL) {
io_error = true;
} else {
- if (fwrite("line2\n", 6, 1, fd) != 1) {
+ if (fwrite(S_LEN("line2\n"), 1, fd) != 1) {
io_error = true;
}
fclose(fd);
@@ -1049,8 +1050,8 @@ static int check_external_diff(diffio_T *diffio)
break;
}
- if (strncmp(linebuf, "1c1", 3) == 0
- || strncmp(linebuf, "@@ -1 +1 @@", 11) == 0) {
+ if (strncmp(linebuf, S_LEN("1c1")) == 0
+ || strncmp(linebuf, S_LEN("@@ -1 +1 @@")) == 0) {
ok = kTrue;
}
}
@@ -1272,10 +1273,10 @@ void ex_diffpatch(exarg_T *eap)
// Delete any .orig or .rej file created.
STRCPY(buf, tmp_new);
- STRCAT(buf, ".orig");
+ strcat(buf, ".orig");
os_remove(buf);
STRCPY(buf, tmp_new);
- STRCAT(buf, ".rej");
+ strcat(buf, ".rej");
os_remove(buf);
// Only continue if the output file was created.
@@ -1287,7 +1288,7 @@ void ex_diffpatch(exarg_T *eap)
} else {
if (curbuf->b_fname != NULL) {
newname = xstrnsave(curbuf->b_fname, strlen(curbuf->b_fname) + 4);
- STRCAT(newname, ".new");
+ strcat(newname, ".new");
}
// don't use a new tab page, each tab page has its own diffs
@@ -1582,13 +1583,13 @@ static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle)
// @@ -1,3 +1,5 @@
if (isdigit((uint8_t)(*line))) {
*diffstyle = DIFF_ED;
- } else if ((strncmp(line, "@@ ", 3) == 0)) {
+ } else if ((strncmp(line, S_LEN("@@ ")) == 0)) {
*diffstyle = DIFF_UNIFIED;
- } else if ((strncmp(line, "--- ", 4) == 0)
+ } else if ((strncmp(line, S_LEN("--- ")) == 0)
&& (vim_fgets(line, LBUFLEN, fd) == 0)
- && (strncmp(line, "+++ ", 4) == 0)
+ && (strncmp(line, S_LEN("+++ ")) == 0)
&& (vim_fgets(line, LBUFLEN, fd) == 0)
- && (strncmp(line, "@@ ", 3) == 0)) {
+ && (strncmp(line, S_LEN("@@ ")) == 0)) {
*diffstyle = DIFF_UNIFIED;
} else {
// Format not recognized yet, skip over this line. Cygwin diff
@@ -1606,7 +1607,7 @@ static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle)
}
} else {
assert(*diffstyle == DIFF_UNIFIED);
- if (strncmp(line, "@@ ", 3) != 0) {
+ if (strncmp(line, S_LEN("@@ ")) != 0) {
continue; // not the start of a diff block
}
if (parse_diff_unified(line, hunk) == FAIL) {
@@ -2472,70 +2473,70 @@ int diffopt_changed(void)
char *p = p_dip;
while (*p != NUL) {
// Note: Keep this in sync with p_dip_values
- if (strncmp(p, "filler", 6) == 0) {
+ if (strncmp(p, S_LEN("filler")) == 0) {
p += 6;
diff_flags_new |= DIFF_FILLER;
- } else if ((strncmp(p, "context:", 8) == 0) && ascii_isdigit(p[8])) {
+ } else if ((strncmp(p, S_LEN("context:")) == 0) && ascii_isdigit(p[8])) {
p += 8;
diff_context_new = getdigits_int(&p, false, diff_context_new);
- } else if (strncmp(p, "iblank", 6) == 0) {
+ } else if (strncmp(p, S_LEN("iblank")) == 0) {
p += 6;
diff_flags_new |= DIFF_IBLANK;
- } else if (strncmp(p, "icase", 5) == 0) {
+ } else if (strncmp(p, S_LEN("icase")) == 0) {
p += 5;
diff_flags_new |= DIFF_ICASE;
- } else if (strncmp(p, "iwhiteall", 9) == 0) {
+ } else if (strncmp(p, S_LEN("iwhiteall")) == 0) {
p += 9;
diff_flags_new |= DIFF_IWHITEALL;
- } else if (strncmp(p, "iwhiteeol", 9) == 0) {
+ } else if (strncmp(p, S_LEN("iwhiteeol")) == 0) {
p += 9;
diff_flags_new |= DIFF_IWHITEEOL;
- } else if (strncmp(p, "iwhite", 6) == 0) {
+ } else if (strncmp(p, S_LEN("iwhite")) == 0) {
p += 6;
diff_flags_new |= DIFF_IWHITE;
- } else if (strncmp(p, "horizontal", 10) == 0) {
+ } else if (strncmp(p, S_LEN("horizontal")) == 0) {
p += 10;
diff_flags_new |= DIFF_HORIZONTAL;
- } else if (strncmp(p, "vertical", 8) == 0) {
+ } else if (strncmp(p, S_LEN("vertical")) == 0) {
p += 8;
diff_flags_new |= DIFF_VERTICAL;
- } else if ((strncmp(p, "foldcolumn:", 11) == 0) && ascii_isdigit(p[11])) {
+ } else if ((strncmp(p, S_LEN("foldcolumn:")) == 0) && ascii_isdigit(p[11])) {
p += 11;
diff_foldcolumn_new = getdigits_int(&p, false, diff_foldcolumn_new);
- } else if (strncmp(p, "hiddenoff", 9) == 0) {
+ } else if (strncmp(p, S_LEN("hiddenoff")) == 0) {
p += 9;
diff_flags_new |= DIFF_HIDDEN_OFF;
- } else if (strncmp(p, "closeoff", 8) == 0) {
+ } else if (strncmp(p, S_LEN("closeoff")) == 0) {
p += 8;
diff_flags_new |= DIFF_CLOSE_OFF;
- } else if (strncmp(p, "followwrap", 10) == 0) {
+ } else if (strncmp(p, S_LEN("followwrap")) == 0) {
p += 10;
diff_flags_new |= DIFF_FOLLOWWRAP;
- } else if (strncmp(p, "indent-heuristic", 16) == 0) {
+ } else if (strncmp(p, S_LEN("indent-heuristic")) == 0) {
p += 16;
diff_indent_heuristic = XDF_INDENT_HEURISTIC;
- } else if (strncmp(p, "internal", 8) == 0) {
+ } else if (strncmp(p, S_LEN("internal")) == 0) {
p += 8;
diff_flags_new |= DIFF_INTERNAL;
- } else if (strncmp(p, "algorithm:", 10) == 0) {
+ } else if (strncmp(p, S_LEN("algorithm:")) == 0) {
// Note: Keep this in sync with p_dip_algorithm_values.
p += 10;
- if (strncmp(p, "myers", 5) == 0) {
+ if (strncmp(p, S_LEN("myers")) == 0) {
p += 5;
diff_algorithm_new = 0;
- } else if (strncmp(p, "minimal", 7) == 0) {
+ } else if (strncmp(p, S_LEN("minimal")) == 0) {
p += 7;
diff_algorithm_new = XDF_NEED_MINIMAL;
- } else if (strncmp(p, "patience", 8) == 0) {
+ } else if (strncmp(p, S_LEN("patience")) == 0) {
p += 8;
diff_algorithm_new = XDF_PATIENCE_DIFF;
- } else if (strncmp(p, "histogram", 9) == 0) {
+ } else if (strncmp(p, S_LEN("histogram")) == 0) {
p += 9;
diff_algorithm_new = XDF_HISTOGRAM_DIFF;
} else {
return FAIL;
}
- } else if ((strncmp(p, "linematch:", 10) == 0) && ascii_isdigit(p[10])) {
+ } else if ((strncmp(p, S_LEN("linematch:")) == 0) && ascii_isdigit(p[10])) {
p += 10;
linematch_lines_new = getdigits_int(&p, false, linematch_lines_new);
diff_flags_new |= DIFF_LINEMATCH;
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index a358a1723a..26fb77df30 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -12,6 +12,7 @@
#include "nvim/charset.h"
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds_defs.h"
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 4d534d78a2..4247705896 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -465,6 +465,7 @@ static void draw_sign(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, i
int fill = nrcol ? number_width(wp) + 1 : SIGN_WIDTH;
draw_col_fill(wlv, schar_from_ascii(' '), fill, attr);
int sign_pos = wlv->off - SIGN_WIDTH - (int)nrcol;
+ assert(sign_pos >= 0);
linebuf_char[sign_pos] = sattr.text[0];
linebuf_char[sign_pos + 1] = sattr.text[1];
} else {
@@ -1421,7 +1422,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
line = ml_get_buf(wp->w_buffer, lnum);
ptr = line + linecol;
- if (len == 0 || (int)wp->w_cursor.col > ptr - line) {
+ if (len == 0 || wp->w_cursor.col > linecol) {
// no bad word found at line start, don't check until end of a
// word
spell_hlf = HLF_COUNT;
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 039bbd219c..88e1f302da 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -931,13 +931,7 @@ int showmode(void)
msg_ext_clear(true);
}
- // Don't make non-flushed message part of the showmode and reset global
- // variables before flushing to to avoid recursiveness.
- bool draw_mode = redraw_mode;
- bool clear_cmd = clear_cmdline;
- redraw_cmdline = false;
- redraw_mode = false;
- clear_cmdline = false;
+ // Don't make non-flushed message part of the showmode.
msg_ext_ui_flush();
msg_grid_validate();
@@ -960,8 +954,8 @@ int showmode(void)
msg_check_for_delay(false);
// if the cmdline is more than one line high, erase top lines
- bool need_clear = clear_cmd;
- if (clear_cmd && cmdline_row < Rows - 1) {
+ bool need_clear = clear_cmdline;
+ if (clear_cmdline && cmdline_row < Rows - 1) {
msg_clr_cmdline(); // will reset clear_cmdline
}
@@ -1083,7 +1077,7 @@ int showmode(void)
}
mode_displayed = true;
- if (need_clear || clear_cmd || draw_mode) {
+ if (need_clear || clear_cmdline || redraw_mode) {
msg_clr_eos();
}
msg_didout = false; // overwrite this message
@@ -1092,10 +1086,10 @@ int showmode(void)
msg_no_more = false;
lines_left = save_lines_left;
need_wait_return = nwr_save; // never ask for hit-return for this
- } else if (clear_cmd && msg_silent == 0) {
+ } else if (clear_cmdline && msg_silent == 0) {
// Clear the whole command line. Will reset "clear_cmdline".
msg_clr_cmdline();
- } else if (draw_mode) {
+ } else if (redraw_mode) {
msg_pos_mode();
msg_clr_eos();
}
@@ -1118,6 +1112,10 @@ int showmode(void)
grid_line_flush();
}
+ redraw_cmdline = false;
+ redraw_mode = false;
+ clear_cmdline = false;
+
return length;
}
@@ -1548,6 +1546,7 @@ static void win_update(win_T *wp)
// Force redraw when width of 'number' or 'relativenumber' column changes.
if (wp->w_nrwidth != nrwidth_new) {
type = UPD_NOT_VALID;
+ changed_line_abv_curs_win(wp);
wp->w_nrwidth = nrwidth_new;
} else {
// Set mod_top to the first line that needs displaying because of
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 220b92d099..889f445c3d 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -18,6 +18,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
@@ -473,7 +474,8 @@ static int insert_check(VimState *state)
if (curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(),
curbuf->b_p_ts,
- curbuf->b_p_vts_array)
+ curbuf->b_p_vts_array,
+ false)
&& curwin->w_wrow == curwin->w_height_inner - 1 - get_scrolloff_value(curwin)
&& (curwin->w_cursor.lnum != curwin->w_topline
|| curwin->w_topfill > 0)) {
@@ -3093,7 +3095,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) {
p = get_cursor_line_ptr();
if (skipwhite(p) == p + curwin->w_cursor.col - 4
- && strncmp(p + curwin->w_cursor.col - 4, "else", 4) == 0) {
+ && strncmp(p + curwin->w_cursor.col - 4, S_LEN("else")) == 0) {
return true;
}
}
@@ -4419,18 +4421,30 @@ static bool ins_tab(void)
// Delete following spaces.
int i = cursor->col - fpos.col;
if (i > 0) {
- STRMOVE(ptr, ptr + i);
+ if (!(State & VREPLACE_FLAG)) {
+ char *newp = xmalloc((size_t)(curbuf->b_ml.ml_line_len - i));
+ ptrdiff_t col = ptr - curbuf->b_ml.ml_line_ptr;
+ if (col > 0) {
+ memmove(newp, ptr - col, (size_t)col);
+ }
+ memmove(newp + col, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - col - i));
+ if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) {
+ xfree(curbuf->b_ml.ml_line_ptr);
+ }
+ curbuf->b_ml.ml_line_ptr = newp;
+ curbuf->b_ml.ml_line_len -= i;
+ curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
+ inserted_bytes(fpos.lnum, change_col,
+ cursor->col - change_col, fpos.col - change_col);
+ } else {
+ STRMOVE(ptr, ptr + i);
+ }
// correct replace stack.
if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) {
for (temp = i; --temp >= 0;) {
replace_join(repl_off);
}
}
- if (!(State & VREPLACE_FLAG)) {
- curbuf->b_ml.ml_line_len -= i;
- inserted_bytes(fpos.lnum, change_col,
- cursor->col - change_col, fpos.col - change_col);
- }
}
cursor->col -= i;
diff --git a/src/nvim/errors.h b/src/nvim/errors.h
new file mode 100644
index 0000000000..39095db952
--- /dev/null
+++ b/src/nvim/errors.h
@@ -0,0 +1,193 @@
+#pragma once
+
+#include "nvim/gettext_defs.h"
+#include "nvim/macros_defs.h"
+
+//
+// Shared error messages. Excludes errors only used once and debugging messages.
+//
+// uncrustify:off
+EXTERN const char e_abort[] INIT(= N_("E470: Command aborted"));
+EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup"));
+EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
+EXTERN const char e_argreq[] INIT(= N_("E471: Argument required"));
+EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
+EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
+EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search"));
+EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s"));
+EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive"));
+EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded"));
+EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif"));
+EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry"));
+EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
+EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor"));
+EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while"));
+EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for"));
+EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)"));
+EXTERN const char e_failed[] INIT(= N_("E472: Command failed"));
+EXTERN const char e_internal[] INIT(= N_("E473: Internal error"));
+EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s"));
+EXTERN const char e_interr[] INIT(= N_("Interrupted"));
+EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument"));
+EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s"));
+EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s"));
+EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s"));
+EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s"));
+EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\""));
+EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range"));
+EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command"));
+EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory"));
+EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible"));
+EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id"));
+EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job"));
+EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full"));
+EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\""));
+EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty"));
+EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s"));
+EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel"));
+EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'"));
+EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64));
+EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
+EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s"));
+EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s"));
+EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number"));
+EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set"));
+EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off"));
+EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep"));
+EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file"));
+EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation"));
+EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed"));
+EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s"));
+EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet"));
+EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line"));
+EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping"));
+EXTERN const char e_nomatch[] INIT(= N_("E479: No match"));
+EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s"));
+EXTERN const char e_noname[] INIT(= N_("E32: No file name"));
+EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression"));
+EXTERN const char e_noprev[] INIT(= N_("E34: No previous command"));
+EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression"));
+EXTERN const char e_norange[] INIT(= N_("E481: No range allowed"));
+EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room"));
+EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name"));
+EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s"));
+EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s"));
+EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s"));
+EXTERN const char e_null[] INIT(= N_("E38: Null argument"));
+EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected"));
+EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s"));
+EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!"));
+EXTERN const char e_patnotf[] INIT(= N_("Pattern not found"));
+EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s"));
+EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive"));
+EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory"));
+
+EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors"));
+EXTERN const char e_loclist[] INIT(= N_("E776: No location list"));
+EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string"));
+EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program"));
+EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)"));
+EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s="));
+EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s"));
+EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable"));
+EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\""));
+EXTERN const char e_stringreq[] INIT(= N_("E928: String required"));
+EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required"));
+EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64));
+EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob"));
+EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s"));
+EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s"));
+EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\""));
+EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\""));
+EXTERN const char e_listreq[] INIT(= N_("E714: List required"));
+EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required"));
+EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary"));
+EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob"));
+EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
+EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox"));
+EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here"));
+EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window"));
+EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported"));
+EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size"));
+EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty"));
+EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!"));
+EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file"));
+EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex"));
+EXTERN const char e_longname[] INIT(= N_("E75: Name too long"));
+EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many ["));
+EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names"));
+EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters"));
+EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s"));
+EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark"));
+EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards"));
+EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'"));
+EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'"));
+EXTERN const char e_write[] INIT(= N_("E80: Error while writing"));
+EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required"));
+EXTERN const char e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context"));
+EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s"));
+EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer"));
+EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist"));
+
+EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function"));
+
+EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter"));
+EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer"));
+EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set"));
+EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name"));
+EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\""));
+EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior"));
+EXTERN const char e_menu_only_exists_in_another_mode[]
+INIT(= N_("E328: Menu only exists in another mode"));
+EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window"));
+EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List"));
+EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
+EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long"));
+EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String"));
+EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now"));
+EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d"));
+EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s"));
+EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort"));
+
+EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s"));
+
+EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
+
+EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain"));
+EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float"));
+
+EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events"));
+
+EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long"));
+
+EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range"));
+
+EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name"));
+
+EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long"));
+
+EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld"));
+EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld"));
+
+EXTERN const char e_stray_closing_curly_str[]
+INIT(= N_("E1278: Stray '}' without a matching '{': %s"));
+EXTERN const char e_missing_close_curly_str[]
+INIT(= N_("E1279: Missing '}': %s"));
+
+EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s"));
+
+EXTERN const char e_undobang_cannot_redo_or_move_branch[]
+INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch"));
+
+EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
+INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
+
+EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
+
+EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s"));
+
+EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
+EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
+
+EXTERN const char line_msg[] INIT(= N_(" line "));
+// uncrustify:on
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 48a58228ae..4cff5e1582 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -24,6 +24,7 @@
#include "nvim/cmdhist.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/executor.h"
@@ -1218,7 +1219,7 @@ int call_vim_function(const char *func, int argc, typval_T *argv, typval_T *rett
int len = (int)strlen(func);
partial_T *pt = NULL;
- if (len >= 6 && !memcmp(func, "v:lua.", 6)) {
+ if (len >= 6 && !memcmp(func, S_LEN("v:lua."))) {
func += 6;
len = check_luafunc_name(func, false);
if (len == 0) {
@@ -2160,7 +2161,7 @@ void del_menutrans_vars(void)
{
hash_lock(&globvarht);
HASHTAB_ITER(&globvarht, hi, {
- if (strncmp(hi->hi_key, "menutrans_", 10) == 0) {
+ if (strncmp(hi->hi_key, S_LEN("menutrans_")) == 0) {
delete_var(&globvarht, hi);
}
});
@@ -3273,7 +3274,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
check_vars(s, (size_t)len);
// If evaluate is false rettv->v_type was not set, but it's needed
// in handle_subscript() to parse v:lua, so set it here.
- if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, "v:lua.", 6)) {
+ if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, S_LEN("v:lua."))) {
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = vvlua_partial;
rettv->vval.v_partial->pt_refcount++;
@@ -3482,7 +3483,7 @@ static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const
int len;
char *name = *arg;
char *lua_funcname = NULL;
- if (strnequal(name, "v:lua.", 6)) {
+ if (strnequal(name, S_LEN("v:lua."))) {
lua_funcname = name + 6;
*arg = (char *)skip_luafunc_name(lua_funcname);
*arg = skipwhite(*arg); // to detect trailing whitespace later
@@ -5617,7 +5618,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref)
int dict_idx = 0;
int arg_idx = 0;
list_T *list = NULL;
- if (strncmp(s, "s:", 2) == 0 || strncmp(s, "<SID>", 5) == 0) {
+ if (strncmp(s, S_LEN("s:")) == 0 || strncmp(s, S_LEN("<SID>")) == 0) {
// Expand s: and <SID> into <SNR>nr_, so that the function can
// also be called from another script. Using trans_function_name()
// would also work, but some plugins depend on the name being
@@ -6191,7 +6192,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co
case kCallbackFuncref:
name = callback->data.funcref;
int len = (int)strlen(name);
- if (len >= 6 && !memcmp(name, "v:lua.", 6)) {
+ if (len >= 6 && !memcmp(name, S_LEN("v:lua."))) {
name += 6;
len = check_luafunc_name(name, false);
if (len == 0) {
@@ -6459,7 +6460,7 @@ bool write_list(FileDescriptor *const fp, const list_T *const list, const bool b
}
}
if (!binary || TV_LIST_ITEM_NEXT(list, li) != NULL) {
- const ptrdiff_t written = file_write(fp, "\n", 1);
+ const ptrdiff_t written = file_write(fp, S_LEN("\n"));
if (written < 0) {
error = (int)written;
goto write_list_error;
@@ -7153,8 +7154,8 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex
retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start)
+ (size_t)(in_end - expr_end) + 1);
STRCPY(retval, in_start);
- STRCAT(retval, temp_result);
- STRCAT(retval, expr_end + 1);
+ strcat(retval, temp_result);
+ strcat(retval, expr_end + 1);
}
xfree(temp_result);
@@ -8909,7 +8910,7 @@ bool eval_has_provider(const char *feat, bool throw_if_fast)
char name[32]; // Normalized: "python3_compiled" => "python3".
snprintf(name, sizeof(name), "%s", feat);
- strchrsub(name, '_', '\0'); // Chop any "_xx" suffix.
+ strchrsub(name, '_', NUL); // Chop any "_xx" suffix.
char buf[256];
typval_T tv;
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index ceaba11f41..f5706f9553 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -19,7 +19,7 @@
--- @field returns_desc? string
--- @field signature? string
--- @field desc? string
---- @field params {[1]:string, [2]:string, [3]:string}[]
+--- @field params [string, string, string][]
--- @field lua? false Do not render type information
--- @field tags? string[] Extra tags
--- @field data? string Used by gen_eval.lua
@@ -3448,7 +3448,7 @@ M.funcs = {
<
]=],
name = 'getchar',
- params = {},
+ params = { { 'expr', '0|1' } },
returns = 'integer',
signature = 'getchar([{expr}])',
},
@@ -3537,7 +3537,7 @@ M.funcs = {
result is converted to a string.
]=],
name = 'getcharstr',
- params = {},
+ params = { { 'expr', '0|1' } },
returns = 'string',
signature = 'getcharstr([{expr}])',
},
@@ -4047,8 +4047,9 @@ M.funcs = {
]=],
name = 'getmarklist',
- params = { { 'buf', 'any' } },
+ params = { { 'buf', 'integer?' } },
signature = 'getmarklist([{buf}])',
+ returns = 'vim.fn.getmarklist.ret.item[]',
},
getmatches = {
args = { 0, 1 },
@@ -6080,10 +6081,21 @@ M.funcs = {
display isn't updated, e.g. in silent Ex mode)
w$ last line visible in current window (this is one
less than "w0" if no lines are visible)
- v In Visual mode: the start of the Visual area (the
- cursor is the end). When not in Visual mode
- returns the cursor position. Differs from |'<| in
- that it's updated right away.
+ v When not in Visual mode, returns the cursor
+ position. In Visual mode, returns the other end
+ of the Visual area. A good way to think about
+ this is that in Visual mode "v" and "." complement
+ each other. While "." refers to the cursor
+ position, "v" refers to where |v_o| would move the
+ cursor. As a result, you can use "v" and "."
+ together to work on all of a selection in
+ characterwise visual mode. If the cursor is at
+ the end of a characterwise visual area, "v" refers
+ to the start of the same visual area. And if the
+ cursor is at the start of a characterwise visual
+ area, "v" refers to the end of the same visual
+ area. "v" differs from |'<| and |'>| in that it's
+ updated right away.
Note that a mark in another file can be used. The line number
then applies to another buffer.
To get the column number use |col()|. To get both use
@@ -6481,7 +6493,8 @@ M.funcs = {
echo printf("Operator-pending mode bit: 0x%x", op_bit)
]],
name = 'maplist',
- params = {},
+ params = { { 'abbr', '0|1' } },
+ returns = 'table[]',
signature = 'maplist([{abbr}])',
},
mapnew = {
@@ -9142,7 +9155,16 @@ M.funcs = {
<
]=],
name = 'searchpair',
- params = {},
+ params = {
+ { 'start', 'any' },
+ { 'middle', 'any' },
+ { 'end', 'any' },
+ { 'flags', 'string' },
+ { 'skip', 'any' },
+ { 'stopline', 'any' },
+ { 'timeout', 'integer' },
+ },
+ returns = 'integer',
signature = 'searchpair({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]])',
},
searchpairpos = {
@@ -9159,7 +9181,16 @@ M.funcs = {
See |match-parens| for a bigger and more useful example.
]=],
name = 'searchpairpos',
- params = {},
+ params = {
+ { 'start', 'any' },
+ { 'middle', 'any' },
+ { 'end', 'any' },
+ { 'flags', 'string' },
+ { 'skip', 'any' },
+ { 'stopline', 'any' },
+ { 'timeout', 'integer' },
+ },
+ returns = '[integer, integer]',
signature = 'searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]])',
},
searchpos = {
@@ -11672,7 +11703,7 @@ M.funcs = {
]=],
name = 'synconcealed',
params = { { 'lnum', 'integer' }, { 'col', 'integer' } },
- returns = '{[1]: integer, [2]: string, [3]: integer}',
+ returns = '[integer, string, integer]',
signature = 'synconcealed({lnum}, {col})',
},
synstack = {
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index d35ac4eb7b..e216dbdaa6 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -855,7 +855,7 @@ char *encode_tv2string(typval_T *tv, size_t *len)
if (len != NULL) {
*len = (size_t)ga.ga_len;
}
- ga_append(&ga, '\0');
+ ga_append(&ga, NUL);
return (char *)ga.ga_data;
}
@@ -883,7 +883,7 @@ char *encode_tv2echo(typval_T *tv, size_t *len)
if (len != NULL) {
*len = (size_t)ga.ga_len;
}
- ga_append(&ga, '\0');
+ ga_append(&ga, NUL);
return (char *)ga.ga_data;
}
@@ -908,7 +908,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
if (len != NULL) {
*len = (size_t)ga.ga_len;
}
- ga_append(&ga, '\0');
+ ga_append(&ga, NUL);
return (char *)ga.ga_data;
}
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index 1b8c057d7c..3255e78d09 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -1,6 +1,7 @@
#include <inttypes.h>
#include <stdlib.h>
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/executor.h"
#include "nvim/eval/typval.h"
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 8b22c7a797..9a1ed7dea9 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -38,6 +38,7 @@
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/buffer.h"
#include "nvim/eval/decode.h"
@@ -4317,7 +4318,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
// Set $NVIM (in the child process) to v:servername. #3118
char *nvim_addr = get_vim_var_str(VV_SEND_SERVER);
- if (nvim_addr[0] != '\0') {
+ if (nvim_addr[0] != NUL) {
dictitem_T *dv = tv_dict_find(env, S_LEN("NVIM"));
if (dv) {
tv_dict_item_remove(env, dv);
@@ -5094,7 +5095,7 @@ static void get_matches_in_str(const char *str, regmatch_T *rmp, list_T *mlist,
// return a list with the submatches
for (int i = 1; i < NSUBEXP; i++) {
if (rmp->endp[i] == NULL) {
- tv_list_append_string(sml, "", 0);
+ tv_list_append_string(sml, S_LEN(""));
} else {
tv_list_append_string(sml, rmp->startp[i], rmp->endp[i] - rmp->startp[i]);
}
@@ -8301,7 +8302,7 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (col < 0) {
return; // type error; errmsg already given
}
- rettv->vval.v_number = get_sw_value_col(curbuf, col);
+ rettv->vval.v_number = get_sw_value_col(curbuf, col, false);
return;
}
rettv->vval.v_number = get_sw_value(curbuf);
@@ -9173,13 +9174,13 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true);
// Trim slash.
if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) {
- IObuff[len - 1] = '\0';
+ IObuff[len - 1] = NUL;
}
if (len == 1 && IObuff[0] == '/') {
// Avoid ambiguity in the URI when CWD is root directory.
IObuff[1] = '.';
- IObuff[2] = '\0';
+ IObuff[2] = NUL;
}
// Terminal URI: "term://$CWD//$PID:$CMD"
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index eb8c89c36e..13b31ab30f 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -10,6 +10,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/executor.h"
@@ -1823,7 +1824,7 @@ char *callback_to_string(Callback *cb, Arena *arena)
snprintf(msg, msglen, "<vim partial: %s>", cb->data.partial->pt_name);
break;
default:
- *msg = '\0';
+ *msg = NUL;
break;
}
return msg;
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 39bd63462c..122a1ac8ab 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -15,6 +15,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/debugger.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
@@ -264,7 +265,7 @@ static void set_ufunc_name(ufunc_T *fp, char *name)
if ((uint8_t)name[0] == K_SPECIAL) {
fp->uf_name_exp = xmalloc(strlen(name) + 3);
STRCPY(fp->uf_name_exp, "<SNR>");
- STRCAT(fp->uf_name_exp, fp->uf_name + 3);
+ strcat(fp->uf_name_exp, fp->uf_name + 3);
}
}
@@ -2061,7 +2062,7 @@ char *get_scriptlocal_funcname(char *funcname)
const int off = *funcname == 's' ? 2 : 5;
char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1);
STRCPY(newname, sid_buf);
- STRCAT(newname, funcname + off);
+ strcat(newname, funcname + off);
return newname;
}
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 1c15274acc..7b93a291c4 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -15,6 +15,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c
index 68de40f983..86495f1cb6 100644
--- a/src/nvim/eval/window.c
+++ b/src/nvim/eval/window.c
@@ -10,6 +10,7 @@
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -271,7 +272,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
// if count is not specified, default to 1
count = 1;
}
- if (endp != NULL && *endp != '\0') {
+ if (endp != NULL && *endp != NUL) {
if (strequal(endp, "j")) {
twin = win_vert_neighbor(tp, twin, false, count);
} else if (strequal(endp, "k")) {
diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h
index 9b7d8708be..41690ead88 100644
--- a/src/nvim/event/defs.h
+++ b/src/nvim/event/defs.h
@@ -6,7 +6,6 @@
#include <uv.h>
#include "nvim/eval/typval_defs.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
enum { EVENT_HANDLER_MAX_ARGC = 10, };
@@ -55,14 +54,17 @@ struct wbuffer {
};
typedef struct stream Stream;
-/// Type of function called when the Stream buffer is filled with data
+typedef struct rstream RStream;
+/// Type of function called when the RStream buffer is filled with data
///
/// @param stream The Stream instance
-/// @param buf The associated RBuffer instance
+/// @param read_data data that was read
/// @param count Number of bytes that was read.
/// @param data User-defined data
/// @param eof If the stream reached EOF.
-typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof);
+/// @return number of bytes which were consumed
+typedef size_t (*stream_read_cb)(RStream *stream, const char *read_data, size_t count, void *data,
+ bool eof);
/// Type of function called when the Stream has information about a write
/// request.
@@ -71,11 +73,11 @@ typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void
/// @param data User-defined data
/// @param status 0 on success, anything else indicates failure
typedef void (*stream_write_cb)(Stream *stream, void *data, int status);
+
typedef void (*stream_close_cb)(Stream *stream, void *data);
struct stream {
bool closed;
- bool did_eof;
union {
uv_pipe_t pipe;
uv_tcp_t tcp;
@@ -85,20 +87,32 @@ struct stream {
#endif
} uv;
uv_stream_t *uvstream;
- uv_buf_t uvbuf;
- RBuffer *buffer;
uv_file fd;
- stream_read_cb read_cb;
- stream_write_cb write_cb;
void *cb_data;
stream_close_cb close_cb, internal_close_cb;
void *close_cb_data, *internal_data;
- size_t fpos;
+ size_t pending_reqs;
+ MultiQueue *events;
+
+ // only used for writing:
+ stream_write_cb write_cb;
size_t curmem;
size_t maxmem;
- size_t pending_reqs;
+};
+
+struct rstream {
+ Stream s;
+ bool did_eof;
+ bool want_read;
+ bool pending_read;
+ bool paused_full;
+ char *buffer; // ARENA_BLOCK_SIZE
+ char *read_pos;
+ char *write_pos;
+ uv_buf_t uvbuf;
+ stream_read_cb read_cb;
size_t num_bytes;
- MultiQueue *events;
+ int64_t fpos;
};
#define ADDRESS_MAX_SIZE 256
@@ -147,7 +161,8 @@ struct process {
char **argv;
const char *exepath;
dict_T *env;
- Stream in, out, err;
+ Stream in;
+ RStream out, err;
/// Exit handler. If set, user must call process_free().
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index f77d686c10..0dead1f9b4 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -70,19 +70,19 @@ int libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvstdio[0].data.stream = (uv_stream_t *)(&proc->in.uv.pipe);
}
- if (!proc->out.closed) {
+ if (!proc->out.s.closed) {
uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
#ifdef MSWIN
// pipe must be readable for IOCP to work on Windows.
uvproc->uvstdio[1].flags |= proc->overlapped
? (UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0;
#endif
- uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.uv.pipe);
+ uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.s.uv.pipe);
}
- if (!proc->err.closed) {
+ if (!proc->err.s.closed) {
uvproc->uvstdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
- uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.uv.pipe);
+ uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.s.uv.pipe);
} else if (proc->fwd_err) {
uvproc->uvstdio[2].flags = UV_INHERIT_FD;
uvproc->uvstdio[2].data.fd = STDERR_FILENO;
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 7460e92766..70fc31ba21 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -8,7 +8,9 @@
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
+#include "nvim/event/rstream.h"
#include "nvim/event/stream.h"
+#include "nvim/event/wstream.h"
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/main.h"
@@ -16,7 +18,6 @@
#include "nvim/os/pty_process.h"
#include "nvim/os/shell.h"
#include "nvim/os/time.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -51,15 +52,15 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
}
if (out) {
- uv_pipe_init(&proc->loop->uv, &proc->out.uv.pipe, 0);
+ uv_pipe_init(&proc->loop->uv, &proc->out.s.uv.pipe, 0);
} else {
- proc->out.closed = true;
+ proc->out.s.closed = true;
}
if (err) {
- uv_pipe_init(&proc->loop->uv, &proc->err.uv.pipe, 0);
+ uv_pipe_init(&proc->loop->uv, &proc->err.s.uv.pipe, 0);
} else {
- proc->err.closed = true;
+ proc->err.s.closed = true;
}
#ifdef USE_GCOV
@@ -82,10 +83,10 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
uv_close((uv_handle_t *)&proc->in.uv.pipe, NULL);
}
if (out) {
- uv_close((uv_handle_t *)&proc->out.uv.pipe, NULL);
+ uv_close((uv_handle_t *)&proc->out.s.uv.pipe, NULL);
}
if (err) {
- uv_close((uv_handle_t *)&proc->err.uv.pipe, NULL);
+ uv_close((uv_handle_t *)&proc->err.s.uv.pipe, NULL);
}
if (proc->type == kProcessTypeUv) {
@@ -106,16 +107,16 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
}
if (out) {
- stream_init(NULL, &proc->out, -1, (uv_stream_t *)&proc->out.uv.pipe);
- proc->out.internal_data = proc;
- proc->out.internal_close_cb = on_process_stream_close;
+ stream_init(NULL, &proc->out.s, -1, (uv_stream_t *)&proc->out.s.uv.pipe);
+ proc->out.s.internal_data = proc;
+ proc->out.s.internal_close_cb = on_process_stream_close;
proc->refcount++;
}
if (err) {
- stream_init(NULL, &proc->err, -1, (uv_stream_t *)&proc->err.uv.pipe);
- proc->err.internal_data = proc;
- proc->err.internal_close_cb = on_process_stream_close;
+ stream_init(NULL, &proc->err.s, -1, (uv_stream_t *)&proc->err.s.uv.pipe);
+ proc->err.s.internal_data = proc;
+ proc->err.s.internal_close_cb = on_process_stream_close;
proc->refcount++;
}
@@ -148,9 +149,9 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL
{
- stream_may_close(&proc->in);
- stream_may_close(&proc->out);
- stream_may_close(&proc->err);
+ wstream_may_close(&proc->in);
+ rstream_may_close(&proc->out);
+ rstream_may_close(&proc->err);
}
/// Synchronously wait for a process to finish
@@ -337,10 +338,10 @@ static void process_close(Process *proc)
///
/// @param proc Process, for which an output stream should be flushed.
/// @param stream Stream to flush.
-static void flush_stream(Process *proc, Stream *stream)
+static void flush_stream(Process *proc, RStream *stream)
FUNC_ATTR_NONNULL_ARG(1)
{
- if (!stream || stream->closed) {
+ if (!stream || stream->s.closed) {
return;
}
@@ -350,23 +351,23 @@ static void flush_stream(Process *proc, Stream *stream)
// keeps sending data, we only accept as much data as the system buffer size.
// Otherwise this would block cleanup/teardown.
int system_buffer_size = 0;
- int err = uv_recv_buffer_size((uv_handle_t *)&stream->uv.pipe,
+ int err = uv_recv_buffer_size((uv_handle_t *)&stream->s.uv.pipe,
&system_buffer_size);
if (err) {
- system_buffer_size = (int)rbuffer_capacity(stream->buffer);
+ system_buffer_size = ARENA_BLOCK_SIZE;
}
size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size;
// Read remaining data.
- while (!stream->closed && stream->num_bytes < max_bytes) {
+ while (!stream->s.closed && stream->num_bytes < max_bytes) {
// Remember number of bytes before polling
size_t num_bytes = stream->num_bytes;
// Poll for data and process the generated events.
loop_poll_events(proc->loop, 0);
- if (stream->events) {
- multiqueue_process_events(stream->events);
+ if (stream->s.events) {
+ multiqueue_process_events(stream->s.events);
}
// Stream can be closed if it is empty.
@@ -374,7 +375,7 @@ static void flush_stream(Process *proc, Stream *stream)
if (stream->read_cb && !stream->did_eof) {
// Stream callback could miss EOF handling if a child keeps the stream
// open. But only send EOF if we haven't already.
- stream->read_cb(stream, stream->buffer, 0, stream->cb_data, true);
+ stream->read_cb(stream, stream->buffer, 0, stream->s.cb_data, true);
}
break;
}
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 421a470244..74b52cbbb1 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -21,8 +21,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
.argv = NULL,
.exepath = NULL,
.in = { .closed = false },
- .out = { .closed = false },
- .err = { .closed = false },
+ .out = { .s.closed = false },
+ .err = { .s.closed = false },
.cb = NULL,
.closed = false,
.internal_close_cb = NULL,
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index 6b4ab472e4..71290d0c0d 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -11,75 +11,81 @@
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/os/os_defs.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/rstream.c.generated.h"
#endif
-void rstream_init_fd(Loop *loop, Stream *stream, int fd, size_t bufsize)
+void rstream_init_fd(Loop *loop, RStream *stream, int fd)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
- stream_init(loop, stream, fd, NULL);
- rstream_init(stream, bufsize);
+ stream_init(loop, &stream->s, fd, NULL);
+ rstream_init(stream);
}
-void rstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t bufsize)
+void rstream_init_stream(RStream *stream, uv_stream_t *uvstream)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
- stream_init(NULL, stream, -1, uvstream);
- rstream_init(stream, bufsize);
+ stream_init(NULL, &stream->s, -1, uvstream);
+ rstream_init(stream);
}
-void rstream_init(Stream *stream, size_t bufsize)
+void rstream_init(RStream *stream)
FUNC_ATTR_NONNULL_ARG(1)
{
- stream->buffer = rbuffer_new(bufsize);
- stream->buffer->data = stream;
- stream->buffer->full_cb = on_rbuffer_full;
- stream->buffer->nonfull_cb = on_rbuffer_nonfull;
+ stream->fpos = 0;
+ stream->read_cb = NULL;
+ stream->num_bytes = 0;
+ stream->buffer = alloc_block();
+ stream->read_pos = stream->write_pos = stream->buffer;
+}
+
+void rstream_start_inner(RStream *stream)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ if (stream->s.uvstream) {
+ uv_read_start(stream->s.uvstream, alloc_cb, read_cb);
+ } else {
+ uv_idle_start(&stream->s.uv.idle, fread_idle_cb);
+ }
}
/// Starts watching for events from a `Stream` instance.
///
/// @param stream The `Stream` instance
-void rstream_start(Stream *stream, stream_read_cb cb, void *data)
+void rstream_start(RStream *stream, stream_read_cb cb, void *data)
FUNC_ATTR_NONNULL_ARG(1)
{
stream->read_cb = cb;
- stream->cb_data = data;
- if (stream->uvstream) {
- uv_read_start(stream->uvstream, alloc_cb, read_cb);
- } else {
- uv_idle_start(&stream->uv.idle, fread_idle_cb);
+ stream->s.cb_data = data;
+ stream->want_read = true;
+ if (!stream->paused_full) {
+ rstream_start_inner(stream);
}
}
/// Stops watching for events from a `Stream` instance.
///
/// @param stream The `Stream` instance
-void rstream_stop(Stream *stream)
+void rstream_stop_inner(RStream *stream)
FUNC_ATTR_NONNULL_ALL
{
- if (stream->uvstream) {
- uv_read_stop(stream->uvstream);
+ if (stream->s.uvstream) {
+ uv_read_stop(stream->s.uvstream);
} else {
- uv_idle_stop(&stream->uv.idle);
+ uv_idle_stop(&stream->s.uv.idle);
}
}
-static void on_rbuffer_full(RBuffer *buf, void *data)
-{
- rstream_stop(data);
-}
-
-static void on_rbuffer_nonfull(RBuffer *buf, void *data)
+/// Stops watching for events from a `Stream` instance.
+///
+/// @param stream The `Stream` instance
+void rstream_stop(RStream *stream)
+ FUNC_ATTR_NONNULL_ALL
{
- Stream *stream = data;
- assert(stream->read_cb);
- rstream_start(stream, stream->read_cb, stream->cb_data);
+ rstream_stop_inner(stream);
+ stream->want_read = false;
}
// Callbacks used by libuv
@@ -87,11 +93,10 @@ static void on_rbuffer_nonfull(RBuffer *buf, void *data)
/// Called by libuv to allocate memory for reading.
static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
{
- Stream *stream = handle->data;
- // `uv_buf_t.len` happens to have different size on Windows.
- size_t write_count;
- buf->base = rbuffer_write_ptr(stream->buffer, &write_count);
- buf->len = UV_BUF_LEN(write_count);
+ RStream *stream = handle->data;
+ buf->base = stream->write_pos;
+ // `uv_buf_t.len` happens to have different size on Windows (as a treat)
+ buf->len = UV_BUF_LEN(rstream_space(stream));
}
/// Callback invoked by libuv after it copies the data into the buffer provided
@@ -99,27 +104,27 @@ static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
/// 0-length buffer.
static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
{
- Stream *stream = uvstream->data;
+ RStream *stream = uvstream->data;
if (cnt <= 0) {
// cnt == 0 means libuv asked for a buffer and decided it wasn't needed:
// http://docs.libuv.org/en/latest/stream.html#c.uv_read_start.
//
- // We don't need to do anything with the RBuffer because the next call
+ // We don't need to do anything with the buffer because the next call
// to `alloc_cb` will return the same unused pointer (`rbuffer_produced`
// won't be called)
if (cnt == UV_ENOBUFS || cnt == 0) {
return;
} else if (cnt == UV_EOF && uvstream->type == UV_TTY) {
// The TTY driver might signal EOF without closing the stream
- invoke_read_cb(stream, 0, true);
+ invoke_read_cb(stream, true);
} else {
DLOG("closing Stream (%p): %s (%s)", (void *)stream,
uv_err_name((int)cnt), os_strerror((int)cnt));
// Read error or EOF, either way stop the stream and invoke the callback
// with eof == true
uv_read_stop(uvstream);
- invoke_read_cb(stream, 0, true);
+ invoke_read_cb(stream, true);
}
return;
}
@@ -127,10 +132,13 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
// at this point we're sure that cnt is positive, no error occurred
size_t nread = (size_t)cnt;
stream->num_bytes += nread;
- // Data was already written, so all we need is to update 'wpos' to reflect
- // the space actually used in the buffer.
- rbuffer_produced(stream->buffer, nread);
- invoke_read_cb(stream, nread, false);
+ stream->write_pos += cnt;
+ invoke_read_cb(stream, false);
+}
+
+static size_t rstream_space(RStream *stream)
+{
+ return (size_t)((stream->buffer + ARENA_BLOCK_SIZE) - stream->write_pos);
}
/// Called by the by the 'idle' handle to emulate a reading event
@@ -141,66 +149,91 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
static void fread_idle_cb(uv_idle_t *handle)
{
uv_fs_t req;
- Stream *stream = handle->data;
+ RStream *stream = handle->data;
+ stream->uvbuf.base = stream->write_pos;
// `uv_buf_t.len` happens to have different size on Windows.
- size_t write_count;
- stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &write_count);
- stream->uvbuf.len = UV_BUF_LEN(write_count);
-
- // the offset argument to uv_fs_read is int64_t, could someone really try
- // to read more than 9 quintillion (9e18) bytes?
- // upcast is meant to avoid tautological condition warning on 32 bits
- uintmax_t fpos_intmax = stream->fpos;
- if (fpos_intmax > INT64_MAX) {
- ELOG("stream offset overflow");
- preserve_exit("stream offset overflow");
- }
+ stream->uvbuf.len = UV_BUF_LEN(rstream_space(stream));
// Synchronous read
- uv_fs_read(handle->loop,
- &req,
- stream->fd,
- &stream->uvbuf,
- 1,
- (int64_t)stream->fpos,
- NULL);
+ uv_fs_read(handle->loop, &req, stream->s.fd, &stream->uvbuf, 1, stream->fpos, NULL);
uv_fs_req_cleanup(&req);
if (req.result <= 0) {
- uv_idle_stop(&stream->uv.idle);
- invoke_read_cb(stream, 0, true);
+ uv_idle_stop(&stream->s.uv.idle);
+ invoke_read_cb(stream, true);
return;
}
- // no errors (req.result (ssize_t) is positive), it's safe to cast.
- size_t nread = (size_t)req.result;
- rbuffer_produced(stream->buffer, nread);
- stream->fpos += nread;
- invoke_read_cb(stream, nread, false);
+ // no errors (req.result (ssize_t) is positive), it's safe to use.
+ stream->write_pos += req.result;
+ stream->fpos += req.result;
+ invoke_read_cb(stream, false);
}
static void read_event(void **argv)
{
- Stream *stream = argv[0];
+ RStream *stream = argv[0];
+ stream->pending_read = false;
if (stream->read_cb) {
- size_t count = (uintptr_t)argv[1];
- bool eof = (uintptr_t)argv[2];
- stream->did_eof = eof;
- stream->read_cb(stream, stream->buffer, count, stream->cb_data, eof);
+ size_t available = rstream_available(stream);
+ size_t consumed = stream->read_cb(stream, stream->read_pos, available, stream->s.cb_data,
+ stream->did_eof);
+ assert(consumed <= available);
+ rstream_consume(stream, consumed);
+ }
+ stream->s.pending_reqs--;
+ if (stream->s.closed && !stream->s.pending_reqs) {
+ stream_close_handle(&stream->s, true);
+ }
+}
+
+size_t rstream_available(RStream *stream)
+{
+ return (size_t)(stream->write_pos - stream->read_pos);
+}
+
+void rstream_consume(RStream *stream, size_t consumed)
+{
+ stream->read_pos += consumed;
+ size_t remaining = (size_t)(stream->write_pos - stream->read_pos);
+ if (remaining > 0 && stream->read_pos > stream->buffer) {
+ memmove(stream->buffer, stream->read_pos, remaining);
+ stream->read_pos = stream->buffer;
+ stream->write_pos = stream->buffer + remaining;
+ } else if (remaining == 0) {
+ stream->read_pos = stream->write_pos = stream->buffer;
}
- stream->pending_reqs--;
- if (stream->closed && !stream->pending_reqs) {
- stream_close_handle(stream);
+
+ if (stream->want_read && stream->paused_full && rstream_space(stream)) {
+ assert(stream->read_cb);
+ stream->paused_full = false;
+ rstream_start_inner(stream);
}
}
-static void invoke_read_cb(Stream *stream, size_t count, bool eof)
+static void invoke_read_cb(RStream *stream, bool eof)
{
+ stream->did_eof |= eof;
+
+ if (!rstream_space(stream)) {
+ rstream_stop_inner(stream);
+ stream->paused_full = true;
+ }
+
+ // we cannot use pending_reqs as a socket can have both pending reads and writes
+ if (stream->pending_read) {
+ return;
+ }
+
// Don't let the stream be closed before the event is processed.
- stream->pending_reqs++;
+ stream->s.pending_reqs++;
+ stream->pending_read = true;
+ CREATE_EVENT(stream->s.events, read_event, stream);
+}
- CREATE_EVENT(stream->events, read_event,
- stream, (void *)(uintptr_t *)count, (void *)(uintptr_t)eof);
+void rstream_may_close(RStream *stream)
+{
+ stream_may_close(&stream->s, true);
}
diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c
index 4e878a2ecf..1214c3e336 100644
--- a/src/nvim/event/socket.c
+++ b/src/nvim/event/socket.c
@@ -35,7 +35,7 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoint
if (host_end && addr != host_end) {
// Split user specified address into two strings, addr(hostname) and port.
// The port part in watcher->addr will be updated later.
- *host_end = '\0';
+ *host_end = NUL;
char *port = host_end + 1;
intmax_t iport;
@@ -135,17 +135,17 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
return 0;
}
-int socket_watcher_accept(SocketWatcher *watcher, Stream *stream)
+int socket_watcher_accept(SocketWatcher *watcher, RStream *stream)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
{
uv_stream_t *client;
if (watcher->stream->type == UV_TCP) {
- client = (uv_stream_t *)(&stream->uv.tcp);
+ client = (uv_stream_t *)(&stream->s.uv.tcp);
uv_tcp_init(watcher->uv.tcp.handle.loop, (uv_tcp_t *)client);
uv_tcp_nodelay((uv_tcp_t *)client, true);
} else {
- client = (uv_stream_t *)&stream->uv.pipe;
+ client = (uv_stream_t *)&stream->s.uv.pipe;
uv_pipe_init(watcher->uv.pipe.handle.loop, (uv_pipe_t *)client, 0);
}
@@ -156,7 +156,7 @@ int socket_watcher_accept(SocketWatcher *watcher, Stream *stream)
return result;
}
- stream_init(NULL, stream, -1, client);
+ stream_init(NULL, &stream->s, -1, client);
return 0;
}
@@ -197,7 +197,7 @@ static void connect_cb(uv_connect_t *req, int status)
}
}
-bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address, int timeout,
+bool socket_connect(Loop *loop, RStream *stream, bool is_tcp, const char *address, int timeout,
const char **error)
{
bool success = false;
@@ -206,7 +206,7 @@ bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address
req.data = &status;
uv_stream_t *uv_stream;
- uv_tcp_t *tcp = &stream->uv.tcp;
+ uv_tcp_t *tcp = &stream->s.uv.tcp;
uv_getaddrinfo_t addr_req;
addr_req.addrinfo = NULL;
const struct addrinfo *addrinfo = NULL;
@@ -237,7 +237,7 @@ tcp_retry:
uv_tcp_connect(&req, tcp, addrinfo->ai_addr, connect_cb);
uv_stream = (uv_stream_t *)tcp;
} else {
- uv_pipe_t *pipe = &stream->uv.pipe;
+ uv_pipe_t *pipe = &stream->s.uv.pipe;
uv_pipe_init(&loop->uv, pipe, 0);
uv_pipe_connect(&req, pipe, address, connect_cb);
uv_stream = (uv_stream_t *)pipe;
@@ -245,7 +245,7 @@ tcp_retry:
status = 1;
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1);
if (status == 0) {
- stream_init(NULL, stream, -1, uv_stream);
+ stream_init(NULL, &stream->s, -1, uv_stream);
success = true;
} else if (is_tcp && addrinfo->ai_next) {
addrinfo = addrinfo->ai_next;
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index 0b9ed4f25b..bc1b503f4c 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -8,7 +8,6 @@
#include "nvim/event/loop.h"
#include "nvim/event/stream.h"
#include "nvim/log.h"
-#include "nvim/rbuffer.h"
#include "nvim/types_defs.h"
#ifdef MSWIN
# include "nvim/os/os_win_console.h"
@@ -85,21 +84,17 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
}
stream->internal_data = NULL;
- stream->fpos = 0;
stream->curmem = 0;
stream->maxmem = 0;
stream->pending_reqs = 0;
- stream->read_cb = NULL;
stream->write_cb = NULL;
stream->close_cb = NULL;
stream->internal_close_cb = NULL;
stream->closed = false;
- stream->buffer = NULL;
stream->events = NULL;
- stream->num_bytes = 0;
}
-void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
+void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, bool rstream)
FUNC_ATTR_NONNULL_ARG(1)
{
assert(!stream->closed);
@@ -116,18 +111,18 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
#endif
if (!stream->pending_reqs) {
- stream_close_handle(stream);
+ stream_close_handle(stream, rstream);
}
}
-void stream_may_close(Stream *stream)
+void stream_may_close(Stream *stream, bool rstream)
{
if (!stream->closed) {
- stream_close(stream, NULL, NULL);
+ stream_close(stream, NULL, NULL, rstream);
}
}
-void stream_close_handle(Stream *stream)
+void stream_close_handle(Stream *stream, bool rstream)
FUNC_ATTR_NONNULL_ALL
{
uv_handle_t *handle = NULL;
@@ -145,16 +140,22 @@ void stream_close_handle(Stream *stream)
assert(handle != NULL);
if (!uv_is_closing(handle)) {
- uv_close(handle, close_cb);
+ uv_close(handle, rstream ? rstream_close_cb : close_cb);
}
}
-static void close_cb(uv_handle_t *handle)
+static void rstream_close_cb(uv_handle_t *handle)
{
- Stream *stream = handle->data;
+ RStream *stream = handle->data;
if (stream->buffer) {
- rbuffer_free(stream->buffer);
+ free_block(stream->buffer);
}
+ close_cb(handle);
+}
+
+static void close_cb(uv_handle_t *handle)
+{
+ Stream *stream = handle->data;
if (stream->close_cb) {
stream->close_cb(stream, stream->close_cb_data);
}
diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c
index c67a9b96ed..07aab87e4d 100644
--- a/src/nvim/event/wstream.c
+++ b/src/nvim/event/wstream.c
@@ -141,7 +141,7 @@ static void write_cb(uv_write_t *req, int status)
if (data->stream->closed && data->stream->pending_reqs == 0) {
// Last pending write, free the stream;
- stream_close_handle(data->stream);
+ stream_close_handle(data->stream, false);
}
xfree(data);
@@ -158,3 +158,8 @@ void wstream_release_wbuffer(WBuffer *buffer)
xfree(buffer);
}
}
+
+void wstream_may_close(Stream *stream)
+{
+ stream_may_close(stream, false);
+}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 834cc6698a..7858e44f17 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -34,6 +34,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -969,13 +970,13 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out
char *t = xmalloc(len);
*t = NUL;
if (newcmd != NULL) {
- STRCAT(t, newcmd);
+ strcat(t, newcmd);
}
if (ins_prevcmd) {
- STRCAT(t, prevcmd);
+ strcat(t, prevcmd);
}
char *p = t + strlen(t);
- STRCAT(t, trailarg);
+ strcat(t, trailarg);
xfree(newcmd);
newcmd = t;
@@ -1028,8 +1029,8 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out
}
newcmd = xmalloc(strlen(prevcmd) + 2 * strlen(p_shq) + 1);
STRCPY(newcmd, p_shq);
- STRCAT(newcmd, prevcmd);
- STRCAT(newcmd, p_shq);
+ strcat(newcmd, prevcmd);
+ strcat(newcmd, p_shq);
free_newcmd = true;
}
if (addr_count == 0) { // :!
@@ -1359,11 +1360,11 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
{
bool is_fish_shell =
#if defined(UNIX)
- strncmp(invocation_path_tail(p_sh, NULL), "fish", 4) == 0;
+ strncmp(invocation_path_tail(p_sh, NULL), S_LEN("fish")) == 0;
#else
false;
#endif
- bool is_pwsh = strncmp(invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0
+ bool is_pwsh = strncmp(invocation_path_tail(p_sh, NULL), S_LEN("pwsh")) == 0
|| strncmp(invocation_path_tail(p_sh, NULL), "powershell",
10) == 0;
@@ -4107,7 +4108,7 @@ skip:
// the line as reference, because the substitute may
// have changed the number of characters. Same for
// "prev_matchcol".
- STRCAT(new_start, sub_firstline + copycol);
+ strcat(new_start, sub_firstline + copycol);
matchcol = (colnr_T)strlen(sub_firstline) - matchcol;
prev_matchcol = (colnr_T)strlen(sub_firstline)
- prev_matchcol;
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index f4a6e61831..a602719f6d 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -17,6 +17,7 @@
#include "nvim/bufwrite.h"
#include "nvim/change.h"
#include "nvim/channel.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 1fcfc505df..9a6a845958 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -29,6 +29,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -1728,12 +1729,6 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
}
const char *errormsg = NULL;
-#undef ERROR
-#define ERROR(msg) \
- do { \
- errormsg = msg; \
- goto end; \
- } while (0)
cmdmod_T save_cmdmod = cmdmod;
cmdmod = cmdinfo->cmdmod;
@@ -1744,16 +1739,19 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY)
// allow :put in terminals
&& !(curbuf->terminal && eap->cmdidx == CMD_put)) {
- ERROR(_(e_modifiable));
+ errormsg = _(e_modifiable);
+ goto end;
}
if (!IS_USER_CMDIDX(eap->cmdidx)) {
if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) {
// Command not allowed in the command line window
- ERROR(_(e_cmdwin));
+ errormsg = _(e_cmdwin);
+ goto end;
}
if (text_locked() && !(eap->argt & EX_LOCK_OK)) {
// Command not allowed when text is locked
- ERROR(_(get_text_locked_msg()));
+ errormsg = _(get_text_locked_msg());
+ goto end;
}
}
// Disallow editing another buffer when "curbuf->b_ro_locked" is set.
@@ -1801,7 +1799,6 @@ end:
do_cmdline_end();
return retv;
-#undef ERROR
}
static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetline, void *cookie)
@@ -2695,7 +2692,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod,
/// Apply the command modifiers. Saves current state in "cmdmod", call
/// undo_cmdmod() later.
-static void apply_cmdmod(cmdmod_T *cmod)
+void apply_cmdmod(cmdmod_T *cmod)
{
if ((cmod->cmod_flags & CMOD_SANDBOX) && !cmod->cmod_did_sandbox) {
sandbox++;
@@ -3829,8 +3826,8 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep)
// No $* in arg, build "<makeprg> <arg>" instead
new_cmdline = xmalloc(strlen(program) + strlen(arg) + 2);
STRCPY(new_cmdline, program);
- STRCAT(new_cmdline, " ");
- STRCAT(new_cmdline, arg);
+ strcat(new_cmdline, " ");
+ strcat(new_cmdline, arg);
}
msg_make(arg);
@@ -4117,7 +4114,7 @@ static char *getargcmd(char **argp)
if (*arg == '+') { // +[command]
arg++;
- if (ascii_isspace(*arg) || *arg == '\0') {
+ if (ascii_isspace(*arg) || *arg == NUL) {
command = dollar_command;
} else {
command = arg;
@@ -4194,7 +4191,7 @@ static int getargopt(exarg_T *eap)
// Note: Keep this in sync with get_argopt_name.
// ":edit ++[no]bin[ary] file"
- if (strncmp(arg, "bin", 3) == 0 || strncmp(arg, "nobin", 5) == 0) {
+ if (strncmp(arg, S_LEN("bin")) == 0 || strncmp(arg, S_LEN("nobin")) == 0) {
if (*arg == 'n') {
arg += 2;
eap->force_bin = FORCE_NOBIN;
@@ -4209,33 +4206,33 @@ static int getargopt(exarg_T *eap)
}
// ":read ++edit file"
- if (strncmp(arg, "edit", 4) == 0) {
+ if (strncmp(arg, S_LEN("edit")) == 0) {
eap->read_edit = true;
eap->arg = skipwhite(arg + 4);
return OK;
}
// ":write ++p foo/bar/file
- if (strncmp(arg, "p", 1) == 0) {
+ if (strncmp(arg, S_LEN("p")) == 0) {
eap->mkdir_p = true;
eap->arg = skipwhite(arg + 1);
return OK;
}
- if (strncmp(arg, "ff", 2) == 0) {
+ if (strncmp(arg, S_LEN("ff")) == 0) {
arg += 2;
pp = &eap->force_ff;
- } else if (strncmp(arg, "fileformat", 10) == 0) {
+ } else if (strncmp(arg, S_LEN("fileformat")) == 0) {
arg += 10;
pp = &eap->force_ff;
- } else if (strncmp(arg, "enc", 3) == 0) {
- if (strncmp(arg, "encoding", 8) == 0) {
+ } else if (strncmp(arg, S_LEN("enc")) == 0) {
+ if (strncmp(arg, S_LEN("encoding")) == 0) {
arg += 8;
} else {
arg += 3;
}
pp = &eap->force_enc;
- } else if (strncmp(arg, "bad", 3) == 0) {
+ } else if (strncmp(arg, S_LEN("bad")) == 0) {
arg += 3;
pp = &bad_char_idx;
}
@@ -4299,19 +4296,19 @@ int expand_argopt(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int
char *name_end = xp->xp_pattern - 1;
if (name_end - xp->xp_line >= 2
- && strncmp(name_end - 2, "ff", 2) == 0) {
+ && strncmp(name_end - 2, S_LEN("ff")) == 0) {
cb = get_fileformat_name;
} else if (name_end - xp->xp_line >= 10
- && strncmp(name_end - 10, "fileformat", 10) == 0) {
+ && strncmp(name_end - 10, S_LEN("fileformat")) == 0) {
cb = get_fileformat_name;
} else if (name_end - xp->xp_line >= 3
- && strncmp(name_end - 3, "enc", 3) == 0) {
+ && strncmp(name_end - 3, S_LEN("enc")) == 0) {
cb = get_encoding_name;
} else if (name_end - xp->xp_line >= 8
- && strncmp(name_end - 8, "encoding", 8) == 0) {
+ && strncmp(name_end - 8, S_LEN("encoding")) == 0) {
cb = get_encoding_name;
} else if (name_end - xp->xp_line >= 3
- && strncmp(name_end - 3, "bad", 3) == 0) {
+ && strncmp(name_end - 3, S_LEN("bad")) == 0) {
cb = get_bad_name;
}
@@ -7216,7 +7213,7 @@ char *expand_sfile(char *arg)
char *result = xstrdup(arg);
for (char *p = result; *p;) {
- if (strncmp(p, "<sfile>", 7) != 0) {
+ if (strncmp(p, S_LEN("<sfile>")) != 0) {
p++;
} else {
// replace "<sfile>" with the sourced file name, and do ":" stuff
@@ -7239,7 +7236,7 @@ char *expand_sfile(char *arg)
memmove(newres, result, (size_t)(p - result));
STRCPY(newres + (p - result), repl);
len = strlen(newres);
- STRCAT(newres, p + srclen);
+ strcat(newres, p + srclen);
xfree(repl);
xfree(result);
result = newres;
@@ -7303,12 +7300,12 @@ static void ex_filetype(exarg_T *eap)
// Accept "plugin" and "indent" in any order.
while (true) {
- if (strncmp(arg, "plugin", 6) == 0) {
+ if (strncmp(arg, S_LEN("plugin")) == 0) {
plugin = true;
arg = skipwhite(arg + 6);
continue;
}
- if (strncmp(arg, "indent", 6) == 0) {
+ if (strncmp(arg, S_LEN("indent")) == 0) {
indent = true;
arg = skipwhite(arg + 6);
continue;
@@ -7387,7 +7384,7 @@ static void ex_setfiletype(exarg_T *eap)
}
char *arg = eap->arg;
- if (strncmp(arg, "FALLBACK ", 9) == 0) {
+ if (strncmp(arg, S_LEN("FALLBACK ")) == 0) {
arg += 9;
}
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 472741d537..0f4f31df02 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -11,6 +11,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/charset.h"
#include "nvim/debugger.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -253,7 +254,7 @@ bool cause_errthrow(const char *mesg, bool multiline, bool severe, bool *ignore)
if (plist == msg_list || severe) {
// Skip the extra "Vim " prefix for message "E458".
char *tmsg = elem->msg;
- if (strncmp(tmsg, "Vim E", 5) == 0
+ if (strncmp(tmsg, S_LEN("Vim E")) == 0
&& ascii_isdigit(tmsg[5])
&& ascii_isdigit(tmsg[6])
&& ascii_isdigit(tmsg[7])
@@ -405,7 +406,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, bool
|| (ascii_isdigit(p[3])
&& p[4] == ':')))))) {
if (*p == NUL || p == mesg) {
- STRCAT(val, mesg); // 'E123' missing or at beginning
+ strcat(val, mesg); // 'E123' missing or at beginning
} else {
// '"filename" E123: message text'
if (mesg[0] != '"' || p - 2 < &mesg[1]
@@ -414,7 +415,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, bool
continue;
}
- STRCAT(val, p);
+ strcat(val, p);
p[-2] = NUL;
snprintf(val + strlen(p), strlen(" (%s)"), " (%s)", &mesg[1]);
p[-2] = '"';
@@ -442,7 +443,7 @@ static int throw_exception(void *value, except_type_T type, char *cmdname)
// would be treated differently from real interrupt or error exceptions
// when no active try block is found, see do_cmdline().
if (type == ET_USER) {
- if (strncmp(value, "Vim", 3) == 0
+ if (strncmp(value, S_LEN("Vim")) == 0
&& (((char *)value)[3] == NUL || ((char *)value)[3] == ':'
|| ((char *)value)[3] == '(')) {
emsg(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index cc2608433d..74e6e3422e 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -28,6 +28,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
@@ -2798,13 +2799,13 @@ int check_opt_wim(void)
if (p[i] != NUL && p[i] != ',' && p[i] != ':') {
return FAIL;
}
- if (i == 7 && strncmp(p, "longest", 7) == 0) {
+ if (i == 7 && strncmp(p, S_LEN("longest")) == 0) {
new_wim_flags[idx] |= WIM_LONGEST;
- } else if (i == 4 && strncmp(p, "full", 4) == 0) {
+ } else if (i == 4 && strncmp(p, S_LEN("full")) == 0) {
new_wim_flags[idx] |= WIM_FULL;
- } else if (i == 4 && strncmp(p, "list", 4) == 0) {
+ } else if (i == 4 && strncmp(p, S_LEN("list")) == 0) {
new_wim_flags[idx] |= WIM_LIST;
- } else if (i == 8 && strncmp(p, "lastused", 8) == 0) {
+ } else if (i == 8 && strncmp(p, S_LEN("lastused")) == 0) {
new_wim_flags[idx] |= WIM_BUFLASTUSED;
} else {
return FAIL;
@@ -3454,11 +3455,9 @@ void cmdline_screen_cleared(void)
/// called by ui_flush, do what redraws necessary to keep cmdline updated.
void cmdline_ui_flush(void)
{
- static bool flushing = false;
- if (!ui_has(kUICmdline) || flushing) {
+ if (!ui_has(kUICmdline)) {
return;
}
- flushing = true;
int level = ccline.level;
CmdlineInfo *line = &ccline;
while (level > 0 && line) {
@@ -3473,7 +3472,6 @@ void cmdline_ui_flush(void)
}
line = line->prev_ccline;
}
- flushing = false;
}
// Put a character on the command line. Shifts the following text to the
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 0e5d2fe4f5..50ee197ef4 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -15,6 +15,7 @@
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 4e47fa76fe..b592283d92 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -54,12 +54,12 @@
/// must not be used during iteration!
void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col, int end_row,
colnr_T end_col, DecorInline decor, uint16_t decor_flags, bool right_gravity,
- bool end_right_gravity, bool no_undo, bool invalidate, bool scoped, Error *err)
+ bool end_right_gravity, bool no_undo, bool invalidate, Error *err)
{
uint32_t *ns = map_put_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL, NULL);
uint32_t id = idp ? *idp : 0;
- uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext, scoped) | decor_flags;
+ uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext) | decor_flags;
if (id == 0) {
id = ++*ns;
} else {
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index a8b0dbddee..50031eedee 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -399,7 +399,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
emsg(_(e_path_too_long_for_completion));
break;
}
- if (strncmp(wc_part, "**", 2) == 0) {
+ if (strncmp(wc_part, S_LEN("**")) == 0) {
ff_expand_buffer[len++] = *wc_part++;
ff_expand_buffer[len++] = *wc_part++;
@@ -451,7 +451,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
STRCPY(buf, ff_expand_buffer);
STRCPY(buf + eb_len, search_ctx->ffsc_fix_path);
if (os_isdir(buf)) {
- STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path);
+ strcat(ff_expand_buffer, search_ctx->ffsc_fix_path);
add_pathsep(ff_expand_buffer);
} else {
char *p = path_tail(search_ctx->ffsc_fix_path);
@@ -462,7 +462,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
if (p > search_ctx->ffsc_fix_path) {
// do not add '..' to the path and start upwards searching
len = (int)(p - search_ctx->ffsc_fix_path) - 1;
- if ((len >= 2 && strncmp(search_ctx->ffsc_fix_path, "..", 2) == 0)
+ if ((len >= 2 && strncmp(search_ctx->ffsc_fix_path, S_LEN("..")) == 0)
&& (len == 2 || search_ctx->ffsc_fix_path[2] == PATHSEP)) {
xfree(buf);
goto error_return;
@@ -479,7 +479,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
+ strlen(search_ctx->ffsc_fix_path + len)
+ 1);
STRCPY(temp, search_ctx->ffsc_fix_path + len);
- STRCAT(temp, search_ctx->ffsc_wc_path);
+ strcat(temp, search_ctx->ffsc_wc_path);
xfree(search_ctx->ffsc_wc_path);
xfree(wc_path);
search_ctx->ffsc_wc_path = temp;
@@ -505,24 +505,36 @@ error_return:
/// @return the stopdir string. Check that ';' is not escaped.
char *vim_findfile_stopdir(char *buf)
{
- char *r_ptr = buf;
-
- while (*r_ptr != NUL && *r_ptr != ';') {
- if (r_ptr[0] == '\\' && r_ptr[1] == ';') {
- // Overwrite the escape char,
- // use strlen(r_ptr) to move the trailing '\0'.
- STRMOVE(r_ptr, r_ptr + 1);
- r_ptr++;
+ for (; *buf != NUL && *buf != ';' && (buf[0] != '\\' || buf[1] != ';'); buf++) {}
+ char *dst = buf;
+ if (*buf == ';') {
+ goto is_semicolon;
+ }
+ if (*buf == NUL) {
+ goto is_nul;
+ }
+ goto start;
+ while (*buf != NUL && *buf != ';') {
+ if (buf[0] == '\\' && buf[1] == ';') {
+start:
+ // Overwrite the escape char.
+ *dst++ = ';';
+ buf += 2;
+ } else {
+ *dst++ = *buf++;
}
- r_ptr++;
}
- if (*r_ptr == ';') {
- *r_ptr = 0;
- r_ptr++;
- } else if (*r_ptr == NUL) {
- r_ptr = NULL;
+ assert(dst < buf);
+ *dst = NUL;
+ if (*buf == ';') {
+is_semicolon:
+ *buf = NUL;
+ buf++;
+ } else { // if (*buf == NUL)
+is_nul:
+ buf = NULL;
}
- return r_ptr;
+ return buf;
}
/// Clean up the given search context. Can handle a NULL pointer.
@@ -669,7 +681,7 @@ char *vim_findfile(void *search_ctx_arg)
ff_free_stack_element(stackp);
goto fail;
}
- STRCAT(file_path, stackp->ffs_fix_path);
+ strcat(file_path, stackp->ffs_fix_path);
if (!add_pathsep(file_path)) {
ff_free_stack_element(stackp);
goto fail;
@@ -678,7 +690,7 @@ char *vim_findfile(void *search_ctx_arg)
rest_of_wildcards = stackp->ffs_wc_path;
if (*rest_of_wildcards != NUL) {
len = strlen(file_path);
- if (strncmp(rest_of_wildcards, "**", 2) == 0) {
+ if (strncmp(rest_of_wildcards, S_LEN("**")) == 0) {
// pointer to the restrict byte
// The restrict byte is not a character!
p = rest_of_wildcards + 2;
@@ -769,7 +781,7 @@ char *vim_findfile(void *search_ctx_arg)
ff_free_stack_element(stackp);
goto fail;
}
- STRCAT(file_path, search_ctx->ffsc_file_to_search);
+ strcat(file_path, search_ctx->ffsc_file_to_search);
// Try without extra suffix and then with suffixes
// from 'suffixesadd'.
@@ -855,7 +867,7 @@ char *vim_findfile(void *search_ctx_arg)
// if wildcards contains '**' we have to descent till we reach the
// leaves of the directory tree.
- if (strncmp(stackp->ffs_wc_path, "**", 2) == 0) {
+ if (strncmp(stackp->ffs_wc_path, S_LEN("**")) == 0) {
for (int i = stackp->ffs_filearray_cur;
i < stackp->ffs_filearray_size; i++) {
if (path_fnamecmp(stackp->ffs_filearray[i],
@@ -910,7 +922,7 @@ char *vim_findfile(void *search_ctx_arg)
if (!add_pathsep(file_path)) {
goto fail;
}
- STRCAT(file_path, search_ctx->ffsc_fix_path);
+ strcat(file_path, search_ctx->ffsc_fix_path);
// create a new stack entry
sptr = ff_create_stack_element(file_path,
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index df9c4928c9..4b8121b423 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -27,6 +27,7 @@
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_eval.h"
@@ -1895,7 +1896,7 @@ theend:
bool is_dev_fd_file(char *fname)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- return strncmp(fname, "/dev/fd/", 8) == 0
+ return strncmp(fname, S_LEN("/dev/fd/")) == 0
&& ascii_isdigit((uint8_t)fname[8])
&& *skipdigits(fname + 9) == NUL
&& (fname[9] != NUL
@@ -2418,7 +2419,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot)
// the file name has at most BASENAMELEN characters.
if (strlen(ptr) > BASENAMELEN) {
- ptr[BASENAMELEN] = '\0';
+ ptr[BASENAMELEN] = NUL;
}
char *s = ptr + strlen(ptr);
@@ -3329,7 +3330,7 @@ static void vim_mktempdir(void)
#endif
// If our "root" tempdir is invalid or fails, proceed without "<user>/".
// Else user1 could break user2 by creating "/tmp/nvim.user2/".
- tmp[strlen(tmp) - strlen(user)] = '\0';
+ tmp[strlen(tmp) - strlen(user)] = NUL;
}
// Now try to create "/tmp/nvim.<user>/XXXXXX".
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 59a4dc6aad..78fe33cc78 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -22,6 +22,7 @@
#include "nvim/decoration.h"
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_session.h"
@@ -3314,7 +3315,7 @@ void f_foldtext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
char *r = xmalloc(len);
snprintf(r, len, txt, dashes, count);
len = strlen(r);
- STRCAT(r, s);
+ strcat(r, s);
// remove 'foldmarker' and 'commentstring'
foldtext_cleanup(r + len);
rettv->vval.v_string = r;
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 62c99ce082..61c80a3d2e 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -306,6 +306,7 @@ local keysets_defs = assert(io.open(keysets_outputf, 'wb'))
-- so that the dispatcher can find the C functions that you are creating!
-- ===========================================================================
output:write([[
+#include "nvim/errors.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/globals.h"
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index 516b5ad5ae..c5b37672bf 100644
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -128,8 +128,16 @@ for i = 1, #events do
write_signature(call_output, ev, '')
call_output:write('\n{\n')
if ev.remote_only then
+ -- Lua callbacks may emit other events or the same event again. Avoid the latter
+ -- by adding a recursion guard to each generated function that may call a Lua callback.
+ call_output:write(' static bool entered = false;\n')
+ call_output:write(' if (entered) {\n')
+ call_output:write(' return;\n')
+ call_output:write(' }\n')
+ call_output:write(' entered = true;\n')
write_arglist(call_output, ev)
call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n')
+ call_output:write(' entered = false;\n')
elseif ev.compositor_impl then
call_output:write(' ui_comp_' .. ev.name)
write_signature(call_output, ev, '', true)
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index 0718d965c6..591a6b93df 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -148,7 +148,7 @@ local get_defaults = function(d, n)
return value_dumpers[type(d)](d)
end
---- @type {[1]:string,[2]:string}[]
+--- @type [string,string][]
local defines = {}
--- @param i integer
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 9b19644b7e..6167418052 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -19,6 +19,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -565,7 +566,7 @@ void AppendToRedobuffLit(const char *str, int len)
// CTRL-V '0' must be inserted as CTRL-V 048.
if (*s == NUL && c == '0') {
- add_buff(&redobuff, "048", 3);
+ add_buff(&redobuff, S_LEN("048"));
} else {
add_char_buff(&redobuff, c);
}
@@ -776,7 +777,7 @@ int start_redo(int count, bool old_redo)
// copy the buffer name, if present
if (c == '"') {
- add_buff(&readbuf2, "\"", 1);
+ add_buff(&readbuf2, S_LEN("\""));
c = read_redo(false, old_redo);
// if a numbered buffer is used, increment the number
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 83fef1fe75..410e8f2e7c 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -793,195 +793,7 @@ EXTERN disptick_T display_tick INIT( = 0);
// cursor position in Insert mode.
EXTERN linenr_T spell_redraw_lnum INIT( = 0);
-// uncrustify:off
-
-// The error messages that can be shared are included here.
-// Excluded are errors that are only used once and debugging messages.
-EXTERN const char e_abort[] INIT(= N_("E470: Command aborted"));
-EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup"));
-EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
-EXTERN const char e_argreq[] INIT(= N_("E471: Argument required"));
-EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
-EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
-EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search"));
-EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s"));
-EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive"));
-EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded"));
-EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif"));
-EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry"));
-EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
-EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor"));
-EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while"));
-EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for"));
-EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)"));
-EXTERN const char e_failed[] INIT(= N_("E472: Command failed"));
-EXTERN const char e_internal[] INIT(= N_("E473: Internal error"));
-EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s"));
-EXTERN const char e_interr[] INIT(= N_("Interrupted"));
-EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument"));
-EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s"));
-EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s"));
-EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s"));
-EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s"));
-EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\""));
-EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range"));
-EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command"));
-EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory"));
-EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible"));
-EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id"));
-EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job"));
-EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full"));
-EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\""));
-EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty"));
-EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s"));
-EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel"));
-EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'"));
-EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64));
-EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
-EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s"));
-EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s"));
-EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number"));
-EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set"));
-EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off"));
-EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep"));
-EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file"));
-EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation"));
-EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed"));
-EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s"));
-EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet"));
-EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line"));
-EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping"));
-EXTERN const char e_nomatch[] INIT(= N_("E479: No match"));
-EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s"));
-EXTERN const char e_noname[] INIT(= N_("E32: No file name"));
-EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression"));
-EXTERN const char e_noprev[] INIT(= N_("E34: No previous command"));
-EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression"));
-EXTERN const char e_norange[] INIT(= N_("E481: No range allowed"));
-EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room"));
-EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name"));
-EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s"));
-EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s"));
-EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s"));
-EXTERN const char e_null[] INIT(= N_("E38: Null argument"));
-EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected"));
-EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s"));
-EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!"));
-EXTERN const char e_patnotf[] INIT(= N_("Pattern not found"));
-EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s"));
-EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive"));
-EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory"));
-
-EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors"));
-EXTERN const char e_loclist[] INIT(= N_("E776: No location list"));
-EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string"));
-EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program"));
-EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)"));
-EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s="));
-EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s"));
-EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable"));
-EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\""));
-EXTERN const char e_stringreq[] INIT(= N_("E928: String required"));
-EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required"));
-EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64));
-EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob"));
-EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s"));
-EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s"));
-EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\""));
-EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\""));
-EXTERN const char e_listreq[] INIT(= N_("E714: List required"));
-EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required"));
-EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary"));
-EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob"));
-EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
-EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox"));
-EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here"));
-EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window"));
-EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported"));
-EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size"));
-EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty"));
-EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!"));
-EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file"));
-EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex"));
-EXTERN const char e_longname[] INIT(= N_("E75: Name too long"));
-EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many ["));
-EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names"));
-EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters"));
-EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s"));
-EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark"));
-EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards"));
-EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'"));
-EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'"));
-EXTERN const char e_write[] INIT(= N_("E80: Error while writing"));
-EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required"));
-EXTERN const char e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context"));
-EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s"));
-EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer"));
-EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist"));
-
-EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function"));
-
-EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter"));
-EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer"));
-EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set"));
-EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name"));
-EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\""));
-EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior"));
-EXTERN const char e_menu_only_exists_in_another_mode[]
-INIT(= N_("E328: Menu only exists in another mode"));
-EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window"));
-EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List"));
-EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
-EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long"));
-EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String"));
-EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now"));
-EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d"));
-EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s"));
-EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort"));
-
-EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s"));
-
-EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
-
-EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain"));
-EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float"));
-
-EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events"));
-
-EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long"));
-
-EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range"));
-
-EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name"));
-
-EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long"));
-
-EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld"));
-EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld"));
-
-EXTERN const char e_stray_closing_curly_str[]
-INIT(= N_("E1278: Stray '}' without a matching '{': %s"));
-EXTERN const char e_missing_close_curly_str[]
-INIT(= N_("E1279: Missing '}': %s"));
-
-EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s"));
-
-EXTERN const char e_undobang_cannot_redo_or_move_branch[]
-INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch"));
-
-EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
-INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
-
-EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
-
-EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s"));
-
-EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
-EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
-
-EXTERN const char line_msg[] INIT(= N_(" line "));
-
-EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report.
+EXTERN FILE *time_fd INIT( = NULL); // Where to write --startuptime report.
// Some compilers warn for not using a return value, but in some situations we
// can't do anything useful with the value. Assign to this variable to avoid
@@ -989,11 +801,9 @@ EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report.
EXTERN int vim_ignored;
// stdio is an RPC channel (--embed).
-EXTERN bool embedded_mode INIT(= false);
+EXTERN bool embedded_mode INIT( = false);
// Do not start UI (--headless, -l) nor read/write to stdio (unless embedding).
-EXTERN bool headless_mode INIT(= false);
-
-// uncrustify:on
+EXTERN bool headless_mode INIT( = false);
/// Only filled for Win32.
EXTERN char windowsVersion[20] INIT( = { 0 });
diff --git a/src/nvim/help.c b/src/nvim/help.c
index e9f67ca3e4..6ba3e17e0b 100644
--- a/src/nvim/help.c
+++ b/src/nvim/help.c
@@ -13,6 +13,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/cmdexpand_defs.h"
+#include "nvim/errors.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
@@ -654,7 +655,7 @@ void get_local_additions(void)
// files. This uses the very first line in the help file.
char *const fname = path_tail(curbuf->b_fname);
if (path_fnamecmp(fname, "help.txt") == 0
- || (path_fnamencmp(fname, "help.", 5) == 0
+ || (path_fnamencmp(fname, S_LEN("help.")) == 0
&& ASCII_ISALPHA(fname[5])
&& ASCII_ISALPHA(fname[6])
&& TOLOWER_ASC(fname[7]) == 'x'
@@ -957,8 +958,8 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
if (s == p2
&& (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t')
&& (vim_strchr(" \t\n\r", (uint8_t)s[1]) != NULL
- || s[1] == '\0')) {
- *p2 = '\0';
+ || s[1] == NUL)) {
+ *p2 = NUL;
p1++;
size_t s_len = (size_t)(p2 - p1) + strlen(fname) + 2;
s = xmalloc(s_len);
@@ -1014,7 +1015,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
// Write the tags into the file.
for (int i = 0; i < ga.ga_len; i++) {
s = ((char **)ga.ga_data)[i];
- if (strncmp(s, "help-tags\t", 10) == 0) {
+ if (strncmp(s, S_LEN("help-tags\t")) == 0) {
// help-tags entry was added in formatted form
fputs(s, fd_tags);
} else {
@@ -1148,7 +1149,7 @@ void ex_helptags(exarg_T *eap)
bool add_help_tags = false;
// Check for ":helptags ++t {dir}".
- if (strncmp(eap->arg, "++t", 3) == 0 && ascii_iswhite(eap->arg[3])) {
+ if (strncmp(eap->arg, S_LEN("++t")) == 0 && ascii_iswhite(eap->arg[3])) {
add_help_tags = true;
eap->arg = skipwhite(eap->arg + 3);
}
diff --git a/src/nvim/highlight.h b/src/nvim/highlight.h
index cb3a84bcaf..558727fc51 100644
--- a/src/nvim/highlight.h
+++ b/src/nvim/highlight.h
@@ -78,6 +78,8 @@ EXTERN const char *hlf_names[] INIT( = {
[HLF_CU] = "Cursor",
[HLF_BTITLE] = "FloatTitle",
[HLF_BFOOTER] = "FloatFooter",
+ [HLF_TS] = "StatusLineTerm",
+ [HLF_TSNC] = "StatusLineTermNC",
});
EXTERN int highlight_attr[HLF_COUNT + 1]; // Highl. attr for each context.
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 25ab9dc2d9..17e3db04da 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -125,6 +125,8 @@ typedef enum {
HLF_CU, ///< Cursor
HLF_BTITLE, ///< Float Border Title
HLF_BFOOTER, ///< Float Border Footer
+ HLF_TS, ///< status line for terminal window
+ HLF_TSNC, ///< status line for non-current terminal window
HLF_COUNT, ///< MUST be the last one
} hlf_T;
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index ccb093c116..cc9e606d1d 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -22,6 +22,7 @@
#include "nvim/cursor_shape.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
@@ -150,34 +151,36 @@ static const char *highlight_init_both[] = {
"lCursor guifg=bg guibg=fg",
// UI
- "default link CursorIM Cursor",
- "default link CursorLineFold FoldColumn",
- "default link CursorLineSign SignColumn",
- "default link EndOfBuffer NonText",
- "default link FloatBorder NormalFloat",
- "default link FloatFooter FloatTitle",
- "default link FloatTitle Title",
- "default link FoldColumn SignColumn",
- "default link IncSearch CurSearch",
- "default link LineNrAbove LineNr",
- "default link LineNrBelow LineNr",
- "default link MsgSeparator StatusLine",
- "default link MsgArea NONE",
- "default link NormalNC NONE",
- "default link PmenuExtra Pmenu",
- "default link PmenuExtraSel PmenuSel",
- "default link PmenuKind Pmenu",
- "default link PmenuKindSel PmenuSel",
- "default link PmenuSbar Pmenu",
- "default link Substitute Search",
- "default link TabLine StatusLineNC",
- "default link TabLineFill TabLine",
- "default link TermCursorNC NONE",
- "default link VertSplit WinSeparator",
- "default link VisualNOS Visual",
- "default link Whitespace NonText",
- "default link WildMenu PmenuSel",
- "default link WinSeparator Normal",
+ "default link CursorIM Cursor",
+ "default link CursorLineFold FoldColumn",
+ "default link CursorLineSign SignColumn",
+ "default link EndOfBuffer NonText",
+ "default link FloatBorder NormalFloat",
+ "default link FloatFooter FloatTitle",
+ "default link FloatTitle Title",
+ "default link FoldColumn SignColumn",
+ "default link IncSearch CurSearch",
+ "default link LineNrAbove LineNr",
+ "default link LineNrBelow LineNr",
+ "default link MsgSeparator StatusLine",
+ "default link MsgArea NONE",
+ "default link NormalNC NONE",
+ "default link PmenuExtra Pmenu",
+ "default link PmenuExtraSel PmenuSel",
+ "default link PmenuKind Pmenu",
+ "default link PmenuKindSel PmenuSel",
+ "default link PmenuSbar Pmenu",
+ "default link Substitute Search",
+ "default link StatusLineTerm StatusLine",
+ "default link StatusLineTermNC StatusLineNC",
+ "default link TabLine StatusLineNC",
+ "default link TabLineFill TabLine",
+ "default link TermCursorNC NONE",
+ "default link VertSplit WinSeparator",
+ "default link VisualNOS Visual",
+ "default link Whitespace NonText",
+ "default link WildMenu PmenuSel",
+ "default link WinSeparator Normal",
// Syntax
"default link Character Constant",
@@ -1056,7 +1059,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
}
int from_id = syn_check_group(from_start, (size_t)(from_end - from_start));
- if (strncmp(to_start, "NONE", 4) == 0) {
+ if (strncmp(to_start, S_LEN("NONE")) == 0) {
to_id = 0;
} else {
to_id = syn_check_group(to_start, (size_t)(to_end - to_start));
@@ -1173,7 +1176,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
break;
}
vim_memcpy_up(key, key_start, key_len);
- key[key_len] = '\0';
+ key[key_len] = NUL;
linep = skipwhite(linep);
if (strcmp(key, "NONE") == 0) {
@@ -1966,7 +1969,7 @@ int syn_name2id_len(const char *name, size_t len)
// Avoid using stricmp() too much, it's slow on some systems
// Avoid alloc()/free(), these are slow too.
vim_memcpy_up(name_u, name, len);
- name_u[len] = '\0';
+ name_u[len] = NUL;
// map_get(..., int) returns 0 when no key is present, which is
// the expected value for missing highlight group.
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index d635c7d7bf..a4964db465 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -13,6 +13,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
@@ -146,25 +147,42 @@ int tabstop_padding(colnr_T col, OptInt ts_arg, const colnr_T *vts)
}
/// Find the size of the tab that covers a particular column.
-int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts)
+///
+/// If this is being called as part of a shift operation, col is not the cursor
+/// column but is the column number to the left of the first non-whitespace
+/// character in the line. If the shift is to the left (left == true), then
+/// return the size of the tab interval to the left of the column.
+int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts, bool left)
{
- colnr_T tabcol = 0;
- int t;
- int tab_size = 0;
-
if (vts == NULL || vts[0] == 0) {
return (int)ts;
}
- const int tabcount = vts[0];
+ colnr_T tabcol = 0; // Column of the tab stop under consideration.
+ int t; // Tabstop index in the list of variable tab stops.
+ int tab_size = 0; // Size of the tab stop interval to the right or left of the col.
+ const int tabcount // Number of tab stops in the list of variable tab stops.
+ = vts[0];
for (t = 1; t <= tabcount; t++) {
tabcol += vts[t];
if (tabcol > col) {
- tab_size = vts[t];
+ // If shifting left (left == true), and if the column to the left of
+ // the first first non-blank character (col) in the line is
+ // already to the left of the first tabstop, set the shift amount
+ // (tab_size) to just enough to shift the line to the left margin.
+ // The value doesn't seem to matter as long as it is at least that
+ // distance.
+ if (left && (t == 1)) {
+ tab_size = col;
+ } else {
+ tab_size = vts[t - (left ? 1 : 0)];
+ }
break;
}
}
- if (t > tabcount) {
+ if (t > tabcount) { // If the value of the index t is beyond the
+ // end of the list, use the tab stop value at
+ // the end of the list.
tab_size = vts[tabcount];
}
@@ -311,35 +329,35 @@ int tabstop_first(colnr_T *ts)
/// 'tabstop' value when 'shiftwidth' is zero.
int get_sw_value(buf_T *buf)
{
- int result = get_sw_value_col(buf, 0);
+ int result = get_sw_value_col(buf, 0, false);
return result;
}
/// Idem, using "pos".
-int get_sw_value_pos(buf_T *buf, pos_T *pos)
+int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left)
{
pos_T save_cursor = curwin->w_cursor;
curwin->w_cursor = *pos;
- int sw_value = get_sw_value_col(buf, get_nolist_virtcol());
+ int sw_value = get_sw_value_col(buf, get_nolist_virtcol(), left);
curwin->w_cursor = save_cursor;
return sw_value;
}
/// Idem, using the first non-black in the current line.
-int get_sw_value_indent(buf_T *buf)
+int get_sw_value_indent(buf_T *buf, bool left)
{
pos_T pos = curwin->w_cursor;
pos.col = (colnr_T)getwhitecols_curline();
- return get_sw_value_pos(buf, &pos);
+ return get_sw_value_pos(buf, &pos, left);
}
/// Idem, using virtual column "col".
-int get_sw_value_col(buf_T *buf, colnr_T col)
+int get_sw_value_col(buf_T *buf, colnr_T col, bool left)
{
return buf->b_p_sw ? (int)buf->b_p_sw
- : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
+ : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array, left);
}
/// Return the effective softtabstop value for the current buffer,
@@ -764,20 +782,20 @@ bool briopt_check(win_T *wp)
char *p = wp->w_p_briopt;
while (*p != NUL) {
// Note: Keep this in sync with p_briopt_values
- if (strncmp(p, "shift:", 6) == 0
+ if (strncmp(p, S_LEN("shift:")) == 0
&& ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) {
p += 6;
bri_shift = getdigits_int(&p, true, 0);
- } else if (strncmp(p, "min:", 4) == 0 && ascii_isdigit(p[4])) {
+ } else if (strncmp(p, S_LEN("min:")) == 0 && ascii_isdigit(p[4])) {
p += 4;
bri_min = getdigits_int(&p, true, 0);
- } else if (strncmp(p, "sbr", 3) == 0) {
+ } else if (strncmp(p, S_LEN("sbr")) == 0) {
p += 3;
bri_sbr = true;
- } else if (strncmp(p, "list:", 5) == 0) {
+ } else if (strncmp(p, S_LEN("list:")) == 0) {
p += 5;
bri_list = (int)getdigits(&p, false, 0);
- } else if (strncmp(p, "column:", 7) == 0) {
+ } else if (strncmp(p, S_LEN("column:")) == 0) {
p += 7;
bri_vcol = (int)getdigits(&p, false, 0);
}
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 8b1c09b32f..711e2292b1 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -22,6 +22,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -167,6 +168,7 @@ struct compl_S {
///< cp_flags has CP_FREE_FNAME
int cp_flags; ///< CP_ values
int cp_number; ///< sequence number
+ int cp_score; ///< fuzzy match score
};
/// state information used for getting the next set of insert completion
@@ -224,13 +226,6 @@ static char *compl_leader = NULL;
static bool compl_get_longest = false; ///< put longest common string in compl_leader
-static bool compl_no_insert = false; ///< false: select & insert
- ///< true: noinsert
-static bool compl_no_select = false; ///< false: select & insert
- ///< true: noselect
-static bool compl_longest = false; ///< false: insert full match
- ///< true: insert longest prefix
-
/// Selected one of the matches. When false the match was edited or using the
/// longest common string.
static bool compl_used_match;
@@ -287,7 +282,7 @@ static bool compl_opt_refresh_always = false;
static size_t spell_bad_len = 0; // length of located bad word
-static int pum_selected_item = -1;
+static int compl_selected_item = -1;
/// CTRL-X pressed in Insert mode.
void ins_ctrl_x(void)
@@ -1048,22 +1043,10 @@ bool ins_compl_long_shown_match(void)
&& (colnr_T)strlen(compl_shown_match->cp_str) > curwin->w_cursor.col - compl_col;
}
-/// Set variables that store noselect and noinsert behavior from the
-/// 'completeopt' value.
-void completeopt_was_set(void)
+/// Get the local or global value of 'completeopt' flags.
+unsigned get_cot_flags(void)
{
- compl_no_insert = false;
- compl_no_select = false;
- compl_longest = false;
- if (strstr(p_cot, "noselect") != NULL) {
- compl_no_select = true;
- }
- if (strstr(p_cot, "noinsert") != NULL) {
- compl_no_insert = true;
- }
- if (strstr(p_cot, "longest") != NULL) {
- compl_longest = true;
- }
+ return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags;
}
/// "compl_match_array" points the currently displayed list of entries in the
@@ -1087,7 +1070,7 @@ bool pum_wanted(void)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
// "completeopt" must contain "menu" or "menuone"
- return vim_strchr(p_cot, 'm') != NULL;
+ return (get_cot_flags() & COT_ANY_MENU) != 0;
}
/// Check that there are two or more matches to be shown in the popup menu.
@@ -1106,7 +1089,7 @@ static bool pum_enough_matches(void)
comp = comp->cp_next;
} while (!is_first_match(comp));
- if (strstr(p_cot, "menuone") != NULL) {
+ if (get_cot_flags() & COT_MENUONE) {
return i >= 1;
}
return i >= 2;
@@ -1160,6 +1143,14 @@ static void trigger_complete_changed_event(int cur)
restore_v_event(v_event, &save_v_event);
}
+/// pumitem qsort compare func
+static int ins_compl_fuzzy_sort(const void *a, const void *b)
+{
+ const int sa = (*(pumitem_T *)a).pum_score;
+ const int sb = (*(pumitem_T *)b).pum_score;
+ return sa == sb ? 0 : sa < sb ? 1 : -1;
+}
+
/// Build a popup menu to show the completion matches.
///
/// @return the popup menu entry that should be selected,
@@ -1177,11 +1168,22 @@ static int ins_compl_build_pum(void)
}
const int lead_len = compl_leader != NULL ? (int)strlen(compl_leader) : 0;
+ int max_fuzzy_score = 0;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
+ bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
do {
+ // When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
+ // set the cp_score for later comparisons.
+ if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
+ comp->cp_score = fuzzy_match_str(comp->cp_str, compl_leader);
+ }
+
if (!match_at_original_text(comp)
&& (compl_leader == NULL
- || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) {
+ || ins_compl_equal(comp, compl_leader, (size_t)lead_len)
+ || (compl_fuzzy_match && comp->cp_score > 0))) {
compl_match_arraysize++;
}
comp = comp->cp_next;
@@ -1210,8 +1212,9 @@ static int ins_compl_build_pum(void)
do {
if (!match_at_original_text(comp)
&& (compl_leader == NULL
- || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) {
- if (!shown_match_ok) {
+ || ins_compl_equal(comp, compl_leader, (size_t)lead_len)
+ || (compl_fuzzy_match && comp->cp_score > 0))) {
+ if (!shown_match_ok && !compl_fuzzy_match) {
if (comp == compl_shown_match || did_find_shown_match) {
// This item is the shown match or this is the
// first displayed item after the shown match.
@@ -1224,6 +1227,26 @@ static int ins_compl_build_pum(void)
shown_compl = comp;
}
cur = i;
+ } else if (compl_fuzzy_match) {
+ // Update the maximum fuzzy score and the shown match
+ // if the current item's score is higher
+ if (comp->cp_score > max_fuzzy_score) {
+ did_find_shown_match = true;
+ max_fuzzy_score = comp->cp_score;
+ compl_shown_match = comp;
+ shown_match_ok = true;
+ }
+
+ // If there is no "no select" condition and the max fuzzy
+ // score is positive, or there is no completion leader or the
+ // leader length is zero, mark the shown match as valid and
+ // reset the current index.
+ if (!compl_no_select
+ && (max_fuzzy_score > 0
+ || (compl_leader == NULL || lead_len == 0))) {
+ shown_match_ok = true;
+ cur = 0;
+ }
}
if (comp->cp_text[CPT_ABBR] != NULL) {
@@ -1233,6 +1256,7 @@ static int ins_compl_build_pum(void)
}
compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
+ compl_match_array[i].pum_score = comp->cp_score;
if (comp->cp_text[CPT_MENU] != NULL) {
compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU];
} else {
@@ -1240,7 +1264,7 @@ static int ins_compl_build_pum(void)
}
}
- if (comp == compl_shown_match) {
+ if (comp == compl_shown_match && !compl_fuzzy_match) {
did_find_shown_match = true;
// When the original text is the shown match don't set
@@ -1259,6 +1283,12 @@ static int ins_compl_build_pum(void)
comp = comp->cp_next;
} while (comp != NULL && !is_first_match(comp));
+ if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
+ // sort by the largest score of fuzzy match
+ qsort(compl_match_array, (size_t)compl_match_arraysize, sizeof(pumitem_T),
+ ins_compl_fuzzy_sort);
+ }
+
if (!shown_match_ok) { // no displayed match at all
cur = -1;
}
@@ -1310,7 +1340,7 @@ void ins_compl_show_pum(void)
// Use the cursor to get all wrapping and other settings right.
const colnr_T col = curwin->w_cursor.col;
curwin->w_cursor.col = compl_col;
- pum_selected_item = cur;
+ compl_selected_item = cur;
pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0);
curwin->w_cursor.col = col;
@@ -2178,7 +2208,7 @@ bool ins_compl_prep(int c)
// Set "compl_get_longest" when finding the first matches.
if (ctrl_x_mode_not_defined_yet()
|| (ctrl_x_mode_normal() && !compl_started)) {
- compl_get_longest = compl_longest;
+ compl_get_longest = (get_cot_flags() & COT_LONGEST) != 0;
compl_used_match = true;
}
@@ -2598,6 +2628,10 @@ static void restore_orig_extmarks(void)
static void set_completion(colnr_T startcol, list_T *list)
{
int flags = CP_ORIGINAL_TEXT;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool compl_longest = (cur_cot_flags & COT_LONGEST) != 0;
+ bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0;
+ bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
// If already doing completions stop it.
if (ctrl_x_mode_not_default()) {
@@ -3588,6 +3622,42 @@ static void ins_compl_show_filename(void)
redraw_cmdline = false; // don't overwrite!
}
+/// Find a completion item when 'completeopt' contains "fuzzy".
+static compl_T *find_comp_when_fuzzy(void)
+{
+ int target_idx = -1;
+ const bool is_forward = compl_shows_dir_forward();
+ const bool is_backward = compl_shows_dir_backward();
+ compl_T *comp = NULL;
+
+ if (compl_match_array == NULL
+ || (is_forward && compl_selected_item == compl_match_arraysize - 1)
+ || (is_backward && compl_selected_item == 0)) {
+ return compl_first_match;
+ }
+
+ if (is_forward) {
+ target_idx = compl_selected_item + 1;
+ } else if (is_backward) {
+ target_idx = compl_selected_item == -1 ? compl_match_arraysize - 1
+ : compl_selected_item - 1;
+ }
+
+ const int score = compl_match_array[target_idx].pum_score;
+ char *const str = compl_match_array[target_idx].pum_text;
+
+ comp = compl_first_match;
+ do {
+ if (comp->cp_score == score
+ && (str == comp->cp_str || str == comp->cp_text[CPT_ABBR])) {
+ return comp;
+ }
+ comp = comp->cp_next;
+ } while (comp != NULL && !is_first_match(comp));
+
+ return NULL;
+}
+
/// Find the next set of matches for completion. Repeat the completion "todo"
/// times. The number of matches found is returned in 'num_matches'.
///
@@ -3605,17 +3675,22 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a
{
bool found_end = false;
compl_T *found_compl = NULL;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
+ bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
while (--todo >= 0) {
if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL) {
- compl_shown_match = compl_shown_match->cp_next;
+ compl_shown_match = !compl_fuzzy_match ? compl_shown_match->cp_next
+ : find_comp_when_fuzzy();
found_end = (compl_first_match != NULL
&& (is_first_match(compl_shown_match->cp_next)
|| is_first_match(compl_shown_match)));
} else if (compl_shows_dir_backward()
&& compl_shown_match->cp_prev != NULL) {
found_end = is_first_match(compl_shown_match);
- compl_shown_match = compl_shown_match->cp_prev;
+ compl_shown_match = !compl_fuzzy_match ? compl_shown_match->cp_prev
+ : find_comp_when_fuzzy();
found_end |= is_first_match(compl_shown_match);
} else {
if (!allow_get_expansion) {
@@ -3659,7 +3734,8 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a
if (!match_at_original_text(compl_shown_match)
&& compl_leader != NULL
&& !ins_compl_equal(compl_shown_match,
- compl_leader, strlen(compl_leader))) {
+ compl_leader, strlen(compl_leader))
+ && !(compl_fuzzy_match && compl_shown_match->cp_score > 0)) {
todo++;
} else {
// Remember a matching item.
@@ -3704,6 +3780,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
int todo = count;
const bool started = compl_started;
buf_T *const orig_curbuf = curbuf;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0;
+ bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
// When user complete function return -1 for findstart which is next
// time of 'always', compl_shown_match become NULL.
@@ -3711,7 +3790,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
return -1;
}
- if (compl_leader != NULL && !match_at_original_text(compl_shown_match)) {
+ if (compl_leader != NULL
+ && !match_at_original_text(compl_shown_match)
+ && !compl_fuzzy_match) {
// Update "compl_shown_match" to the actually shown match
ins_compl_update_shown_match();
}
@@ -3840,7 +3921,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func)
}
}
}
- if (compl_pending != 0 && !got_int && !compl_no_insert) {
+ if (compl_pending != 0 && !got_int && !(cot_flags & COT_NOINSERT)) {
int todo = compl_pending > 0 ? compl_pending : -compl_pending;
compl_pending = 0;
@@ -3853,7 +3934,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func)
static int ins_compl_key2dir(int c)
{
if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
- return pum_want.item < pum_selected_item ? BACKWARD : FORWARD;
+ return pum_want.item < compl_selected_item ? BACKWARD : FORWARD;
}
if (c == Ctrl_P || c == Ctrl_L
|| c == K_PAGEUP || c == K_KPAGEUP
@@ -3879,7 +3960,7 @@ static bool ins_compl_pum_key(int c)
static int ins_compl_key2count(int c)
{
if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
- int offset = pum_want.item - pum_selected_item;
+ int offset = pum_want.item - compl_selected_item;
return abs(offset);
}
@@ -3978,7 +4059,7 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col)
compl_pattern = xmalloc(7);
STRCPY(compl_pattern, "\\<");
quote_meta(compl_pattern + 2, line + compl_col, 1);
- STRCAT(compl_pattern, "\\k");
+ strcat(compl_pattern, "\\k");
} else {
compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2);
STRCPY(compl_pattern, "\\<");
diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c
index 44ddfbba00..a2dffa4602 100644
--- a/src/nvim/keycodes.c
+++ b/src/nvim/keycodes.c
@@ -8,6 +8,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
#include "nvim/gettext_defs.h"
@@ -903,7 +904,7 @@ char *replace_termcodes(const char *const from, const size_t from_len, char **co
}
// Check for special <> keycodes, like "<C-S-LeftMouse>"
if (do_special && ((flags & REPTERM_DO_LT) || ((end - src) >= 3
- && strncmp(src, "<lt>", 4) != 0))) {
+ && strncmp(src, S_LEN("<lt>")) != 0))) {
// Change <SID>Func to K_SNR <script-nr> _Func. This name is used
// for script-local user functions.
// (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c
index c34b303193..24b2c82381 100644
--- a/src/nvim/linematch.c
+++ b/src/nvim/linematch.c
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <string.h>
+#include "nvim/ascii_defs.h"
#include "nvim/linematch.h"
#include "nvim/macros_defs.h"
#include "nvim/memory.h"
@@ -61,7 +62,7 @@ static int matching_chars_iwhite(const char *s1, const char *s2)
d++;
}
}
- strsproc[k][i] = '\0';
+ strsproc[k][i] = NUL;
}
int matching = matching_chars(strsproc[0], strsproc[1]);
xfree(strsproc[0]);
diff --git a/src/nvim/log.c b/src/nvim/log.c
index fbb3e0385a..774f1c956d 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -46,7 +46,7 @@ static uv_mutex_t mutex;
static bool log_try_create(char *fname)
{
- if (fname == NULL || fname[0] == '\0') {
+ if (fname == NULL || fname[0] == NUL) {
return false;
}
FILE *log_file = fopen(fname, "a");
@@ -67,7 +67,7 @@ static void log_path_init(void)
size_t size = sizeof(log_file_path);
expand_env("$" ENV_LOGFILE, log_file_path, (int)size - 1);
if (strequal("$" ENV_LOGFILE, log_file_path)
- || log_file_path[0] == '\0'
+ || log_file_path[0] == NUL
|| os_isdir(log_file_path)
|| !log_try_create(log_file_path)) {
// Make $XDG_STATE_HOME if it does not exist.
@@ -88,7 +88,7 @@ static void log_path_init(void)
}
// Fall back to stderr
if (len >= size || !log_try_create(log_file_path)) {
- log_file_path[0] = '\0';
+ log_file_path[0] = NUL;
return;
}
os_setenv(ENV_LOGFILE, log_file_path, true);
@@ -324,7 +324,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
// Get a name for this Nvim instance.
// TODO(justinmk): expose this as v:name ?
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
// Parent servername.
const char *parent = path_tail(os_getenv(ENV_NVIM));
// Servername. Empty until starting=false.
@@ -350,7 +350,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
func_name, line_num);
if (name[0] == '?') {
// No v:servername yet. Clear `name` so that the next log can try again.
- name[0] = '\0';
+ name[0] = NUL;
}
if (rv < 0) {
diff --git a/src/nvim/lua/api_wrappers.c b/src/nvim/lua/api_wrappers.c
index 2b7b0c6471..36847d1fc9 100644
--- a/src/nvim/lua/api_wrappers.c
+++ b/src/nvim/lua/api_wrappers.c
@@ -5,6 +5,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/errors.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/func_attr.h"
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index a76b8213e5..6246452b92 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -22,6 +22,7 @@
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c
index f62e0ace04..61277949c4 100644
--- a/src/nvim/lua/secure.c
+++ b/src/nvim/lua/secure.c
@@ -3,6 +3,7 @@
#include <string.h>
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
@@ -103,12 +104,12 @@ void ex_trust(exarg_T *eap)
action = "deny";
} else if (strcmp(arg1, "++remove") == 0) {
action = "remove";
- } else if (*arg1 != '\0') {
+ } else if (*arg1 != NUL) {
semsg(e_invarg2, arg1);
goto theend;
}
- if (path[0] == '\0') {
+ if (path[0] == NUL) {
path = NULL;
}
diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c
index ba83239dc5..f4dacd7a55 100644
--- a/src/nvim/lua/spell.c
+++ b/src/nvim/lua/spell.c
@@ -7,6 +7,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
+#include "nvim/errors.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/highlight_defs.h"
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index 22ee0a1c98..ee0eabbebb 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -17,10 +17,13 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
+#include "nvim/eval/window.h"
+#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/fold.h"
#include "nvim/globals.h"
@@ -40,6 +43,7 @@
#include "nvim/runtime.h"
#include "nvim/strings.h"
#include "nvim/types_defs.h"
+#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/stdlib.c.generated.h"
@@ -568,6 +572,99 @@ static int nlua_foldupdate(lua_State *lstate)
return 0;
}
+static int nlua_with(lua_State *L)
+{
+ int flags = 0;
+ buf_T *buf = NULL;
+ win_T *win = NULL;
+
+#define APPLY_FLAG(key, flag) \
+ if (strequal((key), k) && (v)) { \
+ flags |= (flag); \
+ }
+
+ luaL_argcheck(L, lua_istable(L, 1), 1, "table expected");
+ lua_pushnil(L); // [dict, ..., nil]
+ while (lua_next(L, 1)) {
+ // [dict, ..., key, value]
+ if (lua_type(L, -2) == LUA_TSTRING) {
+ const char *k = lua_tostring(L, -2);
+ bool v = lua_toboolean(L, -1);
+ if (strequal("buf", k)) { \
+ buf = handle_get_buffer((int)luaL_checkinteger(L, -1));
+ } else if (strequal("win", k)) { \
+ win = handle_get_window((int)luaL_checkinteger(L, -1));
+ } else {
+ APPLY_FLAG("sandbox", CMOD_SANDBOX);
+ APPLY_FLAG("silent", CMOD_SILENT);
+ APPLY_FLAG("emsg_silent", CMOD_ERRSILENT);
+ APPLY_FLAG("unsilent", CMOD_UNSILENT);
+ APPLY_FLAG("noautocmd", CMOD_NOAUTOCMD);
+ APPLY_FLAG("hide", CMOD_HIDE);
+ APPLY_FLAG("keepalt", CMOD_KEEPALT);
+ APPLY_FLAG("keepmarks", CMOD_KEEPMARKS);
+ APPLY_FLAG("keepjumps", CMOD_KEEPJUMPS);
+ APPLY_FLAG("lockmarks", CMOD_LOCKMARKS);
+ APPLY_FLAG("keeppatterns", CMOD_KEEPPATTERNS);
+ }
+ }
+ // pop the value; lua_next will pop the key.
+ lua_pop(L, 1); // [dict, ..., key]
+ }
+ int status = 0;
+ int rets = 0;
+
+ cmdmod_T save_cmdmod = cmdmod;
+ cmdmod.cmod_flags = flags;
+ apply_cmdmod(&cmdmod);
+
+ if (buf || win) {
+ try_start();
+ }
+
+ aco_save_T aco;
+ win_execute_T win_execute_args;
+ Error err = ERROR_INIT;
+
+ if (win) {
+ tabpage_T *tabpage = win_find_tabpage(win);
+ if (!win_execute_before(&win_execute_args, win, tabpage)) {
+ goto end;
+ }
+ } else if (buf) {
+ aucmd_prepbuf(&aco, buf);
+ }
+
+ int s = lua_gettop(L);
+ lua_pushvalue(L, 2);
+ status = lua_pcall(L, 0, LUA_MULTRET, 0);
+ rets = lua_gettop(L) - s;
+
+ if (win) {
+ win_execute_after(&win_execute_args);
+ } else if (buf) {
+ aucmd_restbuf(&aco);
+ }
+
+end:
+ if (buf || win) {
+ try_end(&err);
+ }
+
+ undo_cmdmod(&cmdmod);
+ cmdmod = save_cmdmod;
+
+ if (status) {
+ return lua_error(L);
+ } else if (ERROR_SET(&err)) {
+ nlua_push_errstr(L, "%s", err.msg);
+ api_clear_error(&err);
+ return lua_error(L);
+ }
+
+ return rets;
+}
+
// Access to internal functions. For use in runtime/
static void nlua_state_add_internal(lua_State *const lstate)
{
@@ -582,6 +679,9 @@ static void nlua_state_add_internal(lua_State *const lstate)
// _updatefolds
lua_pushcfunction(lstate, &nlua_foldupdate);
lua_setfield(lstate, -2, "_foldupdate");
+
+ lua_pushcfunction(lstate, &nlua_with);
+ lua_setfield(lstate, -2, "_with_c");
}
void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index e87cf756a8..b13a162074 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -279,7 +279,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position
memcpy(buf, line + position.column, tocopy);
// Translate embedded \n to NUL
- memchrsub(buf, '\n', '\0', tocopy);
+ memchrsub(buf, '\n', NUL, tocopy);
*bytes_read = (uint32_t)tocopy;
if (tocopy < BUFSIZE) {
// now add the final \n. If it didn't fit, input_cb will be called again
diff --git a/src/nvim/main.c b/src/nvim/main.c
index cf1324d37f..5e243df975 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -37,6 +37,7 @@
#include "nvim/diff.h"
#include "nvim/drawline.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -154,7 +155,6 @@ void event_init(void)
loop_init(&main_loop, NULL);
resize_events = multiqueue_new_child(main_loop.events);
- input_init();
signal_init();
// mspgack-rpc initialization
channel_init();
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 9320390d68..d02c865328 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -19,6 +19,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/cmdexpand_defs.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -402,43 +403,43 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa
// Accept <buffer>, <nowait>, <silent>, <expr>, <script>, and <unique> in
// any order.
while (true) {
- if (strncmp(to_parse, "<buffer>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<buffer>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->buffer = true;
continue;
}
- if (strncmp(to_parse, "<nowait>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<nowait>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->nowait = true;
continue;
}
- if (strncmp(to_parse, "<silent>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<silent>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->silent = true;
continue;
}
// Ignore obsolete "<special>" modifier.
- if (strncmp(to_parse, "<special>", 9) == 0) {
+ if (strncmp(to_parse, S_LEN("<special>")) == 0) {
to_parse = skipwhite(to_parse + 9);
continue;
}
- if (strncmp(to_parse, "<script>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<script>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->script = true;
continue;
}
- if (strncmp(to_parse, "<expr>", 6) == 0) {
+ if (strncmp(to_parse, S_LEN("<expr>")) == 0) {
to_parse = skipwhite(to_parse + 6);
mapargs->expr = true;
continue;
}
- if (strncmp(to_parse, "<unique>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<unique>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->unique = true;
continue;
@@ -1251,32 +1252,32 @@ char *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, b
xp->xp_context = EXPAND_MAPPINGS;
expand_buffer = false;
while (true) {
- if (strncmp(arg, "<buffer>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<buffer>")) == 0) {
expand_buffer = true;
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<unique>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<unique>")) == 0) {
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<nowait>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<nowait>")) == 0) {
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<silent>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<silent>")) == 0) {
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<special>", 9) == 0) {
+ if (strncmp(arg, S_LEN("<special>")) == 0) {
arg = skipwhite(arg + 9);
continue;
}
- if (strncmp(arg, "<script>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<script>")) == 0) {
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<expr>", 6) == 0) {
+ if (strncmp(arg, S_LEN("<expr>")) == 0) {
arg = skipwhite(arg + 6);
continue;
}
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 6ce42bb7fe..16f444a316 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -14,6 +14,7 @@
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index 34d6cd118f..9e3005b6a3 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -2286,7 +2286,7 @@ static void marktree_itr_fix_pos(MarkTree *b, MarkTreeIter *itr)
void marktree_put_test(MarkTree *b, uint32_t ns, uint32_t id, int row, int col, bool right_gravity,
int end_row, int end_col, bool end_right, bool meta_inline)
{
- uint16_t flags = mt_flags(right_gravity, false, false, false, false);
+ uint16_t flags = mt_flags(right_gravity, false, false, false);
// The specific choice is irrelevant here, we pick one counted decor
// type to test the counting and filtering logic.
flags |= meta_inline ? MT_FLAG_DECOR_VIRT_TEXT_INLINE : 0;
diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h
index 8e5cf30ff3..15df57ef63 100644
--- a/src/nvim/marktree.h
+++ b/src/nvim/marktree.h
@@ -35,8 +35,6 @@
#define MT_FLAG_DECOR_VIRT_LINES (((uint16_t)1) << 11)
#define MT_FLAG_DECOR_VIRT_TEXT_INLINE (((uint16_t)1) << 12)
-#define MT_FLAG_SCOPED (((uint16_t)1) << 13)
-
// These _must_ be last to preserve ordering of marks
#define MT_FLAG_RIGHT_GRAVITY (((uint16_t)1) << 14)
#define MT_FLAG_LAST (((uint16_t)1) << 15)
@@ -46,7 +44,7 @@
| MT_FLAG_DECOR_VIRT_TEXT_INLINE)
#define MT_FLAG_EXTERNAL_MASK (MT_FLAG_DECOR_MASK | MT_FLAG_NO_UNDO \
- | MT_FLAG_INVALIDATE | MT_FLAG_INVALID | MT_FLAG_SCOPED)
+ | MT_FLAG_INVALIDATE | MT_FLAG_INVALID)
// this is defined so that start and end of the same range have adjacent ids
#define MARKTREE_END_FLAG ((uint64_t)1)
@@ -110,24 +108,12 @@ static inline bool mt_decor_sign(MTKey key)
return key.flags & (MT_FLAG_DECOR_SIGNTEXT | MT_FLAG_DECOR_SIGNHL);
}
-static inline bool mt_scoped(MTKey key)
-{
- return key.flags & MT_FLAG_SCOPED;
-}
-
-static inline bool mt_scoped_in_win(MTKey key, win_T *wp)
-{
- return !mt_scoped(key) || set_has(uint32_t, &wp->w_ns_set, key.ns);
-}
-
-static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext,
- bool scoped)
+static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext)
{
return (uint16_t)((right_gravity ? MT_FLAG_RIGHT_GRAVITY : 0)
| (no_undo ? MT_FLAG_NO_UNDO : 0)
| (invalidate ? MT_FLAG_INVALIDATE : 0)
- | (decor_ext ? MT_FLAG_DECOR_EXT : 0)
- | (scoped ? MT_FLAG_SCOPED : 0));
+ | (decor_ext ? MT_FLAG_DECOR_EXT : 0));
}
static inline MTPair mtpair_from(MTKey start, MTKey end)
diff --git a/src/nvim/match.c b/src/nvim/match.c
index 580d7d1069..6ae4e41147 100644
--- a/src/nvim/match.c
+++ b/src/nvim/match.c
@@ -10,6 +10,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/window.h"
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index a345795bbe..018febb995 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -43,6 +43,7 @@
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/getchar.h"
@@ -370,9 +371,9 @@ int enc_canon_props(const char *name)
int i = enc_canon_search(name);
if (i >= 0) {
return enc_canon_table[i].prop;
- } else if (strncmp(name, "2byte-", 6) == 0) {
+ } else if (strncmp(name, S_LEN("2byte-")) == 0) {
return ENC_DBCS;
- } else if (strncmp(name, "8bit-", 5) == 0 || strncmp(name, "iso-8859-", 9) == 0) {
+ } else if (strncmp(name, S_LEN("8bit-")) == 0 || strncmp(name, S_LEN("iso-8859-")) == 0) {
return ENC_8BIT;
}
return 0;
@@ -392,10 +393,10 @@ int bomb_size(void)
if (*curbuf->b_p_fenc == NUL
|| strcmp(curbuf->b_p_fenc, "utf-8") == 0) {
n = 3;
- } else if (strncmp(curbuf->b_p_fenc, "ucs-2", 5) == 0
- || strncmp(curbuf->b_p_fenc, "utf-16", 6) == 0) {
+ } else if (strncmp(curbuf->b_p_fenc, S_LEN("ucs-2")) == 0
+ || strncmp(curbuf->b_p_fenc, S_LEN("utf-16")) == 0) {
n = 2;
- } else if (strncmp(curbuf->b_p_fenc, "ucs-4", 5) == 0) {
+ } else if (strncmp(curbuf->b_p_fenc, S_LEN("ucs-4")) == 0) {
n = 4;
}
}
@@ -1545,7 +1546,7 @@ int utf16_to_utf8(const wchar_t *utf16, int utf16len, char **utf8)
return uv_translate_sys_error(GetLastError());
}
- (*utf8)[bufsize] = '\0';
+ (*utf8)[bufsize] = NUL;
return 0;
}
@@ -2187,10 +2188,10 @@ const char *mb_unescape(const char **const pp)
/// Skip the Vim specific head of a 'encoding' name.
char *enc_skip(char *p)
{
- if (strncmp(p, "2byte-", 6) == 0) {
+ if (strncmp(p, S_LEN("2byte-")) == 0) {
return p + 6;
}
- if (strncmp(p, "8bit-", 5) == 0) {
+ if (strncmp(p, S_LEN("8bit-")) == 0) {
return p + 5;
}
return p;
@@ -2221,37 +2222,42 @@ char *enc_canonize(char *enc)
}
}
*p = NUL;
+ char *p_e = p;
// Skip "2byte-" and "8bit-".
p = enc_skip(r);
// Change "microsoft-cp" to "cp". Used in some spell files.
- if (strncmp(p, "microsoft-cp", 12) == 0) {
- STRMOVE(p, p + 10);
+ if (strncmp(p, S_LEN("microsoft-cp")) == 0) {
+ memmove(p, p + STRLEN_LITERAL("microsoft-"),
+ (size_t)(p_e - (p + STRLEN_LITERAL("microsoft-"))) + 1);
}
// "iso8859" -> "iso-8859"
- if (strncmp(p, "iso8859", 7) == 0) {
- STRMOVE(p + 4, p + 3);
- p[3] = '-';
+ if (strncmp(p, S_LEN("iso8859")) == 0) {
+ memmove(p + STRLEN_LITERAL("iso-"), p + STRLEN_LITERAL("iso"),
+ (size_t)(p_e - (p + STRLEN_LITERAL("iso"))) + 1);
+ p[STRLEN_LITERAL("iso")] = '-';
}
// "iso-8859n" -> "iso-8859-n"
- if (strncmp(p, "iso-8859", 8) == 0 && p[8] != '-') {
- STRMOVE(p + 9, p + 8);
- p[8] = '-';
+ if (strncmp(p, S_LEN("iso-8859")) == 0 && p[8] != '-') {
+ memmove(p + STRLEN_LITERAL("iso-8859-"), p + STRLEN_LITERAL("iso-8859"),
+ (size_t)(p_e - (p + STRLEN_LITERAL("iso-8859"))) + 1);
+ p[STRLEN_LITERAL("iso-8859")] = '-';
}
// "latin-N" -> "latinN"
- if (strncmp(p, "latin-", 6) == 0) {
- STRMOVE(p + 5, p + 6);
+ if (strncmp(p, S_LEN("latin-")) == 0) {
+ memmove(p + STRLEN_LITERAL("latin"), p + STRLEN_LITERAL("latin-"),
+ (size_t)(p_e - (p + STRLEN_LITERAL("latin-"))) + 1);
}
int i;
if (enc_canon_search(p) >= 0) {
// canonical name can be used unmodified
if (p != r) {
- STRMOVE(r, p);
+ memmove(r, p, (size_t)(p_e - p) + 1);
}
} else if ((i = enc_alias_search(p)) >= 0) {
// alias recognized, get canonical name
@@ -2314,7 +2320,7 @@ char *enc_locale(void)
if (p > s + 2 && !STRNICMP(p + 1, "EUC", 3)
&& !isalnum((uint8_t)p[4]) && p[4] != '-' && p[-3] == '_') {
// Copy "XY.EUC" to "euc-XY" to buf[10].
- memmove(buf, "euc-", 4);
+ memmove(buf, S_LEN("euc-"));
buf[4] = (char)(ASCII_ISALNUM(p[-2]) ? TOLOWER_ASC(p[-2]) : 0);
buf[5] = (char)(ASCII_ISALNUM(p[-1]) ? TOLOWER_ASC(p[-1]) : 0);
buf[6] = NUL;
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index a1713edb66..498d212da3 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -46,6 +46,7 @@
#include "nvim/assert_defs.h"
#include "nvim/buffer_defs.h"
+#include "nvim/errors.h"
#include "nvim/fileio.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 5acf4f0c37..a21c232a2d 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -864,7 +864,7 @@ void ml_recover(bool checkext)
goto theend;
}
ZeroBlock *b0p = hp->bh_data;
- if (strncmp(b0p->b0_version, "VIM 3.0", 7) == 0) {
+ if (strncmp(b0p->b0_version, S_LEN("VIM 3.0")) == 0) {
msg_start();
msg_outtrans(mfp->mf_fname, MSG_HIST);
msg_puts_attr(_(" cannot be used with this version of Vim.\n"),
@@ -1538,7 +1538,7 @@ static time_t swapfile_info(char *fname)
int fd = os_open(fname, O_RDONLY, 0);
if (fd >= 0) {
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) {
- if (strncmp(b0.b0_version, "VIM 3.0", 7) == 0) {
+ if (strncmp(b0.b0_version, S_LEN("VIM 3.0")) == 0) {
msg_puts(_(" [from Vim version 3.0]"));
} else if (ml_check_b0_id(&b0) == FAIL) {
msg_puts(_(" [does not look like a Vim swap file]"));
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 789535e270..50860c69d0 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -19,6 +19,7 @@
#include "nvim/context.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawline.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
@@ -202,7 +203,7 @@ void *xmallocz(size_t size)
}
void *ret = xmalloc(total_size);
- ((char *)ret)[size] = '\0';
+ ((char *)ret)[size] = NUL;
return ret;
}
@@ -232,7 +233,7 @@ void *xmemcpyz(void *dst, const void *src, size_t len)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
memcpy(dst, src, len);
- ((char *)dst)[len] = '\0';
+ ((char *)dst)[len] = NUL;
return dst;
}
@@ -240,7 +241,7 @@ void *xmemcpyz(void *dst, const void *src, size_t len)
size_t xstrnlen(const char *s, size_t n)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
{
- const char *end = memchr(s, '\0', n);
+ const char *end = memchr(s, NUL, n);
if (end == NULL) {
return n;
}
@@ -287,7 +288,7 @@ void *xmemscan(const void *addr, char c, size_t size)
void strchrsub(char *str, char c, char x)
FUNC_ATTR_NONNULL_ALL
{
- assert(c != '\0');
+ assert(c != NUL);
while ((str = strchr(str, c))) {
*str++ = x;
}
@@ -387,7 +388,7 @@ char *xstpcpy(char *restrict dst, const char *restrict src)
char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- const char *p = memchr(src, '\0', maxlen);
+ const char *p = memchr(src, NUL, maxlen);
if (p) {
size_t srclen = (size_t)(p - src);
memcpy(dst, src, srclen);
@@ -419,7 +420,7 @@ size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize)
if (dsize) {
size_t len = MIN(slen, dsize - 1);
memcpy(dst, src, len);
- dst[len] = '\0';
+ dst[len] = NUL;
}
return slen; // Does not include NUL.
@@ -449,7 +450,7 @@ size_t xstrlcat(char *const dst, const char *const src, const size_t dsize)
if (slen > dsize - dlen - 1) {
memmove(dst + dlen, src, dsize - dlen - 1);
- dst[dsize - 1] = '\0';
+ dst[dsize - 1] = NUL;
} else {
memmove(dst + dlen, src, slen + 1);
}
@@ -509,7 +510,7 @@ char *xstrndup(const char *str, size_t len)
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
FUNC_ATTR_NONNULL_ALL
{
- char *p = memchr(str, '\0', len);
+ char *p = memchr(str, NUL, len);
return xmemdupz(str, p ? (size_t)(p - str) : len);
}
@@ -882,7 +883,6 @@ void free_all_mem(void)
decor_free_all_mem();
drawline_free_all_mem();
- input_free_all_mem();
if (ui_client_channel_id) {
ui_client_free_all_mem();
diff --git a/src/nvim/memory.h b/src/nvim/memory.h
index 0788670142..277ffe97aa 100644
--- a/src/nvim/memory.h
+++ b/src/nvim/memory.h
@@ -72,5 +72,3 @@ EXTERN size_t arena_alloc_count INIT( = 0);
// Like strcpy() but allows overlapped source and destination.
#define STRMOVE(d, s) memmove((d), (s), strlen(s) + 1)
-
-#define STRCAT(d, s) strcat((char *)(d), (char *)(s)) // NOLINT(runtime/printf)
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index ab28eeca1c..aa76b8010d 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -13,6 +13,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -60,7 +61,7 @@ static const char e_nomenu[] = N_("E329: No menu \"%s\"");
static bool menu_is_winbar(const char *const name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return (strncmp(name, "WinBar", 6) == 0);
+ return (strncmp(name, S_LEN("WinBar")) == 0);
}
static vimmenu_T **get_root_menu(const char *const name)
@@ -89,17 +90,17 @@ void ex_menu(exarg_T *eap)
char *arg = eap->arg;
while (true) {
- if (strncmp(arg, "<script>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<script>")) == 0) {
noremap = REMAP_SCRIPT;
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<silent>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<silent>")) == 0) {
silent = true;
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<special>", 9) == 0) {
+ if (strncmp(arg, S_LEN("<special>")) == 0) {
// Ignore obsolete "<special>" modifier.
arg = skipwhite(arg + 9);
continue;
@@ -109,7 +110,7 @@ void ex_menu(exarg_T *eap)
// Locate an optional "icon=filename" argument
// TODO(nvim): Currently this is only parsed. Should expose it to UIs.
- if (strncmp(arg, "icon=", 5) == 0) {
+ if (strncmp(arg, S_LEN("icon=")) == 0) {
arg += 5;
while (*arg != NUL && *arg != ' ') {
if (*arg == '\\') {
@@ -152,10 +153,10 @@ void ex_menu(exarg_T *eap)
pri_tab[MENUDEPTH] = -1; // mark end of the table
// Check for "disable" or "enable" argument.
- if (strncmp(arg, "enable", 6) == 0 && ascii_iswhite(arg[6])) {
+ if (strncmp(arg, S_LEN("enable")) == 0 && ascii_iswhite(arg[6])) {
enable = kTrue;
arg = skipwhite(arg + 6);
- } else if (strncmp(arg, "disable", 7) == 0 && ascii_iswhite(arg[7])) {
+ } else if (strncmp(arg, S_LEN("disable")) == 0 && ascii_iswhite(arg[7])) {
enable = kFalse;
arg = skipwhite(arg + 7);
}
@@ -888,10 +889,10 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for
}
if (!ascii_iswhite(*p)) {
- if (strncmp(arg, "enable", 6) == 0
+ if (strncmp(arg, S_LEN("enable")) == 0
&& (arg[6] == NUL || ascii_iswhite(arg[6]))) {
p = arg + 6;
- } else if (strncmp(arg, "disable", 7) == 0
+ } else if (strncmp(arg, S_LEN("disable")) == 0
&& (arg[7] == NUL || ascii_iswhite(arg[7]))) {
p = arg + 7;
} else {
@@ -1056,7 +1057,7 @@ char *get_menu_names(expand_T *xp, int idx)
}
// hack on menu separators: use a 'magic' char for the separator
// so that '.' in names gets escaped properly
- STRCAT(tbuffer, "\001");
+ strcat(tbuffer, "\001");
str = tbuffer;
} else {
if (should_advance) {
@@ -1332,14 +1333,14 @@ bool menu_is_menubar(const char *const name)
bool menu_is_popup(const char *const name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return strncmp(name, "PopUp", 5) == 0;
+ return strncmp(name, S_LEN("PopUp")) == 0;
}
// Return true if "name" is a toolbar menu name.
bool menu_is_toolbar(const char *const name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return strncmp(name, "ToolBar", 7) == 0;
+ return strncmp(name, S_LEN("ToolBar")) == 0;
}
/// @return true if the name is a menu separator identifier: Starts and ends
@@ -1700,7 +1701,7 @@ void ex_menutranslate(exarg_T *eap)
}
// ":menutrans clear": clear all translations.
- if (strncmp(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5))) {
+ if (strncmp(arg, S_LEN("clear")) == 0 && ends_excmd(*skipwhite(arg + 5))) {
GA_DEEP_CLEAR(&menutrans_ga, menutrans_T, FREE_MENUTRANS);
// Delete all "menutrans_" global variables.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 10b90bde29..86e25915a3 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -18,6 +18,7 @@
#include "nvim/channel.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -472,7 +473,7 @@ void trunc_string(const char *s, char *buf, int room_in, int buflen)
}
} else if (e + 3 < buflen) {
// set the middle and copy the last part
- memmove(buf + e, "...", 3);
+ memmove(buf + e, S_LEN("..."));
len = (int)strlen(s + i) + 1;
if (len >= buflen - e - 3) {
len = buflen - e - 3 - 1;
@@ -2689,7 +2690,7 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
*p++ = '\r';
}
memcpy(p, s, (size_t)len);
- *(p + len) = '\0';
+ *(p + len) = NUL;
if (info_message) {
printf("%s", buf);
} else {
@@ -3181,7 +3182,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
if (*s != '\n' && *s != '\r') {
while (cur_col < msg_col) {
if (capture_ga) {
- ga_concat_len(capture_ga, " ", 1);
+ ga_concat_len(capture_ga, S_LEN(" "));
}
if (redir_reg) {
write_reg_contents(redir_reg, " ", 1, true);
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 418ece09ed..a2bb1b4685 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -20,6 +20,7 @@
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/window.h"
#include "nvim/fold.h"
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 5737a0440f..6a0dc10214 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -31,8 +31,6 @@
#include "nvim/msgpack_rpc/packer.h"
#include "nvim/msgpack_rpc/unpacker.h"
#include "nvim/os/input.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/ui_client.h"
@@ -89,7 +87,7 @@ void rpc_start(Channel *channel)
kv_init(rpc->call_stack);
if (channel->streamtype != kChannelStreamInternal) {
- Stream *out = channel_outstream(channel);
+ RStream *out = channel_outstream(channel);
#ifdef NVIM_LOG_DEBUG
Stream *in = channel_instream(channel);
DLOG("rpc ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id,
@@ -202,10 +200,25 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem
return frame.errored ? NIL : frame.result;
}
-static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, bool eof)
+static size_t receive_msgpack(RStream *stream, const char *rbuf, size_t c, void *data, bool eof)
{
Channel *channel = data;
channel_incref(channel);
+ size_t consumed = 0;
+
+ DLOG("ch %" PRIu64 ": parsing %zu bytes from msgpack Stream: %p",
+ channel->id, c, (void *)stream);
+
+ if (c > 0) {
+ Unpacker *p = channel->rpc.unpacker;
+ p->read_ptr = rbuf;
+ p->read_size = c;
+ parse_msgpack(channel);
+
+ if (!unpacker_closed(p)) {
+ consumed = c - p->read_size;
+ }
+ }
if (eof) {
channel_close(channel->id, kChannelPartRpc, NULL);
@@ -213,25 +226,10 @@ static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data,
snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client",
channel->id);
chan_close_with_error(channel, buf, LOGLVL_INF);
- goto end;
- }
-
- DLOG("ch %" PRIu64 ": parsing %zu bytes from msgpack Stream: %p",
- channel->id, rbuffer_size(rbuf), (void *)stream);
-
- Unpacker *p = channel->rpc.unpacker;
- size_t size = 0;
- p->read_ptr = rbuffer_read_ptr(rbuf, &size);
- p->read_size = size;
- parse_msgpack(channel);
-
- if (!unpacker_closed(p)) {
- size_t consumed = size - p->read_size;
- rbuffer_consumed_compact(rbuf, consumed);
}
-end:
channel_decref(channel);
+ return consumed;
}
static ChannelCallFrame *find_call_frame(RpcState *rpc, uint32_t request_id)
diff --git a/src/nvim/msgpack_rpc/packer.c b/src/nvim/msgpack_rpc/packer.c
index cac68f76f0..9c0d2910fa 100644
--- a/src/nvim/msgpack_rpc/packer.c
+++ b/src/nvim/msgpack_rpc/packer.c
@@ -113,7 +113,6 @@ void mpack_handle(ObjectType type, handle_T handle, PackerBuffer *packer)
mpack_w(&packer->ptr, 0xc7);
mpack_w(&packer->ptr, packsize);
mpack_w(&packer->ptr, exttype);
- // check_buffer(packer);
memcpy(packer->ptr, buf, (size_t)packsize);
packer->ptr += packsize;
}
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 56b03d67d0..24bd343a34 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <uv.h>
+#include "nvim/ascii_defs.h"
#include "nvim/channel.h"
#include "nvim/eval.h"
#include "nvim/event/defs.h"
@@ -131,7 +132,7 @@ bool server_owns_pipe_address(const char *path)
/// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen.
int server_start(const char *addr)
{
- if (addr == NULL || addr[0] == '\0') {
+ if (addr == NULL || addr[0] == NUL) {
WLOG("Empty or NULL address");
return 1;
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 8ba375f29d..3343803bb1 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -28,6 +28,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
@@ -1986,7 +1987,7 @@ bool add_to_showcmd(int c)
size_t overflow = old_len + extra_len - limit;
memmove(showcmd_buf, showcmd_buf + overflow, old_len - overflow + 1);
}
- STRCAT(showcmd_buf, p);
+ strcat(showcmd_buf, p);
if (char_avail()) {
return false;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 5c1e291ac6..8f8baaf619 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -24,6 +24,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds2.h"
@@ -281,8 +282,10 @@ void op_shift(oparg_T *oap, bool curs_top, int amount)
/// @param call_changed_bytes call changed_bytes()
void shift_line(bool left, bool round, int amount, int call_changed_bytes)
{
- const int sw_val = get_sw_value_indent(curbuf);
-
+ int sw_val = get_sw_value_indent(curbuf, left);
+ if (sw_val == 0) {
+ sw_val = 1; // shouldn't happen, just in case
+ }
int count = get_indent(); // get current indent
if (round) { // round off indent
@@ -327,7 +330,7 @@ static void shift_block(oparg_T *oap, int amount)
const int oldstate = State;
char *newp;
const int oldcol = curwin->w_cursor.col;
- const int sw_val = get_sw_value_indent(curbuf);
+ const int sw_val = get_sw_value_indent(curbuf, left);
const int ts_val = (int)curbuf->b_p_ts;
struct block_def bd;
int incr;
@@ -2663,7 +2666,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
char *pnew = xmalloc(strlen(curr->y_array[curr->y_size - 1])
+ strlen(reg->y_array[0]) + 1);
STRCPY(pnew, curr->y_array[--j]);
- STRCAT(pnew, reg->y_array[0]);
+ strcat(pnew, reg->y_array[0]);
xfree(curr->y_array[j]);
xfree(reg->y_array[0]);
curr->y_array[j++] = pnew;
@@ -3428,7 +3431,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
totlen = strlen(y_array[y_size - 1]);
char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1);
STRCPY(newp, y_array[y_size - 1]);
- STRCAT(newp, ptr);
+ strcat(newp, ptr);
// insert second line
ml_append(lnum, newp, 0, false);
new_lnum++;
@@ -4722,7 +4725,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0';
}
- buf2[i] = '\0';
+ buf2[i] = NUL;
} else if (pre == 0) {
vim_snprintf(buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n);
} else if (pre == '0') {
@@ -4744,7 +4747,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
}
}
*ptr = NUL;
- STRCAT(buf1, buf2);
+ strcat(buf1, buf2);
ins_str(buf1); // insert the new number
endpos = curwin->w_cursor;
if (curwin->w_cursor.col) {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 799513e018..4c68e2bf16 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -44,6 +44,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
@@ -235,11 +236,11 @@ static void set_init_default_backupskip(void)
== NULL) {
ga_grow(&ga, (int)len);
if (!GA_EMPTY(&ga)) {
- STRCAT(ga.ga_data, ",");
+ strcat(ga.ga_data, ",");
}
- STRCAT(ga.ga_data, p);
+ strcat(ga.ga_data, p);
add_pathsep(ga.ga_data);
- STRCAT(ga.ga_data, "*");
+ strcat(ga.ga_data, "*");
ga.ga_len += (int)len;
}
xfree(item);
@@ -346,7 +347,7 @@ void set_init_1(bool clean_arg)
const size_t backupdir_len = strlen(backupdir);
backupdir = xrealloc(backupdir, backupdir_len + 3);
memmove(backupdir + 2, backupdir, backupdir_len + 1);
- memmove(backupdir, ".,", 2);
+ memmove(backupdir, S_LEN(".,"));
set_string_default(kOptBackupdir, backupdir, true);
set_string_default(kOptViewdir, stdpaths_user_state_subpath("view", 2, true),
true);
@@ -1003,10 +1004,10 @@ static set_op_T get_op(const char *arg)
static set_prefix_T get_option_prefix(char **argp)
{
- if (strncmp(*argp, "no", 2) == 0) {
+ if (strncmp(*argp, S_LEN("no")) == 0) {
*argp += 2;
return PREFIX_NO;
- } else if (strncmp(*argp, "inv", 3) == 0) {
+ } else if (strncmp(*argp, S_LEN("inv")) == 0) {
*argp += 3;
return PREFIX_INV;
}
@@ -1425,7 +1426,7 @@ int do_set(char *arg, int opt_flags)
did_show = true;
} else {
while (*arg != NUL) { // loop to process all options
- if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3])
+ if (strncmp(arg, S_LEN("all")) == 0 && !ASCII_ISALPHA(arg[3])
&& !(opt_flags & OPT_MODELINE)) {
// ":set all" show all options.
// ":set all&" set all options to their default value.
@@ -2770,7 +2771,7 @@ static void do_spelllang_source(win_T *win)
char *q = win->w_s->b_p_spl;
// Skip the first name if it is "cjk".
- if (strncmp(q, "cjk,", 4) == 0) {
+ if (strncmp(q, S_LEN("cjk,")) == 0) {
q += 4;
}
@@ -4569,6 +4570,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win)
return &(buf->b_p_def);
case PV_INC:
return &(buf->b_p_inc);
+ case PV_COT:
+ return &(buf->b_p_cot);
case PV_DICT:
return &(buf->b_p_dict);
case PV_TSR:
@@ -4652,6 +4655,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var;
case PV_INC:
return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var;
+ case PV_COT:
+ return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var;
case PV_DICT:
return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var;
case PV_TSR:
@@ -5331,6 +5336,8 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_inc = empty_string_option;
buf->b_p_inex = xstrdup(p_inex);
COPY_OPT_SCTX(buf, BV_INEX);
+ buf->b_p_cot = empty_string_option;
+ buf->b_cot_flags = 0;
buf->b_p_dict = empty_string_option;
buf->b_p_tsr = empty_string_option;
buf->b_p_tsrfu = empty_string_option;
@@ -5443,11 +5450,11 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
}
p--;
}
- if (strncmp(p, "no", 2) == 0) {
+ if (strncmp(p, S_LEN("no")) == 0) {
xp->xp_context = EXPAND_BOOL_SETTINGS;
xp->xp_prefix = XP_PREFIX_NO;
p += 2;
- } else if (strncmp(p, "inv", 3) == 0) {
+ } else if (strncmp(p, S_LEN("inv")) == 0) {
xp->xp_context = EXPAND_BOOL_SETTINGS;
xp->xp_prefix = XP_PREFIX_INV;
p += 3;
@@ -5642,7 +5649,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// manually handle it here to make sure we have the correct xp_context set.
// for 'spellsuggest' start at "file:"
if (options[opt_idx].var == &p_sps) {
- if (strncmp(xp->xp_pattern, "file:", 5) == 0) {
+ if (strncmp(xp->xp_pattern, S_LEN("file:")) == 0) {
xp->xp_pattern += 5;
return;
} else if (options[expand_option_idx].opt_expand_cb != NULL) {
@@ -6074,16 +6081,16 @@ int fill_culopt_flags(char *val, win_T *wp)
}
while (*p != NUL) {
// Note: Keep this in sync with p_culopt_values.
- if (strncmp(p, "line", 4) == 0) {
+ if (strncmp(p, S_LEN("line")) == 0) {
p += 4;
culopt_flags_new |= CULOPT_LINE;
- } else if (strncmp(p, "both", 4) == 0) {
+ } else if (strncmp(p, S_LEN("both")) == 0) {
p += 4;
culopt_flags_new |= CULOPT_LINE | CULOPT_NBR;
- } else if (strncmp(p, "number", 6) == 0) {
+ } else if (strncmp(p, S_LEN("number")) == 0) {
p += 6;
culopt_flags_new |= CULOPT_NBR;
- } else if (strncmp(p, "screenline", 10) == 0) {
+ } else if (strncmp(p, S_LEN("screenline")) == 0) {
p += 10;
culopt_flags_new |= CULOPT_SCRLINE;
}
@@ -6131,8 +6138,8 @@ int option_set_callback_func(char *optval, Callback *optcb)
typval_T *tv;
if (*optval == '{'
- || (strncmp(optval, "function(", 9) == 0)
- || (strncmp(optval, "funcref(", 8) == 0)) {
+ || (strncmp(optval, S_LEN("function(")) == 0)
+ || (strncmp(optval, S_LEN("funcref(")) == 0)) {
// Lambda expression or a funcref
tv = eval_expr(optval, NULL);
if (tv == NULL) {
@@ -6185,10 +6192,10 @@ bool can_bs(int what)
return vim_strchr(p_bs, what) != NULL;
}
-/// Get the local or global value of 'backupcopy'.
+/// Get the local or global value of 'backupcopy' flags.
///
/// @param buf The buffer.
-unsigned get_bkc_value(buf_T *buf)
+unsigned get_bkc_flags(buf_T *buf)
{
return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
}
@@ -6204,7 +6211,7 @@ char *get_flp_value(buf_T *buf)
return buf->b_p_flp;
}
-/// Get the local or global value of the 'virtualedit' flags.
+/// Get the local or global value of 'virtualedit' flags.
unsigned get_ve_flags(win_T *wp)
{
return (wp->w_ve_flags ? wp->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU);
diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h
index c98c84d34e..bd0fe699d9 100644
--- a/src/nvim/option_vars.h
+++ b/src/nvim/option_vars.h
@@ -430,6 +430,19 @@ EXTERN char *p_cpt; ///< 'complete'
EXTERN OptInt p_columns; ///< 'columns'
EXTERN int p_confirm; ///< 'confirm'
EXTERN char *p_cot; ///< 'completeopt'
+EXTERN unsigned cot_flags; ///< flags from 'completeopt'
+// Keep in sync with p_cot_values in optionstr.c
+#define COT_MENU 0x001
+#define COT_MENUONE 0x002
+#define COT_ANY_MENU 0x003 // combination of menu flags
+#define COT_LONGEST 0x004 // false: insert full match,
+ // true: insert longest prefix
+#define COT_PREVIEW 0x008
+#define COT_POPUP 0x010
+#define COT_ANY_PREVIEW 0x018 // combination of preview flags
+#define COT_NOINSERT 0x020 // false: select & insert, true: noinsert
+#define COT_NOSELECT 0x040 // false: select & insert, true: noselect
+#define COT_FUZZY 0x080 // true: fuzzy match enabled
#ifdef BACKSLASH_IN_FILENAME
EXTERN char *p_csl; ///< 'completeslash'
#endif
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 452cc6876b..f323926015 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1324,8 +1324,8 @@ return {
defaults = { if_true = '' },
desc = [=[
A template for a comment. The "%s" in the value is replaced with the
- comment text. For example, C uses "/*%s*/". Used for |commenting| and to
- add markers for folding, see |fold-marker|.
+ comment text, and should be padded with a space when possible.
+ Used for |commenting| and to add markers for folding, see |fold-marker|.
]=],
full_name = 'commentstring',
redraw = { 'curswant' },
@@ -1443,6 +1443,10 @@ return {
completion in the preview window. Only works in
combination with "menu" or "menuone".
+ popup Show extra information about the currently selected
+ completion in a popup window. Only works in combination
+ with "menu" or "menuone". Overrides "preview".
+
noinsert Do not insert any text for a match until the user selects
a match from the menu. Only works in combination with
"menu" or "menuone". No effect if "longest" is present.
@@ -1451,14 +1455,18 @@ return {
select one from the menu. Only works in combination with
"menu" or "menuone".
- popup Show extra information about the currently selected
- completion in a popup window. Only works in combination
- with "menu" or "menuone". Overrides "preview".
+ fuzzy Enable |fuzzy-matching| for completion candidates. This
+ allows for more flexible and intuitive matching, where
+ characters can be skipped and matches can be found even
+ if the exact sequence is not typed. Only makes a
+ difference how completion candidates are reduced from the
+ list of alternatives, but not how the candidates are
+ collected (using different completion types).
]=],
expand_cb = 'expand_set_completeopt',
full_name = 'completeopt',
list = 'onecomma',
- scope = { 'global' },
+ scope = { 'global', 'buffer' },
short_desc = N_('options for Insert mode completion'),
type = 'string',
varname = 'p_cot',
@@ -7317,8 +7325,8 @@ return {
message; also for quickfix message (e.g., ":cn")
s don't give "search hit BOTTOM, continuing at TOP" or *shm-s*
"search hit TOP, continuing at BOTTOM" messages; when using
- the search count do not show "W" after the count message (see
- S below)
+ the search count do not show "W" before the count message
+ (see |shm-S| below)
t truncate file message at the start if it is too long *shm-t*
to fit on the command-line, "<" will appear in the left most
column; ignored in Ex mode
@@ -7340,7 +7348,11 @@ return {
`:silent` was used for the command; note that this also
affects messages from 'autoread' reloading
S do not show search count message when searching, e.g. *shm-S*
- "[1/5]"
+ "[1/5]". When the "S" flag is not present (e.g. search count
+ is shown), the "search hit BOTTOM, continuing at TOP" and
+ "search hit TOP, continuing at BOTTOM" messages are only
+ indicated by a "W" (Mnemonic: Wrapped) letter before the
+ search count statistics.
This gives you the opportunity to avoid that a change between buffers
requires you to hit <Enter>, but still gives as useful a message as
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 29433ddbb5..503aa7f350 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -14,6 +14,7 @@
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
@@ -121,8 +122,8 @@ static char *(p_bs_values[]) = { "indent", "eol", "start", "nostop", NULL };
static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
"syntax", "diff", NULL };
static char *(p_fcl_values[]) = { "all", NULL };
-static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect",
- "popup", NULL };
+static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "popup",
+ "noinsert", "noselect", "fuzzy", NULL };
#ifdef BACKSLASH_IN_FILENAME
static char *(p_csl_values[]) = { "slash", "backslash", NULL };
#endif
@@ -157,6 +158,7 @@ void didset_string_options(void)
opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true);
opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, true);
opt_strings_flags(p_bo, p_bo_values, &bo_flags, true);
+ opt_strings_flags(p_cot, p_cot_values, &cot_flags, true);
opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true);
opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
@@ -218,6 +220,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_ft);
check_string_option(&buf->b_p_cinw);
check_string_option(&buf->b_p_cinsd);
+ check_string_option(&buf->b_p_cot);
check_string_option(&buf->b_p_cpt);
check_string_option(&buf->b_p_cfu);
check_string_option(&buf->b_p_ofu);
@@ -285,15 +288,15 @@ int check_signcolumn(win_T *wp)
}
if (check_opt_strings(val, p_scl_values, false) == OK) {
- if (!strncmp(val, "no", 2)) { // no
+ if (!strncmp(val, S_LEN("no"))) { // no
wp->w_minscwidth = wp->w_maxscwidth = SCL_NO;
- } else if (!strncmp(val, "nu", 2) && (wp->w_p_nu || wp->w_p_rnu)) { // number
+ } else if (!strncmp(val, S_LEN("nu")) && (wp->w_p_nu || wp->w_p_rnu)) { // number
wp->w_minscwidth = wp->w_maxscwidth = SCL_NUM;
- } else if (!strncmp(val, "yes:", 4)) { // yes:<NUM>
+ } else if (!strncmp(val, S_LEN("yes:"))) { // yes:<NUM>
wp->w_minscwidth = wp->w_maxscwidth = val[4] - '0';
} else if (*val == 'y') { // yes
wp->w_minscwidth = wp->w_maxscwidth = 1;
- } else if (!strncmp(val, "auto:", 5)) { // auto:<NUM>
+ } else if (!strncmp(val, S_LEN("auto:"))) { // auto:<NUM>
wp->w_minscwidth = 0;
wp->w_maxscwidth = val[5] - '0';
} else { // auto
@@ -303,7 +306,7 @@ int check_signcolumn(win_T *wp)
return OK;
}
- if (strncmp(val, "auto:", 5) != 0
+ if (strncmp(val, S_LEN("auto:")) != 0
|| strlen(val) != 8
|| !ascii_isdigit(val[5])
|| val[6] != '-'
@@ -992,10 +995,23 @@ int expand_set_complete(optexpand_T *args, int *numMatches, char ***matches)
/// The 'completeopt' option is changed.
const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED)
{
- if (check_opt_strings(p_cot, p_cot_values, true) != OK) {
+ buf_T *buf = (buf_T *)args->os_buf;
+ char *cot = p_cot;
+ unsigned *flags = &cot_flags;
+
+ if (args->os_flags & OPT_LOCAL) {
+ cot = buf->b_p_cot;
+ flags = &buf->b_cot_flags;
+ }
+
+ if (check_opt_strings(cot, p_cot_values, true) != OK) {
return e_invarg;
}
- completeopt_was_set();
+
+ if (opt_strings_flags(cot, p_cot_values, flags, true) != OK) {
+ return e_invarg;
+ }
+
return NULL;
}
@@ -1716,9 +1732,9 @@ const char *did_set_mousescroll(optset_T *args FUNC_ATTR_UNUSED)
OptInt *direction;
- if (memcmp(string, "ver:", 4) == 0) {
+ if (memcmp(string, S_LEN("ver:")) == 0) {
direction = &vertical;
- } else if (memcmp(string, "hor:", 4) == 0) {
+ } else if (memcmp(string, S_LEN("hor:")) == 0) {
direction = &horizontal;
} else {
return e_invarg;
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 5a79004c41..4689414559 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -63,13 +63,13 @@ const char *os_getenv(const char *name)
FUNC_ATTR_NONNULL_ALL
{
char *e = NULL;
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return NULL;
}
int r = 0;
if (map_has(cstr_t, &envmap, name)
&& !!(e = (char *)pmap_get(cstr_t)(&envmap, name))) {
- if (e[0] != '\0') {
+ if (e[0] != NUL) {
// Found non-empty cached env var.
// NOTE: This risks incoherence if an in-process library changes the
// environment without going through our os_setenv() wrapper. If
@@ -85,11 +85,11 @@ const char *os_getenv(const char *name)
if (r == UV_ENOBUFS) {
e = xmalloc(size);
r = uv_os_getenv(name, e, &size);
- if (r != 0 || size == 0 || e[0] == '\0') {
+ if (r != 0 || size == 0 || e[0] == NUL) {
XFREE_CLEAR(e);
goto end;
}
- } else if (r != 0 || size == 0 || buf[0] == '\0') {
+ } else if (r != 0 || size == 0 || buf[0] == NUL) {
e = NULL;
goto end;
} else {
@@ -110,7 +110,7 @@ end:
bool os_env_exists(const char *name)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return false;
}
// Use a tiny buffer because we don't care about the value: if uv_os_getenv()
@@ -134,14 +134,14 @@ bool os_env_exists(const char *name)
int os_setenv(const char *name, const char *value, int overwrite)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return -1;
}
#ifdef MSWIN
if (!overwrite && os_getenv(name) != NULL) {
return 0;
}
- if (value[0] == '\0') {
+ if (value[0] == NUL) {
// Windows (Vim-compat): Empty string undefines the env var.
return os_unsetenv(name);
}
@@ -174,7 +174,7 @@ int os_setenv(const char *name, const char *value, int overwrite)
int os_unsetenv(const char *name)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return -1;
}
pmap_del2(&envmap, name);
@@ -366,7 +366,7 @@ void os_get_hostname(char *hostname, size_t size)
struct utsname vutsname;
if (uname(&vutsname) < 0) {
- *hostname = '\0';
+ *hostname = NUL;
} else {
xstrlcpy(hostname, vutsname.nodename, size);
}
@@ -374,12 +374,12 @@ void os_get_hostname(char *hostname, size_t size)
wchar_t host_utf16[MAX_COMPUTERNAME_LENGTH + 1];
DWORD host_wsize = sizeof(host_utf16) / sizeof(host_utf16[0]);
if (GetComputerNameW(host_utf16, &host_wsize) == 0) {
- *hostname = '\0';
+ *hostname = NUL;
DWORD err = GetLastError();
semsg("GetComputerNameW failed: %d", err);
return;
}
- host_utf16[host_wsize] = '\0';
+ host_utf16[host_wsize] = NUL;
char *host_utf8;
int conversion_result = utf16_to_utf8(host_utf16, -1, &host_utf8);
@@ -391,7 +391,7 @@ void os_get_hostname(char *hostname, size_t size)
xfree(host_utf8);
#else
emsg("os_get_hostname failed: missing uname()");
- *hostname = '\0';
+ *hostname = NUL;
#endif
}
@@ -885,9 +885,9 @@ void vim_get_prefix_from_exepath(char *exe_name)
// but c_grammar.lua does not recognize it (yet).
xstrlcpy(exe_name, get_vim_var_str(VV_PROGPATH), MAXPATHL * sizeof(*exe_name));
char *path_end = path_tail_with_sep(exe_name);
- *path_end = '\0'; // remove the trailing "nvim.exe"
+ *path_end = NUL; // remove the trailing "nvim.exe"
path_end = path_tail(exe_name);
- *path_end = '\0'; // remove the trailing "bin/"
+ *path_end = NUL; // remove the trailing "bin/"
}
/// Vim getenv() wrapper with special handling of $HOME, $VIM, $VIMRUNTIME,
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index e58eb96c2e..585c4964e2 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -21,8 +21,6 @@
#include "nvim/os/fileio.h"
#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
#ifdef HAVE_SYS_UIO_H
@@ -120,12 +118,9 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags)
assert(!ret_fp->wr || !ret_fp->non_blocking);
ret_fp->fd = fd;
ret_fp->eof = false;
- ret_fp->rv = rbuffer_new(kRWBufferSize);
- ret_fp->_error = 0;
- if (ret_fp->wr) {
- ret_fp->rv->data = ret_fp;
- ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb;
- }
+ ret_fp->buffer = alloc_block();
+ ret_fp->read_pos = ret_fp->buffer;
+ ret_fp->write_pos = ret_fp->buffer;
ret_fp->bytes_read = 0;
return 0;
}
@@ -148,8 +143,9 @@ void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len)
ret_fp->non_blocking = false;
ret_fp->fd = -1;
ret_fp->eof = true;
- ret_fp->rv = rbuffer_new_wrap_buf(data, len);
- ret_fp->_error = 0;
+ ret_fp->buffer = NULL; // we don't take ownership
+ ret_fp->read_pos = data;
+ ret_fp->write_pos = data + len;
ret_fp->bytes_read = 0;
}
@@ -163,36 +159,18 @@ int file_close(FileDescriptor *const fp, const bool do_fsync)
FUNC_ATTR_NONNULL_ALL
{
if (fp->fd < 0) {
- rbuffer_free(fp->rv);
return 0;
}
const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp));
const int close_error = os_close(fp->fd);
- rbuffer_free(fp->rv);
+ free_block(fp->buffer);
if (close_error != 0) {
return close_error;
}
return flush_error;
}
-/// Flush file modifications to disk
-///
-/// @param[in,out] fp File to work with.
-///
-/// @return 0 or error code.
-int file_flush(FileDescriptor *const fp)
- FUNC_ATTR_NONNULL_ALL
-{
- if (!fp->wr) {
- return 0;
- }
- file_rb_write_full_cb(fp->rv, fp);
- const int error = fp->_error;
- fp->_error = 0;
- return error;
-}
-
/// Flush file modifications to disk and run fsync()
///
/// @param[in,out] fp File to work with.
@@ -218,36 +196,29 @@ int file_fsync(FileDescriptor *const fp)
return 0;
}
-/// Buffer used for writing
-///
-/// Like IObuff, but allows file_\* callers not to care about spoiling it.
-static char writebuf[kRWBufferSize];
-
-/// Function run when RBuffer is full when writing to a file
-///
-/// Actually does writing to the file, may also be invoked directly.
+/// Flush file modifications to disk
///
-/// @param[in,out] rv RBuffer instance used.
/// @param[in,out] fp File to work with.
-static void file_rb_write_full_cb(RBuffer *const rv, void *const fp_in)
+///
+/// @return 0 or error code.
+int file_flush(FileDescriptor *fp)
FUNC_ATTR_NONNULL_ALL
{
- FileDescriptor *const fp = fp_in;
- assert(fp->wr);
- assert(rv->data == (void *)fp);
- if (rbuffer_size(rv) == 0) {
- return;
+ if (!fp->wr) {
+ return 0;
+ }
+
+ ptrdiff_t to_write = fp->write_pos - fp->read_pos;
+ if (to_write == 0) {
+ return 0;
}
- const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize);
- const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes,
+ const ptrdiff_t wres = os_write(fp->fd, fp->read_pos, (size_t)to_write,
fp->non_blocking);
- if (wres != (ptrdiff_t)read_bytes) {
- if (wres >= 0) {
- fp->_error = UV_EIO;
- } else {
- fp->_error = (int)wres;
- }
+ fp->read_pos = fp->write_pos = fp->buffer;
+ if (wres != to_write) {
+ return (wres >= 0) ? UV_EIO : (int)wres;
}
+ return 0;
}
/// Read from file
@@ -262,77 +233,78 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(!fp->wr);
- char *buf = ret_buf;
- size_t read_remaining = size;
- RBuffer *const rv = fp->rv;
+ size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size);
+ memcpy(ret_buf, fp->read_pos, from_buffer);
+
+ char *buf = ret_buf + from_buffer;
+ size_t read_remaining = size - from_buffer;
+ if (!read_remaining) {
+ fp->bytes_read += from_buffer;
+ fp->read_pos += from_buffer;
+ return (ptrdiff_t)from_buffer;
+ }
+
+ // at this point, we have consumed all of an existing buffer. restart from the beginning
+ fp->read_pos = fp->write_pos = fp->buffer;
+
+#ifdef HAVE_READV
bool called_read = false;
while (read_remaining) {
- const size_t rv_size = rbuffer_size(rv);
- if (rv_size > 0) {
- const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining));
- buf += rsize;
- read_remaining -= rsize;
- }
- if (fp->eof
- // Allow only at most one os_read[v] call.
- || (called_read && fp->non_blocking)) {
+ // Allow only at most one os_read[v] call.
+ if (fp->eof || (called_read && fp->non_blocking)) {
break;
}
- if (read_remaining) {
- assert(rbuffer_size(rv) == 0);
- rbuffer_reset(rv);
-#ifdef HAVE_READV
- // If there is readv() syscall, then take an opportunity to populate
- // both target buffer and RBuffer at once, …
- size_t write_count;
- struct iovec iov[] = {
- { .iov_base = buf, .iov_len = read_remaining },
- { .iov_base = rbuffer_write_ptr(rv, &write_count),
- .iov_len = kRWBufferSize },
- };
- assert(write_count == kRWBufferSize);
- const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
- ARRAY_SIZE(iov), fp->non_blocking);
- if (r_ret > 0) {
- if (r_ret > (ptrdiff_t)read_remaining) {
- rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining));
- read_remaining = 0;
- } else {
- buf += (size_t)r_ret;
- read_remaining -= (size_t)r_ret;
- }
- } else if (r_ret < 0) {
- return r_ret;
- }
-#else
- if (read_remaining >= kRWBufferSize) {
- // …otherwise leave RBuffer empty and populate only target buffer,
- // because filtering information through rbuffer will be more syscalls.
- const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining,
- fp->non_blocking);
- if (r_ret >= 0) {
- read_remaining -= (size_t)r_ret;
- fp->bytes_read += (size - read_remaining);
- return (ptrdiff_t)(size - read_remaining);
- } else if (r_ret < 0) {
- return r_ret;
- }
+ // If there is readv() syscall, then take an opportunity to populate
+ // both target buffer and RBuffer at once, …
+ struct iovec iov[] = {
+ { .iov_base = buf, .iov_len = read_remaining },
+ { .iov_base = fp->write_pos,
+ .iov_len = ARENA_BLOCK_SIZE },
+ };
+ const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
+ ARRAY_SIZE(iov), fp->non_blocking);
+ if (r_ret > 0) {
+ if (r_ret > (ptrdiff_t)read_remaining) {
+ fp->write_pos += (size_t)(r_ret - (ptrdiff_t)read_remaining);
+ read_remaining = 0;
} else {
- size_t write_count;
- const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
- rbuffer_write_ptr(rv, &write_count),
- kRWBufferSize, fp->non_blocking);
- assert(write_count == kRWBufferSize);
- if (r_ret > 0) {
- rbuffer_produced(rv, (size_t)r_ret);
- } else if (r_ret < 0) {
- return r_ret;
- }
+ buf += r_ret;
+ read_remaining -= (size_t)r_ret;
}
-#endif
- called_read = true;
+ } else if (r_ret < 0) {
+ return r_ret;
+ }
+ called_read = true;
+ }
+#else
+ if (fp->eof) {
+ // already eof, cannot read more
+ } else if (read_remaining >= ARENA_BLOCK_SIZE) {
+ // …otherwise leave fp->buffer empty and populate only target buffer,
+ // because filtering information through rbuffer will be more syscalls.
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining,
+ fp->non_blocking);
+ if (r_ret >= 0) {
+ read_remaining -= (size_t)r_ret;
+ } else if (r_ret < 0) {
+ return r_ret;
+ }
+ } else {
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
+ fp->write_pos,
+ ARENA_BLOCK_SIZE, fp->non_blocking);
+ if (r_ret < 0) {
+ return r_ret;
+ } else {
+ fp->write_pos += r_ret;
+ size_t to_copy = MIN((size_t)r_ret, read_remaining);
+ memcpy(buf, fp->read_pos, to_copy);
+ fp->read_pos += to_copy;
+ read_remaining -= to_copy;
}
}
+#endif
+
fp->bytes_read += (size - read_remaining);
return (ptrdiff_t)(size - read_remaining);
}
@@ -348,40 +320,68 @@ ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
assert(fp->wr);
- const size_t written = rbuffer_write(fp->rv, buf, size);
- if (fp->_error != 0) {
- const int error = fp->_error;
- fp->_error = 0;
- return error;
- } else if (written != size) {
- return UV_EIO;
+ ptrdiff_t space = (fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos;
+ // includes the trivial case of size==0
+ if (size < (size_t)space) {
+ memcpy(fp->write_pos, buf, size);
+ fp->write_pos += size;
+ return (ptrdiff_t)size;
+ }
+
+ // TODO(bfredl): just as for reading, use iovec to combine fp->buffer with buf
+ int status = file_flush(fp);
+ if (status < 0) {
+ return status;
+ }
+
+ if (size < ARENA_BLOCK_SIZE) {
+ memcpy(fp->write_pos, buf, size);
+ fp->write_pos += size;
+ return (ptrdiff_t)size;
}
- return (ptrdiff_t)written;
-}
-/// Buffer used for skipping. Its contents is undefined and should never be
-/// used.
-static char skipbuf[kRWBufferSize];
+ const ptrdiff_t wres = os_write(fp->fd, buf, size,
+ fp->non_blocking);
+ return (wres != (ptrdiff_t)size && wres >= 0) ? UV_EIO : wres;
+}
/// Skip some bytes
///
/// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply
-/// reads to a buffer and discards the result.
+/// reads to the buffer and discards the result.
ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size)
FUNC_ATTR_NONNULL_ALL
{
assert(!fp->wr);
- size_t read_bytes = 0;
- do {
- const ptrdiff_t new_read_bytes =
- file_read(fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf)));
- if (new_read_bytes < 0) {
- return new_read_bytes;
- } else if (new_read_bytes == 0) {
+ size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size);
+ size_t skip_remaining = size - from_buffer;
+ if (skip_remaining == 0) {
+ fp->read_pos += from_buffer;
+ fp->bytes_read += from_buffer;
+ return (ptrdiff_t)from_buffer;
+ }
+
+ fp->read_pos = fp->write_pos = fp->buffer;
+ bool called_read = false;
+ while (skip_remaining > 0) {
+ // Allow only at most one os_read[v] call.
+ if (fp->eof || (called_read && fp->non_blocking)) {
break;
}
- read_bytes += (size_t)new_read_bytes;
- } while (read_bytes < size && !file_eof(fp));
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, fp->buffer, ARENA_BLOCK_SIZE,
+ fp->non_blocking);
+ if (r_ret < 0) {
+ return r_ret;
+ } else if ((size_t)r_ret > skip_remaining) {
+ fp->read_pos = fp->buffer + skip_remaining;
+ fp->write_pos = fp->buffer + r_ret;
+ fp->bytes_read += size;
+ return (ptrdiff_t)size;
+ }
+ skip_remaining -= (size_t)r_ret;
+ called_read = true;
+ }
- return (ptrdiff_t)read_bytes;
+ fp->bytes_read += size - skip_remaining;
+ return (ptrdiff_t)(size - skip_remaining);
}
diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h
index 10277d2a7a..0f76fdb2aa 100644
--- a/src/nvim/os/fileio_defs.h
+++ b/src/nvim/os/fileio_defs.h
@@ -4,13 +4,13 @@
#include <stdint.h>
#include "nvim/func_attr.h"
-#include "nvim/rbuffer_defs.h"
/// Structure used to read from/write to file
typedef struct {
- int fd; ///< File descriptor.
- int _error; ///< Error code for use with RBuffer callbacks or zero.
- RBuffer *rv; ///< Read or write buffer.
+ int fd; ///< File descriptor. Can be -1 if no backing file (file_open_buffer)
+ char *buffer; ///< Read or write buffer. always ARENA_BLOCK_SIZE if allocated
+ char *read_pos; ///< read position in buffer
+ char *write_pos; ///< write position in buffer
bool wr; ///< True if file is in write mode.
bool eof; ///< True if end of file was encountered.
bool non_blocking; ///< True if EAGAIN should not restart syscalls.
@@ -28,7 +28,7 @@ static inline bool file_eof(const FileDescriptor *fp)
/// performed.
static inline bool file_eof(const FileDescriptor *const fp)
{
- return fp->eof && rbuffer_size(fp->rv) == 0;
+ return fp->eof && fp->read_pos == fp->write_pos;
}
static inline int file_fd(const FileDescriptor *fp)
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 19bdf30311..b681b2f832 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -17,6 +17,7 @@
#endif
#include "auto/config.h"
+#include "nvim/errors.h"
#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
@@ -301,7 +302,7 @@ static bool is_executable_ext(const char *name, char **abspath)
char *nameext = strrchr(name, '.');
size_t nameext_len = nameext ? strlen(nameext) : 0;
xstrlcpy(os_buf, name, sizeof(os_buf));
- char *buf_end = xstrchrnul(os_buf, '\0');
+ char *buf_end = xstrchrnul(os_buf, NUL);
const char *pathext = os_getenv("PATHEXT");
if (!pathext) {
pathext = ".com;.exe;.bat;.cmd";
@@ -309,7 +310,7 @@ static bool is_executable_ext(const char *name, char **abspath)
const char *ext = pathext;
while (*ext) {
// If $PATHEXT itself contains dot:
- if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ENV_SEPCHAR)) {
+ if (ext[0] == '.' && (ext[1] == NUL || ext[1] == ENV_SEPCHAR)) {
if (is_executable(name, abspath)) {
return true;
}
@@ -435,7 +436,7 @@ FILE *os_fopen(const char *path, const char *flags)
assert(flags != NULL && strlen(flags) > 0 && strlen(flags) <= 2);
int iflags = 0;
// Per table in fopen(3) manpage.
- if (flags[1] == '\0' || flags[1] == 'b') {
+ if (flags[1] == NUL || flags[1] == 'b') {
switch (flags[0]) {
case 'r':
iflags = O_RDONLY;
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 60b5b48745..ea21a32230 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -27,13 +27,11 @@
#include "nvim/os/os_defs.h"
#include "nvim/os/time.h"
#include "nvim/profile.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/state.h"
#include "nvim/state_defs.h"
#define READ_BUFFER_SIZE 0xfff
-#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4)
+#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN)
typedef enum {
kInputNone,
@@ -41,8 +39,11 @@ typedef enum {
kInputEof,
} InbufPollResult;
-static Stream read_stream = { .closed = true }; // Input before UI starts.
-static RBuffer *input_buffer = NULL;
+static RStream read_stream = { .s.closed = true }; // Input before UI starts.
+static char input_buffer[INPUT_BUFFER_SIZE];
+static char *input_read_pos = input_buffer;
+static char *input_write_pos = input_buffer;
+
static bool input_eof = false;
static bool blocking = false;
static int cursorhold_time = 0; ///< time waiting for CursorHold event
@@ -52,38 +53,26 @@ static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting starte
# include "os/input.c.generated.h"
#endif
-void input_init(void)
-{
- input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
-}
-
void input_start(void)
{
- if (!read_stream.closed) {
+ if (!read_stream.s.closed) {
return;
}
used_stdin = true;
- rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO, READ_BUFFER_SIZE);
+ rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO);
rstream_start(&read_stream, input_read_cb, NULL);
}
void input_stop(void)
{
- if (read_stream.closed) {
+ if (read_stream.s.closed) {
return;
}
rstream_stop(&read_stream);
- stream_close(&read_stream, NULL, NULL);
-}
-
-#ifdef EXITFREE
-void input_free_all_mem(void)
-{
- rbuffer_free(input_buffer);
+ rstream_may_close(&read_stream);
}
-#endif
static void cursorhold_event(void **argv)
{
@@ -119,9 +108,12 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
restart_cursorhold_wait(tb_change_cnt);
}
- if (maxlen && rbuffer_size(input_buffer)) {
+ if (maxlen && input_available()) {
restart_cursorhold_wait(tb_change_cnt);
- return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
+ size_t to_read = MIN((size_t)maxlen, input_available());
+ memcpy(buf, input_read_pos, to_read);
+ input_read_pos += to_read;
+ return (int)to_read;
}
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
@@ -138,7 +130,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
uint64_t wait_start = os_hrtime();
cursorhold_time = MIN(cursorhold_time, (int)p_ut);
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) {
- if (read_stream.closed && silent_mode) {
+ if (read_stream.s.closed && silent_mode) {
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
read_error_exit();
}
@@ -161,11 +153,14 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
return 0;
}
- if (maxlen && rbuffer_size(input_buffer)) {
+ if (maxlen && input_available()) {
restart_cursorhold_wait(tb_change_cnt);
- // Safe to convert rbuffer_read to int, it will never overflow since we use
- // relatively small buffers.
- return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
+ // Safe to convert `to_read` to int, it will never overflow since
+ // INPUT_BUFFER_SIZE fits in an int
+ size_t to_read = MIN((size_t)maxlen, input_available());
+ memcpy(buf, input_read_pos, to_read);
+ input_read_pos += to_read;
+ return (int)to_read;
}
// If there are events, return the keys directly
@@ -247,11 +242,28 @@ bool os_isatty(int fd)
return uv_guess_handle(fd) == UV_TTY;
}
-void input_enqueue_raw(String keys)
+size_t input_available(void)
{
- if (keys.size > 0) {
- rbuffer_write(input_buffer, keys.data, keys.size);
+ return (size_t)(input_write_pos - input_read_pos);
+}
+
+static size_t input_space(void)
+{
+ return (size_t)(input_buffer + INPUT_BUFFER_SIZE - input_write_pos);
+}
+
+void input_enqueue_raw(const char *data, size_t size)
+{
+ if (input_read_pos > input_buffer) {
+ size_t available = input_available();
+ memmove(input_buffer, input_read_pos, available);
+ input_read_pos = input_buffer;
+ input_write_pos = input_buffer + available;
}
+
+ size_t to_write = MIN(size, input_space());
+ memcpy(input_write_pos, data, to_write);
+ input_write_pos += to_write;
}
size_t input_enqueue(String keys)
@@ -259,7 +271,7 @@ size_t input_enqueue(String keys)
const char *ptr = keys.data;
const char *end = ptr + keys.size;
- while (rbuffer_space(input_buffer) >= 19 && ptr < end) {
+ while (input_space() >= 19 && ptr < end) {
// A "<x>" form occupies at least 1 characters, and produces up
// to 19 characters (1 + 5 * 3 for the char and 3 for a modifier).
// In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed,
@@ -272,7 +284,7 @@ size_t input_enqueue(String keys)
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);
- rbuffer_write(input_buffer, (char *)buf, new_size);
+ input_enqueue_raw((char *)buf, new_size);
continue;
}
@@ -293,11 +305,11 @@ size_t input_enqueue(String keys)
// copy the character, escaping K_SPECIAL
if ((uint8_t)(*ptr) == K_SPECIAL) {
- rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1);
} else {
- rbuffer_write(input_buffer, ptr, 1);
+ input_enqueue_raw(ptr, 1);
}
ptr++;
}
@@ -422,7 +434,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs
return bufsize;
}
-size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
+void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
{
modifier |= check_multiclick(code, grid, row, col);
uint8_t buf[7];
@@ -442,8 +454,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co
mouse_col = col;
size_t written = 3 + (size_t)(p - buf);
- rbuffer_write(input_buffer, (char *)buf, written);
- return written;
+ input_enqueue_raw((char *)buf, written);
}
/// @return true if the main loop is blocked and waiting for input.
@@ -484,22 +495,15 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
return input_eof ? kInputEof : kInputNone;
}
-bool input_available(void)
-{
- return rbuffer_size(input_buffer) != 0;
-}
-
-static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bool at_eof)
+static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof)
{
if (at_eof) {
input_eof = true;
}
- assert(rbuffer_space(input_buffer) >= rbuffer_size(buf));
- RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
- (void)rbuffer_write(input_buffer, ptr, len);
- rbuffer_consumed(buf, len);
- }
+ assert(input_space() >= c);
+ input_enqueue_raw(buf, c);
+ return c;
}
static void process_ctrl_c(void)
@@ -508,23 +512,24 @@ static void process_ctrl_c(void)
return;
}
- size_t consume_count = 0;
- RBUFFER_EACH_REVERSE(input_buffer, c, i) {
- if ((uint8_t)c == Ctrl_C
- || ((uint8_t)c == 'C' && i >= 3
- && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL
- && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER
- && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) {
- *rbuffer_get(input_buffer, i) = Ctrl_C;
+ size_t available = input_available();
+ ssize_t i;
+ for (i = (ssize_t)available - 1; i >= 0; i--) {
+ uint8_t c = (uint8_t)input_read_pos[i];
+ if (c == Ctrl_C
+ || (c == 'C' && i >= 3
+ && (uint8_t)input_read_pos[i - 3] == K_SPECIAL
+ && (uint8_t)input_read_pos[i - 2] == KS_MODIFIER
+ && (uint8_t)input_read_pos[i - 1] == MOD_MASK_CTRL)) {
+ input_read_pos[i] = Ctrl_C;
got_int = true;
- consume_count = i;
break;
}
}
- if (got_int && consume_count) {
+ if (got_int && i > 0) {
// Remove all unprocessed input (typeahead) before the CTRL-C.
- rbuffer_consumed(input_buffer, consume_count);
+ input_read_pos += i;
}
}
@@ -548,7 +553,7 @@ static int push_event_key(uint8_t *buf, int maxlen)
bool os_input_ready(MultiQueue *events)
{
return (typebuf_was_filled // API call filled typeahead
- || rbuffer_size(input_buffer) // Input buffer filled
+ || input_available() // Input buffer filled
|| pending_events(events)); // Events must be processed
}
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 4d34e8fac4..cfa4dcada7 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -169,7 +169,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
int status = 0; // zero or negative error code (libuv convention)
Process *proc = (Process *)ptyproc;
- assert(proc->err.closed);
+ assert(proc->err.s.closed);
uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD);
ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 };
uv_disable_stdio_inheritance();
@@ -208,8 +208,8 @@ int pty_process_spawn(PtyProcess *ptyproc)
&& (status = set_duplicating_descriptor(master, &proc->in.uv.pipe))) {
goto error;
}
- if (!proc->out.closed
- && (status = set_duplicating_descriptor(master, &proc->out.uv.pipe))) {
+ if (!proc->out.s.closed
+ && (status = set_duplicating_descriptor(master, &proc->out.s.uv.pipe))) {
goto error;
}
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 12831ff05f..39c3966c1c 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -55,7 +55,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
wchar_t *env = NULL;
const char *emsg = NULL;
- assert(proc->err.closed);
+ assert(proc->err.s.closed);
if (!os_has_conpty_working() || (conpty_object = os_conpty_init(&in_name,
&out_name, ptyproc->width,
@@ -72,10 +72,10 @@ int pty_process_spawn(PtyProcess *ptyproc)
pty_process_connect_cb);
}
- if (!proc->out.closed) {
+ if (!proc->out.s.closed) {
out_req = xmalloc(sizeof(uv_connect_t));
uv_pipe_connect(out_req,
- &proc->out.uv.pipe,
+ &proc->out.s.uv.pipe,
out_name,
pty_process_connect_cb);
}
@@ -216,7 +216,7 @@ static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer)
Process *proc = (Process *)ptyproc;
assert(ptyproc->finish_wait != NULL);
- if (proc->out.closed || proc->out.did_eof || !uv_is_readable(proc->out.uvstream)) {
+ if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) {
uv_timer_stop(&ptyproc->wait_eof_timer);
pty_process_finish2(ptyproc);
}
@@ -399,7 +399,7 @@ static int build_env_block(dict_T *denv, wchar_t **env_block)
QUEUE_INSERT_TAIL(&env_q, &env_node->node);
}
- // Additional '\0' after the final entry
+ // Additional NUL after the final entry
env_block_len++;
*env_block = xmalloc(sizeof(**env_block) * env_block_len);
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 2a10510b0f..4b34ed1c4e 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -10,6 +10,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/event/defs.h"
@@ -39,8 +40,6 @@
#include "nvim/path.h"
#include "nvim/pos_defs.h"
#include "nvim/profile.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/state_defs.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
@@ -48,17 +47,11 @@
#include "nvim/ui.h"
#include "nvim/vim_defs.h"
-#define DYNAMIC_BUFFER_INIT { NULL, 0, 0 }
#define NS_1_SECOND 1000000000U // 1 second, in nanoseconds
#define OUT_DATA_THRESHOLD 1024 * 10U // 10KB, "a few screenfuls" of data.
#define SHELL_SPECIAL "\t \"&'$;<>()\\|"
-typedef struct {
- char *data;
- size_t cap, len;
-} DynamicBuffer;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/shell.c.generated.h"
#endif
@@ -255,11 +248,11 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
} else {
STRCPY(command, "(");
}
- STRCAT(command, pat[0] + 1); // exclude first backtick
+ strcat(command, pat[0] + 1); // exclude first backtick
p = command + strlen(command) - 1;
if (is_fish_shell) {
*p-- = ';';
- STRCAT(command, " end");
+ strcat(command, " end");
} else {
*p-- = ')'; // remove last backtick
}
@@ -270,7 +263,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
ampersand = true;
*p = ' ';
}
- STRCAT(command, ">");
+ strcat(command, ">");
} else {
STRCPY(command, "");
if (shell_style == STYLE_GLOB) {
@@ -278,26 +271,26 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
// otherwise, this may set the positional parameters for the shell,
// e.g. "$*".
if (flags & EW_NOTFOUND) {
- STRCAT(command, "set nonomatch; ");
+ strcat(command, "set nonomatch; ");
} else {
- STRCAT(command, "unset nonomatch; ");
+ strcat(command, "unset nonomatch; ");
}
}
if (shell_style == STYLE_GLOB) {
- STRCAT(command, "glob >");
+ strcat(command, "glob >");
} else if (shell_style == STYLE_PRINT) {
- STRCAT(command, "print -N >");
+ strcat(command, "print -N >");
} else if (shell_style == STYLE_VIMGLOB) {
- STRCAT(command, sh_vimglob_func);
+ strcat(command, sh_vimglob_func);
} else if (shell_style == STYLE_GLOBSTAR) {
- STRCAT(command, sh_globstar_opt);
- STRCAT(command, sh_vimglob_func);
+ strcat(command, sh_globstar_opt);
+ strcat(command, sh_vimglob_func);
} else {
- STRCAT(command, "echo >");
+ strcat(command, "echo >");
}
}
- STRCAT(command, tempname);
+ strcat(command, tempname);
if (shell_style != STYLE_BT) {
for (i = 0; i < num_pat; i++) {
@@ -341,7 +334,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
}
if (ampersand) {
- STRCAT(command, "&"); // put the '&' after the redirection
+ strcat(command, "&"); // put the '&' after the redirection
}
// Using zsh -G: If a pattern has no matches, it is just deleted from
@@ -647,13 +640,13 @@ char *shell_argv_to_str(char **const argv)
p++;
}
if (n < maxsize) {
- rv[n - 1] = '\0';
+ rv[n - 1] = NUL;
} else {
// Command too long, show ellipsis: "/bin/bash 'foo' 'bar'..."
rv[maxsize - 4] = '.';
rv[maxsize - 3] = '.';
rv[maxsize - 2] = '.';
- rv[maxsize - 1] = '\0';
+ rv[maxsize - 1] = NUL;
}
return rv;
}
@@ -668,7 +661,7 @@ char *shell_argv_to_str(char **const argv)
/// @return shell command exit code
int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
{
- DynamicBuffer input = DYNAMIC_BUFFER_INIT;
+ StringBuilder input = KV_INITIAL_VALUE;
char *output = NULL;
char **output_ptr = NULL;
int current_state = State;
@@ -697,9 +690,9 @@ int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
size_t nread;
int exitcode = do_os_system(shell_build_argv(cmd, extra_args),
- input.data, input.len, output_ptr, &nread,
+ input.items, input.size, output_ptr, &nread,
emsg_silent, forward_output);
- xfree(input.data);
+ kv_destroy(input);
if (output) {
write_output(output, nread, true);
@@ -860,10 +853,10 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
{
out_data_decide_throttle(0); // Initialize throttle decider.
out_data_ring(NULL, 0); // Initialize output ring-buffer.
- bool has_input = (input != NULL && input[0] != '\0');
+ bool has_input = (input != NULL && input[0] != NUL);
// the output buffer
- DynamicBuffer buf = DYNAMIC_BUFFER_INIT;
+ StringBuilder buf = KV_INITIAL_VALUE;
stream_read_cb data_cb = system_data_cb;
if (nread) {
*nread = 0;
@@ -906,9 +899,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
if (has_input) {
wstream_init(&proc->in, 0);
}
- rstream_init(&proc->out, 0);
+ rstream_init(&proc->out);
rstream_start(&proc->out, data_cb, &buf);
- rstream_init(&proc->err, 0);
+ rstream_init(&proc->err);
rstream_start(&proc->err, data_cb, &buf);
// write the input, if any
@@ -951,18 +944,17 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
// prepare the out parameters if requested
if (output) {
- if (buf.len == 0) {
+ assert(nread);
+ if (buf.size == 0) {
// no data received from the process, return NULL
*output = NULL;
- xfree(buf.data);
+ *nread = 0;
+ kv_destroy(buf);
} else {
+ *nread = buf.size;
// NUL-terminate to make the output directly usable as a C string
- buf.data[buf.len] = NUL;
- *output = buf.data;
- }
-
- if (nread) {
- *nread = buf.len;
+ kv_push(buf, NUL);
+ *output = buf.items;
}
}
@@ -972,29 +964,11 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
return exitcode;
}
-/// - ensures at least `desired` bytes in buffer
-///
-/// TODO(aktau): fold with kvec/garray
-static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired)
-{
- if (buf->cap >= desired) {
- assert(buf->data);
- return;
- }
-
- buf->cap = desired;
- kv_roundup32(buf->cap);
- buf->data = xrealloc(buf->data, buf->cap);
-}
-
-static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+static size_t system_data_cb(RStream *stream, const char *buf, size_t count, void *data, bool eof)
{
- DynamicBuffer *dbuf = data;
-
- size_t nread = buf->size;
- dynamic_buffer_ensure(dbuf, dbuf->len + nread + 1);
- rbuffer_read(buf, dbuf->data + dbuf->len, nread);
- dbuf->len += nread;
+ StringBuilder *dbuf = data;
+ kv_concat_len(*dbuf, buf, count);
+ return count;
}
/// Tracks output received for the current executing shell command, and displays
@@ -1023,7 +997,7 @@ static bool out_data_decide_throttle(size_t size)
static uint64_t started = 0; // Start time of the current throttle.
static size_t received = 0; // Bytes observed since last throttle.
static size_t visit = 0; // "Pulse" count of the current throttle.
- static char pulse_msg[] = { ' ', ' ', ' ', '\0' };
+ static char pulse_msg[] = { ' ', ' ', ' ', NUL };
if (!size) {
bool previous_decision = (visit > 0);
@@ -1077,7 +1051,7 @@ static bool out_data_decide_throttle(size_t size)
///
/// @param output Data to save, or NULL to invoke a special mode.
/// @param size Length of `output`.
-static void out_data_ring(char *output, size_t size)
+static void out_data_ring(const char *output, size_t size)
{
#define MAX_CHUNK_SIZE (OUT_DATA_THRESHOLD / 2)
static char last_skipped[MAX_CHUNK_SIZE]; // Saved output.
@@ -1119,11 +1093,11 @@ static void out_data_ring(char *output, size_t size)
/// @param output Data to append to screen lines.
/// @param count Size of data.
/// @param eof If true, there will be no more data output.
-static void out_data_append_to_screen(char *output, size_t *count, bool eof)
+static void out_data_append_to_screen(const char *output, size_t *count, bool eof)
FUNC_ATTR_NONNULL_ALL
{
- char *p = output;
- char *end = output + *count;
+ const char *p = output;
+ const char *end = output + *count;
while (p < end) {
if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) {
msg_putchar_attr((uint8_t)(*p), 0);
@@ -1151,25 +1125,16 @@ end:
ui_flush();
}
-static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+static size_t out_data_cb(RStream *stream, const char *ptr, size_t count, void *data, bool eof)
{
- size_t cnt;
- char *ptr = rbuffer_read_ptr(buf, &cnt);
-
- if (ptr != NULL && cnt > 0
- && out_data_decide_throttle(cnt)) { // Skip output above a threshold.
+ if (count > 0 && out_data_decide_throttle(count)) { // Skip output above a threshold.
// Save the skipped output. If it is the final chunk, we display it later.
- out_data_ring(ptr, cnt);
- } else if (ptr != NULL) {
- out_data_append_to_screen(ptr, &cnt, eof);
- }
-
- if (cnt) {
- rbuffer_consumed(buf, cnt);
+ out_data_ring(ptr, count);
+ } else if (count > 0) {
+ out_data_append_to_screen(ptr, &count, eof);
}
- // Move remaining data to start of buffer, so the buffer can never wrap around.
- rbuffer_reset(buf);
+ return count;
}
/// Parses a command string into a sequence of words, taking quotes into
@@ -1233,7 +1198,7 @@ static size_t word_length(const char *str)
/// event loop starts. If we don't (by writing in chunks returned by `ml_get`)
/// the buffer being modified might get modified by reading from the process
/// before we finish writing.
-static void read_input(DynamicBuffer *buf)
+static void read_input(StringBuilder *buf)
{
size_t written = 0;
size_t len = 0;
@@ -1247,14 +1212,11 @@ static void read_input(DynamicBuffer *buf)
} else if (lp[written] == NL) {
// NL -> NUL translation
len = 1;
- dynamic_buffer_ensure(buf, buf->len + len);
- buf->data[buf->len++] = NUL;
+ kv_push(*buf, NUL);
} else {
char *s = vim_strchr(lp + written, NL);
len = s == NULL ? l : (size_t)(s - (lp + written));
- dynamic_buffer_ensure(buf, buf->len + len);
- memcpy(buf->data + buf->len, lp + written, len);
- buf->len += len;
+ kv_concat_len(*buf, lp + written, len);
}
if (len == l) {
@@ -1263,8 +1225,7 @@ static void read_input(DynamicBuffer *buf)
|| (!curbuf->b_p_bin && curbuf->b_p_fixeol)
|| (lnum != curbuf->b_no_eol_lnum
&& (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) {
- dynamic_buffer_ensure(buf, buf->len + 1);
- buf->data[buf->len++] = NL;
+ kv_push(*buf, NL);
}
lnum++;
if (lnum > curbuf->b_op_end.lnum) {
@@ -1331,7 +1292,7 @@ static void shell_write_cb(Stream *stream, void *data, int status)
msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"),
uv_err_name(status));
}
- stream_close(stream, NULL, NULL);
+ stream_close(stream, NULL, NULL, false);
}
/// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command.
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index e5bdd56fe6..e4435bcaa8 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -69,7 +69,7 @@ static const char *const xdg_defaults[] = {
const char *get_appname(void)
{
const char *env_val = os_getenv("NVIM_APPNAME");
- if (env_val == NULL || *env_val == '\0') {
+ if (env_val == NULL || *env_val == NUL) {
env_val = "nvim";
}
return env_val;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index d782d1a989..aa630038a8 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -962,7 +962,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern)
char *file_pattern = xmalloc(len + 2);
file_pattern[0] = '*';
file_pattern[1] = NUL;
- STRCAT(file_pattern, pattern);
+ strcat(file_pattern, pattern);
char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, true);
xfree(file_pattern);
if (pat == NULL) {
@@ -1065,7 +1065,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern)
rel_path = xmalloc(strlen(short_name) + strlen(PATHSEPSTR) + 2);
STRCPY(rel_path, ".");
add_pathsep(rel_path);
- STRCAT(rel_path, short_name);
+ strcat(rel_path, short_name);
xfree(fnames[i]);
fnames[i] = rel_path;
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index 5881d34c48..f273f88dd1 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <string.h>
+#include "nvim/api/extmark.h"
#include "nvim/ascii_defs.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
@@ -158,7 +159,7 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco
break;
} else if (mark.pos.col == col) {
if (!mt_end(mark) && (mark.flags & MT_FLAG_DECOR_VIRT_TEXT_INLINE)
- && mt_scoped_in_win(mark, wp)) {
+ && ns_in_win(mark.ns, wp)) {
DecorInline decor = mt_decor(mark);
DecorVirtText *vt = decor.ext ? decor.data.ext.vt : NULL;
while (vt) {
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index 86f3611ec5..324254a188 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -19,6 +19,7 @@
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
@@ -699,7 +700,7 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma
}
// delete the empty last line
ml_delete_buf(buf, buf->b_ml.ml_line_count, false);
- if (strstr(p_cot, "popup") != NULL) {
+ if (get_cot_flags() & COT_POPUP) {
extmark_splice(buf, 1, 0, 1, 0, 0, buf->b_ml.ml_line_count, 0, inserted_bytes, kExtmarkNoUndo);
}
}
@@ -794,7 +795,8 @@ static bool pum_set_selected(int n, int repeat)
int prev_selected = pum_selected;
pum_selected = n;
- bool use_float = strstr(p_cot, "popup") != NULL;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool use_float = (cur_cot_flags & COT_POPUP) != 0;
// when new leader add and info window is shown and no selected we still
// need use the first index item to update the info float window position.
bool force_select = use_float && pum_selected < 0 && win_float_find_preview();
@@ -860,7 +862,7 @@ static bool pum_set_selected(int n, int repeat)
if ((pum_array[pum_selected].pum_info != NULL)
&& (Rows > 10)
&& (repeat <= 1)
- && (vim_strchr(p_cot, 'p') != NULL)) {
+ && (cur_cot_flags & COT_ANY_PREVIEW)) {
win_T *curwin_save = curwin;
tabpage_T *curtab_save = curtab;
diff --git a/src/nvim/popupmenu.h b/src/nvim/popupmenu.h
index 20a342b841..9e3f8f5a7f 100644
--- a/src/nvim/popupmenu.h
+++ b/src/nvim/popupmenu.h
@@ -10,10 +10,11 @@
/// Used for popup menu items.
typedef struct {
- char *pum_text; // main menu text
- char *pum_kind; // extra kind text (may be truncated)
- char *pum_extra; // extra menu text (may be truncated)
- char *pum_info; // extra info
+ char *pum_text; ///< main menu text
+ char *pum_kind; ///< extra kind text (may be truncated)
+ char *pum_extra; ///< extra menu text (may be truncated)
+ char *pum_info; ///< extra info
+ int pum_score; ///< fuzzy match score
} pumitem_T;
EXTERN ScreenGrid pum_grid INIT( = SCREEN_GRID_INIT);
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
index b88b08d3f0..f5e8e013ac 100644
--- a/src/nvim/profile.c
+++ b/src/nvim/profile.c
@@ -10,6 +10,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/debugger.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
@@ -293,7 +294,7 @@ void ex_profile(exarg_T *eap)
int len = (int)(e - eap->arg);
e = skipwhite(e);
- if (len == 5 && strncmp(eap->arg, "start", 5) == 0 && *e != NUL) {
+ if (len == 5 && strncmp(eap->arg, S_LEN("start")) == 0 && *e != NUL) {
xfree(profile_fname);
profile_fname = expand_env_save_opt(e, true);
do_profiling = PROF_YES;
@@ -368,12 +369,12 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg)
return;
}
- if ((end_subcmd - arg == 5 && strncmp(arg, "start", 5) == 0)
- || (end_subcmd - arg == 4 && strncmp(arg, "file", 4) == 0)) {
+ if ((end_subcmd - arg == 5 && strncmp(arg, S_LEN("start")) == 0)
+ || (end_subcmd - arg == 4 && strncmp(arg, S_LEN("file")) == 0)) {
xp->xp_context = EXPAND_FILES;
xp->xp_pattern = skipwhite(end_subcmd);
return;
- } else if (end_subcmd - arg == 4 && strncmp(arg, "func", 4) == 0) {
+ } else if (end_subcmd - arg == 4 && strncmp(arg, S_LEN("func")) == 0) {
xp->xp_context = EXPAND_USER_FUNC;
xp->xp_pattern = skipwhite(end_subcmd);
return;
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index e022184f2f..ed3fd83fd5 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -20,6 +20,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/window.h"
@@ -723,7 +724,7 @@ static int qf_get_next_str_line(qfstate_T *state)
state->linelen = len;
}
memcpy(state->linebuf, p_str, state->linelen);
- state->linebuf[state->linelen] = '\0';
+ state->linebuf[state->linelen] = NUL;
// Increment using len in order to discard the rest of the line if it
// exceeds LINE_MAXLEN.
@@ -4530,7 +4531,7 @@ static char *get_mef_name(void)
name = xmalloc(strlen(p_mef) + 30);
STRCPY(name, p_mef);
snprintf(name + (p - p_mef), strlen(name), "%d%d", start, off);
- STRCAT(name, p + 2);
+ strcat(name, p + 2);
// Don't accept a symbolic link, it's a security risk.
FileInfo file_info;
bool file_or_link_found = os_fileinfo_link(name, &file_info);
@@ -7236,7 +7237,7 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char *dirname, regmatch_T *p
// Find all "*.txt" and "*.??x" files in the "doc" directory.
add_pathsep(dirname);
- STRCAT(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT
+ strcat(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT
if (gen_expand_wildcards(1, &dirname, &fcount, &fnames, EW_FILE|EW_SILENT) == OK
&& fcount > 0) {
for (int fi = 0; fi < fcount && !got_int; fi++) {
diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c
deleted file mode 100644
index cf2e10f90d..0000000000
--- a/src/nvim/rbuffer.c
+++ /dev/null
@@ -1,247 +0,0 @@
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "nvim/macros_defs.h"
-#include "nvim/memory.h"
-#include "nvim/rbuffer.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "rbuffer.c.generated.h"
-#endif
-
-/// Creates a new `RBuffer` instance.
-RBuffer *rbuffer_new(size_t capacity)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
-{
- if (!capacity) {
- capacity = 0x10000;
- }
-
- RBuffer *rv = xcalloc(1, sizeof(RBuffer) + capacity);
- rv->full_cb = rv->nonfull_cb = NULL;
- rv->data = NULL;
- rv->size = 0;
- rv->write_ptr = rv->read_ptr = rv->start_ptr;
- rv->end_ptr = rv->start_ptr + capacity;
- rv->temp = NULL;
- return rv;
-}
-
-/// Creates a new `RBuffer` instance for reading from a buffer.
-///
-/// Must not be used with any write function like rbuffer_write_ptr or rbuffer_produced!
-RBuffer *rbuffer_new_wrap_buf(char *data, size_t len)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
-{
- RBuffer *rv = xcalloc(1, sizeof(RBuffer));
- rv->full_cb = rv->nonfull_cb = NULL;
- rv->data = NULL;
- rv->size = len;
- rv->read_ptr = data;
- rv->write_ptr = data + len;
- rv->end_ptr = NULL;
- rv->temp = NULL;
- return rv;
-}
-
-void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL
-{
- xfree(buf->temp);
- xfree(buf);
-}
-
-/// Return a pointer to a raw buffer containing the first empty slot available
-/// for writing. The second argument is a pointer to the maximum number of
-/// bytes that could be written.
-///
-/// It is necessary to call this function twice to ensure all empty space was
-/// used. See RBUFFER_UNTIL_FULL for a macro that simplifies this task.
-char *rbuffer_write_ptr(RBuffer *buf, size_t *write_count) FUNC_ATTR_NONNULL_ALL
-{
- if (buf->size == rbuffer_capacity(buf)) {
- *write_count = 0;
- return NULL;
- }
-
- if (buf->write_ptr >= buf->read_ptr) {
- *write_count = (size_t)(buf->end_ptr - buf->write_ptr);
- } else {
- *write_count = (size_t)(buf->read_ptr - buf->write_ptr);
- }
-
- return buf->write_ptr;
-}
-
-// Reset an RBuffer so read_ptr is at the beginning of the memory. If
-// necessary, this moves existing data by allocating temporary memory.
-void rbuffer_reset(RBuffer *buf) FUNC_ATTR_NONNULL_ALL
-{
- size_t temp_size;
- if ((temp_size = rbuffer_size(buf))) {
- if (buf->temp == NULL) {
- buf->temp = xcalloc(1, rbuffer_capacity(buf));
- }
- rbuffer_read(buf, buf->temp, buf->size);
- }
- buf->read_ptr = buf->write_ptr = buf->start_ptr;
- if (temp_size) {
- rbuffer_write(buf, buf->temp, temp_size);
- }
-}
-
-/// Adjust `rbuffer` write pointer to reflect produced data. This is called
-/// automatically by `rbuffer_write`, but when using `rbuffer_write_ptr`
-/// directly, this needs to called after the data was copied to the internal
-/// buffer. The write pointer will be wrapped if required.
-void rbuffer_produced(RBuffer *buf, size_t count) FUNC_ATTR_NONNULL_ALL
-{
- assert(count && count <= rbuffer_space(buf));
-
- buf->write_ptr += count;
- if (buf->write_ptr >= buf->end_ptr) {
- // wrap around
- buf->write_ptr -= rbuffer_capacity(buf);
- }
-
- buf->size += count;
- if (buf->full_cb && !rbuffer_space(buf)) {
- buf->full_cb(buf, buf->data);
- }
-}
-
-/// Return a pointer to a raw buffer containing the first byte available
-/// for reading. The second argument is a pointer to the maximum number of
-/// bytes that could be read.
-///
-/// It is necessary to call this function twice to ensure all available bytes
-/// were read. See RBUFFER_UNTIL_EMPTY for a macro that simplifies this task.
-char *rbuffer_read_ptr(RBuffer *buf, size_t *read_count) FUNC_ATTR_NONNULL_ALL
-{
- if (!buf->size) {
- *read_count = 0;
- return buf->read_ptr;
- }
-
- if (buf->read_ptr < buf->write_ptr) {
- *read_count = (size_t)(buf->write_ptr - buf->read_ptr);
- } else {
- *read_count = (size_t)(buf->end_ptr - buf->read_ptr);
- }
-
- return buf->read_ptr;
-}
-
-/// Adjust `rbuffer` read pointer to reflect consumed data. This is called
-/// automatically by `rbuffer_read`, but when using `rbuffer_read_ptr`
-/// directly, this needs to called after the data was copied from the internal
-/// buffer. The read pointer will be wrapped if required.
-void rbuffer_consumed(RBuffer *buf, size_t count)
- FUNC_ATTR_NONNULL_ALL
-{
- if (count == 0) {
- return;
- }
- assert(count <= buf->size);
-
- buf->read_ptr += count;
- if (buf->end_ptr && buf->read_ptr >= buf->end_ptr) {
- buf->read_ptr -= rbuffer_capacity(buf);
- }
-
- bool was_full = buf->size == rbuffer_capacity(buf);
- buf->size -= count;
- if (buf->nonfull_cb && was_full) {
- buf->nonfull_cb(buf, buf->data);
- }
-}
-
-/// Use instead of rbuffer_consumed to use rbuffer in a linear, non-cyclic fashion.
-///
-/// This is generally useful if we can guarantee to parse all input
-/// except some small incomplete token, like when parsing msgpack.
-void rbuffer_consumed_compact(RBuffer *buf, size_t count)
- FUNC_ATTR_NONNULL_ALL
-{
- assert(buf->read_ptr <= buf->write_ptr);
- rbuffer_consumed(buf, count);
- if (buf->read_ptr > buf->start_ptr) {
- assert((size_t)(buf->write_ptr - buf->read_ptr) == buf->size
- || buf->write_ptr == buf->start_ptr);
- memmove(buf->start_ptr, buf->read_ptr, buf->size);
- buf->read_ptr = buf->start_ptr;
- buf->write_ptr = buf->read_ptr + buf->size;
- }
-}
-
-// Higher level functions for copying from/to RBuffer instances and data
-// pointers
-size_t rbuffer_write(RBuffer *buf, const char *src, size_t src_size)
- FUNC_ATTR_NONNULL_ALL
-{
- size_t size = src_size;
-
- RBUFFER_UNTIL_FULL(buf, wptr, wcnt) {
- size_t copy_count = MIN(src_size, wcnt);
- memcpy(wptr, src, copy_count);
- rbuffer_produced(buf, copy_count);
-
- if (!(src_size -= copy_count)) {
- return size;
- }
-
- src += copy_count;
- }
-
- return size - src_size;
-}
-
-size_t rbuffer_read(RBuffer *buf, char *dst, size_t dst_size)
- FUNC_ATTR_NONNULL_ALL
-{
- size_t size = dst_size;
-
- RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) {
- size_t copy_count = MIN(dst_size, rcnt);
- memcpy(dst, rptr, copy_count);
- rbuffer_consumed(buf, copy_count);
-
- if (!(dst_size -= copy_count)) {
- return size;
- }
-
- dst += copy_count;
- }
-
- return size - dst_size;
-}
-
-char *rbuffer_get(RBuffer *buf, size_t index)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
-{
- assert(index < buf->size);
- char *rptr = buf->read_ptr + index;
- if (rptr >= buf->end_ptr) {
- rptr -= rbuffer_capacity(buf);
- }
- return rptr;
-}
-
-int rbuffer_cmp(RBuffer *buf, const char *str, size_t count)
- FUNC_ATTR_NONNULL_ALL
-{
- assert(count <= buf->size);
- size_t rcnt;
- rbuffer_read_ptr(buf, &rcnt);
- size_t n = MIN(count, rcnt);
- int rv = memcmp(str, buf->read_ptr, n);
- count -= n;
- size_t remaining = buf->size - rcnt;
-
- if (rv || !count || !remaining) {
- return rv;
- }
-
- return memcmp(str + n, buf->start_ptr, count);
-}
diff --git a/src/nvim/rbuffer.h b/src/nvim/rbuffer.h
deleted file mode 100644
index 942e1f2365..0000000000
--- a/src/nvim/rbuffer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Specialized ring buffer. This is basically an array that wraps read/write
-// pointers around the memory region. It should be more efficient than the old
-// RBuffer which required memmove() calls to relocate read/write positions.
-//
-// The main purpose of RBuffer is simplify memory management when reading from
-// uv_stream_t instances:
-//
-// - The event loop writes data to a RBuffer, advancing the write pointer
-// - The main loop reads data, advancing the read pointer
-// - If the buffer becomes full(size == capacity) the rstream is temporarily
-// stopped(automatic backpressure handling)
-//
-// Reference: http://en.wikipedia.org/wiki/Circular_buffer
-#pragma once
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "nvim/rbuffer_defs.h" // IWYU pragma: keep
-
-// Macros that simplify working with the read/write pointers directly by hiding
-// ring buffer wrap logic. Some examples:
-//
-// - Pass the write pointer to a function(write_data) that incrementally
-// produces data, returning the number of bytes actually written to the
-// ring buffer:
-//
-// RBUFFER_UNTIL_FULL(rbuf, ptr, cnt)
-// rbuffer_produced(rbuf, write_data(state, ptr, cnt));
-//
-// - Pass the read pointer to a function(read_data) that incrementally
-// consumes data, returning the number of bytes actually read from the
-// ring buffer:
-//
-// RBUFFER_UNTIL_EMPTY(rbuf, ptr, cnt)
-// rbuffer_consumed(rbuf, read_data(state, ptr, cnt));
-//
-// Note that the rbuffer_{produced,consumed} calls are necessary or these macros
-// create infinite loops
-#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \
- for (size_t rcnt = 0, _r = 1; _r; _r = 0) \
- for (char *rptr = rbuffer_read_ptr(buf, &rcnt); \
- buf->size; \
- rptr = rbuffer_read_ptr(buf, &rcnt))
-
-#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \
- for (size_t wcnt = 0, _r = 1; _r; _r = 0) \
- for (char *wptr = rbuffer_write_ptr(buf, &wcnt); \
- rbuffer_space(buf); \
- wptr = rbuffer_write_ptr(buf, &wcnt))
-
-// Iteration
-#define RBUFFER_EACH(buf, c, i) \
- for (size_t i = 0; \
- i < buf->size; \
- i = buf->size) \
- for (char c = 0; \
- i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
- i++)
-
-#define RBUFFER_EACH_REVERSE(buf, c, i) \
- for (size_t i = buf->size; \
- i != SIZE_MAX; \
- i = SIZE_MAX) \
- for (char c = 0; \
- i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
- )
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "rbuffer.h.generated.h"
-#endif
diff --git a/src/nvim/rbuffer_defs.h b/src/nvim/rbuffer_defs.h
deleted file mode 100644
index 51dc349846..0000000000
--- a/src/nvim/rbuffer_defs.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-#include <stddef.h>
-
-#include "nvim/func_attr.h"
-
-typedef struct rbuffer RBuffer;
-/// Type of function invoked during certain events:
-/// - When the RBuffer switches to the full state
-/// - When the RBuffer switches to the non-full state
-typedef void (*rbuffer_callback)(RBuffer *buf, void *data);
-
-struct rbuffer {
- rbuffer_callback full_cb, nonfull_cb;
- void *data;
- size_t size;
- // helper memory used to by rbuffer_reset if required
- char *temp;
- char *end_ptr, *read_ptr, *write_ptr;
- char start_ptr[];
-};
-
-static inline size_t rbuffer_size(RBuffer *buf)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
-
-static inline size_t rbuffer_size(RBuffer *buf)
-{
- return buf->size;
-}
-
-static inline size_t rbuffer_capacity(RBuffer *buf)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
-
-static inline size_t rbuffer_capacity(RBuffer *buf)
-{
- return (size_t)(buf->end_ptr - buf->start_ptr);
-}
-
-static inline size_t rbuffer_space(RBuffer *buf)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
-
-static inline size_t rbuffer_space(RBuffer *buf)
-{
- return rbuffer_capacity(buf) - buf->size;
-}
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 5600d6a2f8..e00dbdfc78 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -18,6 +18,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
@@ -11450,7 +11451,7 @@ static void nfa_set_code(int c)
}
if (addnl == true) {
- STRCAT(code, " + NEWLINE ");
+ strcat(code, " + NEWLINE ");
}
}
@@ -11494,7 +11495,7 @@ static void nfa_print_state(FILE *debugf, nfa_state_T *state)
garray_T indent;
ga_init(&indent, 1, 64);
- ga_append(&indent, '\0');
+ ga_append(&indent, NUL);
nfa_print_state2(debugf, state, &indent);
ga_clear(&indent);
}
@@ -11516,7 +11517,7 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent)
uint8_t save[2];
strncpy(save, &p[last], 2); // NOLINT(runtime/printf)
- memcpy(&p[last], "+-", 2);
+ memcpy(&p[last], S_LEN("+-"));
fprintf(debugf, " %s", p);
strncpy(&p[last], save, 2); // NOLINT(runtime/printf)
} else {
@@ -14800,7 +14801,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
}
case NFA_ANY:
- // Any char except '\0', (end of input) does not match.
+ // Any char except NUL, (end of input) does not match.
if (curc > 0) {
add_state = t->state->out;
add_off = clen;
@@ -15931,7 +15932,7 @@ regprog_T *vim_regcomp(const char *expr_arg, int re_flags)
regexp_engine = (int)p_re;
// Check for prefix "\%#=", that sets the regexp engine
- if (strncmp(expr, "\\%#=", 4) == 0) {
+ if (strncmp(expr, S_LEN("\\%#=")) == 0) {
int newengine = expr[4] - '0';
if (newengine == AUTOMATIC_ENGINE
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index d913d311db..6728262432 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -22,6 +22,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/debugger.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
@@ -408,7 +409,7 @@ int do_in_path(const char *path, const char *prefix, char *name, int flags,
did_one = true;
} else if (buflen + 2 + strlen(prefix) + strlen(name) < MAXPATHL) {
add_pathsep(buf);
- STRCAT(buf, prefix);
+ strcat(buf, prefix);
tail = buf + strlen(buf);
// Loop over all patterns in "name"
@@ -1320,16 +1321,16 @@ expand:
}
if (flags & DIP_START) {
- memcpy(tail - 15, "pack/*/start/*/", 15); // NOLINT
+ memcpy(tail - 15, S_LEN("pack/*/start/*/")); // NOLINT
globpath(p_pp, tail - 15, gap, glob_flags, expand_dirs);
- memcpy(tail - 8, "start/*/", 8); // NOLINT
+ memcpy(tail - 8, S_LEN("start/*/")); // NOLINT
globpath(p_pp, tail - 8, gap, glob_flags, expand_dirs);
}
if (flags & DIP_OPT) {
- memcpy(tail - 13, "pack/*/opt/*/", 13); // NOLINT
+ memcpy(tail - 13, S_LEN("pack/*/opt/*/")); // NOLINT
globpath(p_pp, tail - 13, gap, glob_flags, expand_dirs);
- memcpy(tail - 6, "opt/*/", 6); // NOLINT
+ memcpy(tail - 6, S_LEN("opt/*/")); // NOLINT
globpath(p_pp, tail - 6, gap, glob_flags, expand_dirs);
}
@@ -1876,7 +1877,7 @@ static bool concat_continued_line(garray_T *const ga, const int init_growsize, c
const char *const line = skipwhite_len(p, len);
len -= (size_t)(line - p);
// Skip lines starting with '\" ', concat lines starting with '\'
- if (len >= 3 && strncmp(line, "\"\\ ", 3) == 0) {
+ if (len >= 3 && strncmp(line, S_LEN("\"\\ ")) == 0) {
return true;
} else if (len == 0 || line[0] != '\\') {
return false;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 746c253708..5318970d44 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -18,6 +18,7 @@
#include "nvim/cmdhist.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
@@ -542,7 +543,7 @@ void last_pat_prog(regmmatch_T *regmatch)
return;
}
emsg_off++; // So it doesn't beep if bad expr
- search_regcomp("", 0, NULL, 0, last_idx, SEARCH_KEEP, regmatch);
+ search_regcomp(S_LEN(""), NULL, 0, last_idx, SEARCH_KEEP, regmatch);
emsg_off--;
}
@@ -1820,9 +1821,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
ptr = skipwhite(linep);
if (*ptr == '#' && pos.col <= (colnr_T)(ptr - linep)) {
ptr = skipwhite(ptr + 1);
- if (strncmp(ptr, "if", 2) == 0
- || strncmp(ptr, "endif", 5) == 0
- || strncmp(ptr, "el", 2) == 0) {
+ if (strncmp(ptr, S_LEN("if")) == 0
+ || strncmp(ptr, S_LEN("endif")) == 0
+ || strncmp(ptr, S_LEN("el")) == 0) {
hash_dir = 1;
}
} else if (linep[pos.col] == '/') { // Are we on a comment?
@@ -1893,9 +1894,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
}
if (initc != '#') {
ptr = skipwhite(skipwhite(linep) + 1);
- if (strncmp(ptr, "if", 2) == 0 || strncmp(ptr, "el", 2) == 0) {
+ if (strncmp(ptr, S_LEN("if")) == 0 || strncmp(ptr, S_LEN("el")) == 0) {
hash_dir = 1;
- } else if (strncmp(ptr, "endif", 5) == 0) {
+ } else if (strncmp(ptr, S_LEN("endif")) == 0) {
hash_dir = -1;
} else {
return NULL;
@@ -1920,29 +1921,29 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
pos.col = (colnr_T)(ptr - linep);
ptr = skipwhite(ptr + 1);
if (hash_dir > 0) {
- if (strncmp(ptr, "if", 2) == 0) {
+ if (strncmp(ptr, S_LEN("if")) == 0) {
count++;
- } else if (strncmp(ptr, "el", 2) == 0) {
+ } else if (strncmp(ptr, S_LEN("el")) == 0) {
if (count == 0) {
return &pos;
}
- } else if (strncmp(ptr, "endif", 5) == 0) {
+ } else if (strncmp(ptr, S_LEN("endif")) == 0) {
if (count == 0) {
return &pos;
}
count--;
}
} else {
- if (strncmp(ptr, "if", 2) == 0) {
+ if (strncmp(ptr, S_LEN("if")) == 0) {
if (count == 0) {
return &pos;
}
count--;
- } else if (initc == '#' && strncmp(ptr, "el", 2) == 0) {
+ } else if (initc == '#' && strncmp(ptr, S_LEN("el")) == 0) {
if (count == 0) {
return &pos;
}
- } else if (strncmp(ptr, "endif", 5) == 0) {
+ } else if (strncmp(ptr, S_LEN("endif")) == 0) {
count++;
}
}
@@ -3890,7 +3891,7 @@ search_line:
// is not considered to be a comment line.
if (skip_comments) {
if ((*line != '#'
- || strncmp(skipwhite(line + 1), "define", 6) != 0)
+ || strncmp(skipwhite(line + 1), S_LEN("define")) != 0)
&& get_leader_len(line, NULL, false, true)) {
matched = false;
}
diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c
index d49224a987..5e0aac3f69 100644
--- a/src/nvim/sha256.c
+++ b/src/nvim/sha256.c
@@ -15,6 +15,7 @@
#include <stdio.h>
#include <string.h>
+#include "nvim/ascii_defs.h"
#include "nvim/memory.h"
#include "nvim/sha256.h"
@@ -279,7 +280,7 @@ const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len, const uin
for (size_t j = 0; j < SHA256_SUM_SIZE; j++) {
snprintf(hexit + j * SHA_STEP, SHA_STEP + 1, "%02x", sha256sum[j]);
}
- hexit[sizeof(hexit) - 1] = '\0';
+ hexit[sizeof(hexit) - 1] = NUL;
return hexit;
}
@@ -340,7 +341,7 @@ bool sha256_self_test(void)
if (memcmp(output, sha_self_test_vector[i], SHA256_BUFFER_SIZE) != 0) {
failures = true;
- output[sizeof(output) - 1] = '\0';
+ output[sizeof(output) - 1] = NUL;
// printf("sha256_self_test %d failed %s\n", i, output);
}
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 597c7551fd..d5655b1754 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -19,6 +19,7 @@
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
#include "nvim/cmdhist.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/encode.h"
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 4e6672c5dd..f1ded4d594 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -21,6 +21,7 @@
#include "nvim/decoration_defs.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -125,8 +126,8 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr
| (has_hl ? MT_FLAG_DECOR_SIGNHL : 0);
DecorInline decor = { .ext = true, .data.ext = { .vt = NULL, .sh_idx = decor_put_sh(sign) } };
- extmark_set(buf, ns, id, lnum - 1, 0, -1, -1, decor, decor_flags, true,
- false, true, true, false, NULL);
+ extmark_set(buf, ns, id, MIN(buf->b_ml.ml_line_count, lnum) - 1, 0, -1, -1,
+ decor, decor_flags, true, false, true, true, NULL);
}
/// For an existing, placed sign with "id", modify the sign, group or priority.
@@ -246,12 +247,6 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum)
return FAIL;
}
- // When deleting the last sign need to redraw the windows to remove the
- // sign column. Not when curwin is NULL (this means we're exiting).
- if (!buf_meta_total(buf, kMTMetaSignText) && curwin != NULL) {
- changed_line_abv_curs();
- }
-
return OK;
}
@@ -297,8 +292,8 @@ static void sign_list_placed(buf_T *rbuf, char *group)
qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_row_cmp);
for (size_t i = 0; i < kv_size(signs); i++) {
- namebuf[0] = '\0';
- groupbuf[0] = '\0';
+ namebuf[0] = NUL;
+ groupbuf[0] = NUL;
MTKey mark = kv_A(signs, i);
DecorSignHighlight *sh = decor_find_sign(mt_decor(mark));
@@ -499,22 +494,11 @@ static void sign_list_by_name(char *name)
}
}
-static void may_force_numberwidth_recompute(buf_T *buf, int unplace)
-{
- FOR_ALL_TAB_WINDOWS(tp, wp)
- if (wp->w_buffer == buf
- && (wp->w_p_nu || wp->w_p_rnu)
- && (unplace || wp->w_nrwidth_width < 2)
- && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
- wp->w_nrwidth_line_count = 0;
- }
-}
-
/// Place a sign at the specified file location or update a sign.
static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_T lnum, int prio)
{
// Check for reserved character '*' in group name
- if (group != NULL && (*group == '*' || *group == '\0')) {
+ if (group != NULL && (*group == '*' || *group == NUL)) {
return FAIL;
}
@@ -531,11 +515,7 @@ static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_
// ":sign place {id} file={fname}": change sign type and/or priority
lnum = buf_mod_sign(buf, id, group, prio, sp);
}
- if (lnum > 0) {
- // When displaying signs in the 'number' column, if the width of the
- // number column is less than 2, then force recomputing the width.
- may_force_numberwidth_recompute(buf, false);
- } else {
+ if (lnum <= 0) {
semsg(_("E885: Not possible to change sign %s"), name);
return FAIL;
}
@@ -562,13 +542,6 @@ static int sign_unplace_inner(buf_T *buf, int id, char *group, linenr_T atlnum)
}
}
- // When all the signs in a buffer are removed, force recomputing the
- // number column width (if enabled) in all the windows displaying the
- // buffer if 'signcolumn' is set to 'number' in that window.
- if (!buf_meta_total(buf, kMTMetaSignText)) {
- may_force_numberwidth_recompute(buf, true);
- }
-
return OK;
}
@@ -637,17 +610,17 @@ static void sign_define_cmd(char *name, char *cmdline)
break;
}
cmdline = skiptowhite_esc(arg);
- if (strncmp(arg, "icon=", 5) == 0) {
+ if (strncmp(arg, S_LEN("icon=")) == 0) {
icon = arg + 5;
- } else if (strncmp(arg, "text=", 5) == 0) {
+ } else if (strncmp(arg, S_LEN("text=")) == 0) {
text = arg + 5;
- } else if (strncmp(arg, "linehl=", 7) == 0) {
+ } else if (strncmp(arg, S_LEN("linehl=")) == 0) {
linehl = arg + 7;
- } else if (strncmp(arg, "texthl=", 7) == 0) {
+ } else if (strncmp(arg, S_LEN("texthl=")) == 0) {
texthl = arg + 7;
- } else if (strncmp(arg, "culhl=", 6) == 0) {
+ } else if (strncmp(arg, S_LEN("culhl=")) == 0) {
culhl = arg + 6;
- } else if (strncmp(arg, "numhl=", 6) == 0) {
+ } else if (strncmp(arg, S_LEN("numhl=")) == 0) {
numhl = arg + 6;
} else {
semsg(_(e_invarg2), arg);
@@ -676,14 +649,14 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *name, int id, char *
// :sign place
// :sign place group={group}
// :sign place group=*
- if (lnum >= 0 || name != NULL || (group != NULL && *group == '\0')) {
+ if (lnum >= 0 || name != NULL || (group != NULL && *group == NUL)) {
emsg(_(e_invarg));
} else {
sign_list_placed(buf, group);
}
} else {
// Place a new sign
- if (name == NULL || buf == NULL || (group != NULL && *group == '\0')) {
+ if (name == NULL || buf == NULL || (group != NULL && *group == NUL)) {
emsg(_(e_invarg));
return;
}
@@ -695,7 +668,7 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *name, int id, char *
/// ":sign unplace" command
static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, char *group)
{
- if (lnum >= 0 || name != NULL || (group != NULL && *group == '\0')) {
+ if (lnum >= 0 || name != NULL || (group != NULL && *group == NUL)) {
emsg(_(e_invarg));
return;
}
@@ -722,7 +695,7 @@ static void sign_jump_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, c
return;
}
- if (buf == NULL || (group != NULL && *group == '\0') || lnum >= 0 || name != NULL) {
+ if (buf == NULL || (group != NULL && *group == NUL) || lnum >= 0 || name != NULL) {
// File or buffer is not specified or an empty group is used
// or a line number or a sign name is specified.
emsg(_(e_invarg));
@@ -755,19 +728,19 @@ static int parse_sign_cmd_args(int cmd, char *arg, char **name, int *id, char **
}
while (*arg != NUL) {
- if (strncmp(arg, "line=", 5) == 0) {
+ if (strncmp(arg, S_LEN("line=")) == 0) {
arg += 5;
*lnum = atoi(arg);
arg = skiptowhite(arg);
lnum_arg = true;
- } else if (strncmp(arg, "*", 1) == 0 && cmd == SIGNCMD_UNPLACE) {
+ } else if (strncmp(arg, S_LEN("*")) == 0 && cmd == SIGNCMD_UNPLACE) {
if (*id != -1) {
emsg(_(e_invarg));
return FAIL;
}
*id = -2;
arg = skiptowhite(arg + 1);
- } else if (strncmp(arg, "name=", 5) == 0) {
+ } else if (strncmp(arg, S_LEN("name=")) == 0) {
arg += 5;
char *namep = arg;
arg = skiptowhite(arg);
@@ -778,23 +751,23 @@ static int parse_sign_cmd_args(int cmd, char *arg, char **name, int *id, char **
namep++;
}
*name = namep;
- } else if (strncmp(arg, "group=", 6) == 0) {
+ } else if (strncmp(arg, S_LEN("group=")) == 0) {
arg += 6;
*group = arg;
arg = skiptowhite(arg);
if (*arg != NUL) {
*arg++ = NUL;
}
- } else if (strncmp(arg, "priority=", 9) == 0) {
+ } else if (strncmp(arg, S_LEN("priority=")) == 0) {
arg += 9;
*prio = atoi(arg);
arg = skiptowhite(arg);
- } else if (strncmp(arg, "file=", 5) == 0) {
+ } else if (strncmp(arg, S_LEN("file=")) == 0) {
arg += 5;
filename = arg;
*buf = buflist_findname_exp(arg);
break;
- } else if (strncmp(arg, "buffer=", 7) == 0) {
+ } else if (strncmp(arg, S_LEN("buffer=")) == 0) {
arg += 7;
filename = arg;
*buf = buflist_findnr(getdigits_int(&arg, true, 0));
@@ -1172,23 +1145,23 @@ void set_context_in_sign_cmd(expand_T *xp, char *arg)
xp->xp_pattern = p + 1;
switch (cmd_idx) {
case SIGNCMD_DEFINE:
- if (strncmp(last, "texthl", 6) == 0
- || strncmp(last, "linehl", 6) == 0
- || strncmp(last, "culhl", 5) == 0
- || strncmp(last, "numhl", 5) == 0) {
+ if (strncmp(last, S_LEN("texthl")) == 0
+ || strncmp(last, S_LEN("linehl")) == 0
+ || strncmp(last, S_LEN("culhl")) == 0
+ || strncmp(last, S_LEN("numhl")) == 0) {
xp->xp_context = EXPAND_HIGHLIGHT;
- } else if (strncmp(last, "icon", 4) == 0) {
+ } else if (strncmp(last, S_LEN("icon")) == 0) {
xp->xp_context = EXPAND_FILES;
} else {
xp->xp_context = EXPAND_NOTHING;
}
break;
case SIGNCMD_PLACE:
- if (strncmp(last, "name", 4) == 0) {
+ if (strncmp(last, S_LEN("name")) == 0) {
expand_what = EXP_SIGN_NAMES;
- } else if (strncmp(last, "group", 5) == 0) {
+ } else if (strncmp(last, S_LEN("group")) == 0) {
expand_what = EXP_SIGN_GROUPS;
- } else if (strncmp(last, "file", 4) == 0) {
+ } else if (strncmp(last, S_LEN("file")) == 0) {
xp->xp_context = EXPAND_BUFFERS;
} else {
xp->xp_context = EXPAND_NOTHING;
@@ -1196,9 +1169,9 @@ void set_context_in_sign_cmd(expand_T *xp, char *arg)
break;
case SIGNCMD_UNPLACE:
case SIGNCMD_JUMP:
- if (strncmp(last, "group", 5) == 0) {
+ if (strncmp(last, S_LEN("group")) == 0) {
expand_what = EXP_SIGN_GROUPS;
- } else if (strncmp(last, "file", 4) == 0) {
+ } else if (strncmp(last, S_LEN("file")) == 0) {
xp->xp_context = EXPAND_BUFFERS;
} else {
xp->xp_context = EXPAND_NOTHING;
@@ -1343,7 +1316,7 @@ void f_sign_getplaced(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (group == NULL) {
return;
}
- if (*group == '\0') { // empty string means global group
+ if (*group == NUL) { // empty string means global group
group = NULL;
}
}
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index d7a6adef58..8ec28c7f61 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -72,6 +72,7 @@
#include "nvim/decoration.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
@@ -230,14 +231,6 @@ char *repl_to = NULL;
/// caller can skip over the word.
size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount)
{
- matchinf_T mi; // Most things are put in "mi" so that it can
- // be passed to functions quickly.
- size_t nrlen = 0; // found a number first
- size_t wrongcaplen = 0;
- bool count_word = docount;
- bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0;
- bool is_camel_case = false;
-
// A word never starts at a space or a control character. Return quickly
// then, skipping over the character.
if ((uint8_t)(*ptr) <= ' ') {
@@ -249,6 +242,13 @@ size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount
return 1;
}
+ size_t nrlen = 0; // found a number first
+ size_t wrongcaplen = 0;
+ bool count_word = docount;
+ bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0;
+ bool is_camel_case = false;
+
+ matchinf_T mi; // Most things are put in "mi" so that it can be passed to functions quickly.
CLEAR_FIELD(mi);
// A number is always OK. Also skip hexadecimal numbers 0xFF99 and
@@ -540,7 +540,6 @@ static void find_word(matchinf_T *mip, int mode)
int endlen[MAXWLEN]; // length at possible word endings
idx_T endidx[MAXWLEN]; // possible word endings
int endidxcnt = 0;
- int c;
// Repeat advancing in the tree until:
// - there is a byte that doesn't match,
@@ -582,7 +581,7 @@ static void find_word(matchinf_T *mip, int mode)
}
// Perform a binary search in the list of accepted bytes.
- c = (uint8_t)ptr[wlen];
+ int c = (uint8_t)ptr[wlen];
if (c == TAB) { // <Tab> is handled like <Space>
c = ' ';
}
@@ -626,9 +625,6 @@ static void find_word(matchinf_T *mip, int mode)
}
}
- char *p;
- bool word_ends;
-
// Verify that one of the possible endings is valid. Try the longest
// first.
while (endidxcnt > 0) {
@@ -639,6 +635,7 @@ static void find_word(matchinf_T *mip, int mode)
if (utf_head_off(ptr, ptr + wlen) > 0) {
continue; // not at first byte of character
}
+ bool word_ends;
if (spell_iswordp(ptr + wlen, mip->mi_win)) {
if (slang->sl_compprog == NULL && !slang->sl_nobreak) {
continue; // next char is a word character
@@ -655,7 +652,7 @@ static void find_word(matchinf_T *mip, int mode)
// Compute byte length in original word, length may change
// when folding case. This can be slow, take a shortcut when the
// case-folded word is equal to the keep-case word.
- p = mip->mi_word;
+ char *p = mip->mi_word;
if (strncmp(ptr, p, (size_t)wlen) != 0) {
for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) {
MB_PTR_ADV(p);
@@ -691,10 +688,10 @@ static void find_word(matchinf_T *mip, int mode)
// When mode is FIND_PREFIX the word must support the prefix:
// check the prefix ID and the condition. Do that for the list at
// mip->mi_prefarridx that find_prefix() filled.
- c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
- (int)flags,
- mip->mi_word + mip->mi_cprefixlen, slang,
- false);
+ int c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
+ (int)flags,
+ mip->mi_word + mip->mi_cprefixlen, slang,
+ false);
if (c == 0) {
continue;
}
@@ -765,6 +762,7 @@ static void find_word(matchinf_T *mip, int mode)
if (mode == FIND_COMPOUND) {
int capflags;
+ char *p;
// Need to check the caps type of the appended compound
// word.
@@ -851,7 +849,7 @@ static void find_word(matchinf_T *mip, int mode)
// byte length in keep-case word. Length may change when
// folding case. This can be slow, take a shortcut when
// the case-folded word is equal to the keep-case word.
- p = mip->mi_fword;
+ char *p = mip->mi_fword;
if (strncmp(ptr, p, (size_t)wlen) != 0) {
for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) {
MB_PTR_ADV(p);
@@ -1296,12 +1294,14 @@ static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col)
/// @return 0 if not found, length of the badly spelled word otherwise.
size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *attrp)
{
+ if (no_spell_checking(wp)) {
+ return 0;
+ }
+
pos_T found_pos;
size_t found_len = 0;
hlf_T attr = HLF_COUNT;
- size_t len;
bool has_syntax = syntax_present(wp);
- colnr_T col;
char *buf = NULL;
size_t buflen = 0;
int skip = 0;
@@ -1309,10 +1309,6 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a
bool found_one = false;
bool wrapped = false;
- if (no_spell_checking(wp)) {
- return 0;
- }
-
size_t ret = 0;
// Start looking for bad word at the start of the line, because we can't
@@ -1342,7 +1338,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a
while (!got_int) {
char *line = ml_get_buf(wp->w_buffer, lnum);
- len = (size_t)ml_get_buf_len(wp->w_buffer, lnum);
+ size_t len = (size_t)ml_get_buf_len(wp->w_buffer, lnum);
if (buflen < len + MAXWLEN + 2) {
xfree(buf);
buflen = len + MAXWLEN + 2;
@@ -1360,7 +1356,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a
capcol = (colnr_T)getwhitecols(line);
} else if (curline && wp == curwin) {
// For spellbadword(): check if first word needs a capital.
- col = (colnr_T)getwhitecols(line);
+ colnr_T col = (colnr_T)getwhitecols(line);
if (check_need_cap(curwin, lnum, col)) {
capcol = col;
}
@@ -1409,7 +1405,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a
|| ((colnr_T)(curline
? p - buf + (ptrdiff_t)len
: p - buf) > wp->w_cursor.col)) {
- col = (colnr_T)(p - buf);
+ colnr_T col = (colnr_T)(p - buf);
bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0;
bool can_spell = !no_plain_buffer;
@@ -1816,17 +1812,16 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count)
p = buf;
}
- wordcount_T *wc;
hash_T hash = hash_hash(p);
const size_t p_len = strlen(p);
hashitem_T *hi = hash_lookup(&lp->sl_wordcount, p, p_len, hash);
if (HASHITEM_EMPTY(hi)) {
- wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1);
+ wordcount_T *wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1);
memcpy(wc->wc_word, p, p_len + 1);
wc->wc_count = count;
hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash);
} else {
- wc = HI2WC(hi);
+ wordcount_T *wc = HI2WC(hi);
wc->wc_count = (uint16_t)(wc->wc_count + count);
if (wc->wc_count < count) { // check for overflow
wc->wc_count = MAXWORDCOUNT;
@@ -1882,14 +1877,14 @@ int init_syl_tab(slang_T *slang)
static int count_syllables(slang_T *slang, const char *word)
FUNC_ATTR_NONNULL_ALL
{
- int cnt = 0;
- bool skip = false;
- int len;
-
if (slang->sl_syllable == NULL) {
return 0;
}
+ int cnt = 0;
+ bool skip = false;
+ int len;
+
for (const char *p = word; *p != NUL; p += len) {
// When running into a space reset counter.
if (*p == ' ') {
@@ -1929,25 +1924,14 @@ static int count_syllables(slang_T *slang, const char *word)
/// @return NULL if it's OK, an untranslated error message otherwise.
char *parse_spelllang(win_T *wp)
{
- garray_T ga;
- char *splp;
- char *region;
char region_cp[3];
- bool filename;
- int region_mask;
- slang_T *slang;
- int c;
char lang[MAXWLEN + 1];
char spf_name[MAXPATHL];
- char *p;
- int round;
- char *spf;
char *use_region = NULL;
bool dont_use_region = false;
bool nobreak = false;
static bool recursive = false;
char *ret_msg = NULL;
- char *spl_copy;
bufref_T bufref;
set_bufref(&bufref, wp->w_buffer);
@@ -1960,20 +1944,21 @@ char *parse_spelllang(win_T *wp)
}
recursive = true;
+ garray_T ga;
ga_init(&ga, sizeof(langp_T), 2);
clear_midword(wp);
// Make a copy of 'spelllang', the SpellFileMissing autocommands may change
// it under our fingers.
- spl_copy = xstrdup(wp->w_s->b_p_spl);
+ char *spl_copy = xstrdup(wp->w_s->b_p_spl);
wp->w_s->b_cjk = 0;
// Loop over comma separated language names.
- for (splp = spl_copy; *splp != NUL;) {
+ for (char *splp = spl_copy; *splp != NUL;) {
// Get one language name.
copy_option_part(&splp, lang, MAXWLEN, ",");
- region = NULL;
+ char *region = NULL;
int len = (int)strlen(lang);
if (!valid_spelllang(lang)) {
@@ -1985,6 +1970,8 @@ char *parse_spelllang(win_T *wp)
continue;
}
+ slang_T *slang;
+ bool filename;
// If the name ends in ".spl" use it as the name of the spell file.
// If there is a region name let "region" point to it and remove it
// from the name.
@@ -1992,7 +1979,7 @@ char *parse_spelllang(win_T *wp)
filename = true;
// Locate a region and remove it from the file name.
- p = vim_strchr(path_tail(lang), '_');
+ char *p = vim_strchr(path_tail(lang), '_');
if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2])
&& !ASCII_ISALPHA(p[3])) {
xstrlcpy(region_cp, p + 1, 3);
@@ -2055,10 +2042,10 @@ char *parse_spelllang(win_T *wp)
if (filename
? path_full_compare(lang, slang->sl_fname, false, true) == kEqualFiles
: STRICMP(lang, slang->sl_name) == 0) {
- region_mask = REGION_ALL;
+ int region_mask = REGION_ALL;
if (!filename && region != NULL) {
// find region in sl_regions
- c = find_region(slang->sl_regions, region);
+ int c = find_region(slang->sl_regions, region);
if (c == REGION_ALL) {
if (slang->sl_add) {
if (*slang->sl_regions != NUL) {
@@ -2094,8 +2081,8 @@ char *parse_spelllang(win_T *wp)
// round 1: load first name in 'spellfile'.
// round 2: load second name in 'spellfile.
// etc.
- spf = curwin->w_s->b_p_spf;
- for (round = 0; round == 0 || *spf != NUL; round++) {
+ char *spf = curwin->w_s->b_p_spf;
+ for (int round = 0; round == 0 || *spf != NUL; round++) {
if (round == 0) {
// Internal wordlist, if there is one.
if (int_wordlist == NULL) {
@@ -2105,11 +2092,12 @@ char *parse_spelllang(win_T *wp)
} else {
// One entry in 'spellfile'.
copy_option_part(&spf, spf_name, MAXPATHL - 5, ",");
- STRCAT(spf_name, ".spl");
+ strcat(spf_name, ".spl");
+ int c;
// If it was already found above then skip it.
for (c = 0; c < ga.ga_len; c++) {
- p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname;
+ char *p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname;
if (p != NULL
&& path_full_compare(spf_name, p, false, true) == kEqualFiles) {
break;
@@ -2120,6 +2108,8 @@ char *parse_spelllang(win_T *wp)
}
}
+ slang_T *slang;
+
// Check if it was loaded already.
for (slang = first_lang; slang != NULL; slang = slang->sl_next) {
if (path_full_compare(spf_name, slang->sl_fname, false, true)
@@ -2135,7 +2125,7 @@ char *parse_spelllang(win_T *wp)
STRCPY(lang, "internal wordlist");
} else {
xstrlcpy(lang, path_tail(spf_name), MAXWLEN + 1);
- p = vim_strchr(lang, '.');
+ char *p = vim_strchr(lang, '.');
if (p != NULL) {
*p = NUL; // truncate at ".encoding.add"
}
@@ -2149,10 +2139,10 @@ char *parse_spelllang(win_T *wp)
}
}
if (slang != NULL) {
- region_mask = REGION_ALL;
+ int region_mask = REGION_ALL;
if (use_region != NULL && !dont_use_region) {
// find region in sl_regions
- c = find_region(slang->sl_regions, use_region);
+ int c = find_region(slang->sl_regions, use_region);
if (c != REGION_ALL) {
region_mask = 1 << c;
} else if (*slang->sl_regions != NUL) {
@@ -2687,7 +2677,7 @@ void ex_spellrepall(exarg_T *eap)
char *p = xmalloc((size_t)get_cursor_line_len() + (size_t)addlen + 1);
memmove(p, line, (size_t)curwin->w_cursor.col);
STRCPY(p + curwin->w_cursor.col, repl_to);
- STRCAT(p, line + curwin->w_cursor.col + repl_from_len);
+ strcat(p, line + curwin->w_cursor.col + repl_from_len);
ml_replace(curwin->w_cursor.lnum, p, false);
inserted_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col,
(int)repl_from_len, (int)repl_to_len);
@@ -2902,19 +2892,7 @@ static void spell_soundfold_sofo(slang_T *slang, const char *inword, char *res)
// Multi-byte version of spell_soundfold().
static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
{
- salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
int word[MAXWLEN] = { 0 };
- int wres[MAXWLEN] = { 0 };
- int *ws;
- int *pf;
- int j, z;
- int reslen;
- int k = 0;
- int k0;
- int n0;
- int pri;
- int p0 = -333;
- int c0;
bool did_white = false;
// Convert the multi-byte string to a wide-character string.
@@ -2942,17 +2920,24 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
}
word[wordlen] = NUL;
+ salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
+ int wres[MAXWLEN] = { 0 };
+ int k = 0;
+ int p0 = -333;
int c;
// This algorithm comes from Aspell phonet.cpp.
// Converted from C++ to C. Added support for multi-byte chars.
// Changed to keep spaces.
- int i = reslen = z = 0;
+ int i = 0;
+ int reslen = 0;
+ int z = 0;
while ((c = word[i]) != NUL) {
// Start with the first rule that has the character in the word.
int n = slang->sl_sal_first[c & 0xff];
int z0 = 0;
if (n >= 0) {
+ int *ws;
// Check all rules for the same index byte.
// If c is 0x300 need extra check for the end of the array, as
// (c & 0xff) is NUL.
@@ -2969,6 +2954,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
continue;
}
if (k > 2) {
+ int j;
for (j = 2; j < k; j++) {
if (word[i + j] != ws[j]) {
break;
@@ -2980,6 +2966,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
}
}
+ int *pf;
if ((pf = smp[n].sm_oneof_w) != NULL) {
// Check for match with one of the chars in "sm_oneof".
while (*pf != NUL && *pf != word[i + k]) {
@@ -2991,10 +2978,10 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
k++;
}
char *s = smp[n].sm_rules;
- pri = 5; // default priority
+ int pri = 5; // default priority
p0 = (uint8_t)(*s);
- k0 = k;
+ int k0 = k;
while (*s == '-' && k > 1) {
k--;
s++;
@@ -3022,8 +3009,8 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
&& (!spell_iswordp_w(word + i + k0, curwin)))) {
// search for followup rules, if:
// followup and k > 1 and NO '-' in searchstring
- c0 = word[i + k - 1];
- n0 = slang->sl_sal_first[c0 & 0xff];
+ int c0 = word[i + k - 1];
+ int n0 = slang->sl_sal_first[c0 & 0xff];
if (slang->sl_followup && k > 1 && n0 >= 0
&& p0 != '-' && word[i + k] != NUL) {
@@ -3042,6 +3029,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
}
if (k0 > 2) {
pf = word + i + k + 1;
+ int j;
for (j = 2; j < k0; j++) {
if (*pf++ != ws[j]) {
break;
@@ -3262,23 +3250,13 @@ void ex_spelldump(exarg_T *eap)
/// @param dumpflags_arg DUMPFLAG_*
void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
{
- langp_T *lp;
- slang_T *slang;
idx_T arridx[MAXWLEN];
int curi[MAXWLEN];
char word[MAXWLEN];
- int c;
- uint8_t *byts;
- idx_T *idxs;
linenr_T lnum = 0;
- int depth;
- int n;
- int flags;
char *region_names = NULL; // region names being used
bool do_region = true; // dump region names and numbers
- char *p;
int dumpflags = dumpflags_arg;
- int patlen;
// When ignoring case or when the pattern starts with capital pass this on
// to dump_word().
@@ -3286,7 +3264,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
if (ic) {
dumpflags |= DUMPFLAG_ICASE;
} else {
- n = captype(pat, NULL);
+ int n = captype(pat, NULL);
if (n == WF_ONECAP) {
dumpflags |= DUMPFLAG_ONECAP;
} else if (n == WF_ALLCAP
@@ -3299,8 +3277,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
// Find out if we can support regions: All languages must support the same
// regions or none at all.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) {
- lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
- p = lp->lp_slang->sl_regions;
+ langp_T *lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ char *p = lp->lp_slang->sl_regions;
if (p[0] != 0) {
if (region_names == NULL) { // first language with regions
region_names = p;
@@ -3320,8 +3298,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
// Loop over all files loaded for the entries in 'spelllang'.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) {
- lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
- slang = lp->lp_slang;
+ langp_T *lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ slang_T *slang = lp->lp_slang;
if (slang->sl_fbyts == NULL) { // reloading failed
continue;
}
@@ -3331,6 +3309,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
ml_append(lnum++, IObuff, 0, false);
}
+ int patlen;
// When matching with a pattern and there are no prefixes only use
// parts of the tree that match "pat".
if (pat != NULL && slang->sl_pbyts == NULL) {
@@ -3342,6 +3321,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
// round 1: case-folded tree
// round 2: keep-case tree
for (int round = 1; round <= 2; round++) {
+ uint8_t *byts;
+ idx_T *idxs;
if (round == 1) {
dumpflags &= ~DUMPFLAG_KEEPCASE;
byts = slang->sl_fbyts;
@@ -3354,7 +3335,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
if (byts == NULL) {
continue; // array is empty
}
- depth = 0;
+ int depth = 0;
arridx[0] = 0;
curi[0] = 1;
while (depth >= 0 && !got_int
@@ -3366,16 +3347,16 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
ins_compl_check_keys(50, false);
} else {
// Do one more byte at this node.
- n = arridx[depth] + curi[depth];
+ int n = arridx[depth] + curi[depth];
curi[depth]++;
- c = byts[n];
+ int c = byts[n];
if (c == 0 || depth >= MAXWLEN - 1) {
// End of word or reached maximum length, deal with the
// word.
// Don't use keep-case words in the fold-case tree,
// they will appear in the keep-case tree.
// Only use the word when the region matches.
- flags = (int)idxs[n];
+ int flags = (int)idxs[n];
if ((round == 2 || (flags & WF_KEEPCAP) == 0)
&& (flags & WF_NEEDCOMP) == 0
&& (do_region
@@ -3463,14 +3444,14 @@ static void dump_word(slang_T *slang, char *word, char *pat, Direction *dir, int
// Add flags and regions after a slash.
if ((flags & (WF_BANNED | WF_RARE | WF_REGION)) || keepcap) {
STRCPY(badword, p);
- STRCAT(badword, "/");
+ strcat(badword, "/");
if (keepcap) {
- STRCAT(badword, "=");
+ strcat(badword, "=");
}
if (flags & WF_BANNED) {
- STRCAT(badword, "!");
+ strcat(badword, "!");
} else if (flags & WF_RARE) {
- STRCAT(badword, "?");
+ strcat(badword, "?");
}
if (flags & WF_REGION) {
for (int i = 0; i < 7; i++) {
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 046a0a56e5..3feae980c5 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -240,6 +240,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/fileio.h"
#include "nvim/garray.h"
@@ -2139,11 +2140,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname)
+ strlen(items[1]) + 3, false);
if (spin->si_info != NULL) {
STRCPY(p, spin->si_info);
- STRCAT(p, "\n");
+ strcat(p, "\n");
}
- STRCAT(p, items[0]);
- STRCAT(p, " ");
- STRCAT(p, items[1]);
+ strcat(p, items[0]);
+ strcat(p, " ");
+ strcat(p, items[1]);
spin->si_info = p;
} else if (is_aff_rule(items, itemcnt, "MIDWORD", 2) && midword == NULL) {
midword = getroom_save(spin, items[1]);
@@ -2199,7 +2200,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname)
// "Na" into "Na+", "1234" into "1234+".
p = getroom(spin, strlen(items[1]) + 2, false);
STRCPY(p, items[1]);
- STRCAT(p, "+");
+ strcat(p, "+");
compflags = p;
} else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) {
// We don't use the count, but do check that it's a number and
@@ -2220,9 +2221,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname)
p = getroom(spin, (size_t)l, false);
if (compflags != NULL) {
STRCPY(p, compflags);
- STRCAT(p, "/");
+ strcat(p, "/");
}
- STRCAT(p, items[1]);
+ strcat(p, items[1]);
compflags = p;
}
} else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2)
@@ -2843,7 +2844,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags
char *p = getroom(spin, (size_t)len, false);
if (spin->si_compflags != NULL) {
STRCPY(p, spin->si_compflags);
- STRCAT(p, "/");
+ strcat(p, "/");
}
spin->si_compflags = p;
uint8_t *tp = (uint8_t *)p + strlen(p);
@@ -3385,7 +3386,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_
MB_PTR_ADV(p);
}
}
- STRCAT(newword, p);
+ strcat(newword, p);
} else {
// suffix: chop/add at the end of the word
xstrlcpy(newword, word, MAXWLEN);
@@ -3399,7 +3400,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_
*p = NUL;
}
if (ae->ae_add != NULL) {
- STRCAT(newword, ae->ae_add);
+ strcat(newword, ae->ae_add);
}
}
@@ -3614,7 +3615,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char *fname)
if (*line == '/') {
line++;
- if (strncmp(line, "encoding=", 9) == 0) {
+ if (strncmp(line, S_LEN("encoding=")) == 0) {
if (spin->si_conv.vc_type != CONV_NONE) {
smsg(0, _("Duplicate /encoding= line ignored in %s line %" PRIdLINENR ": %s"),
fname, lnum, line - 1);
@@ -3636,7 +3637,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char *fname)
continue;
}
- if (strncmp(line, "regions=", 8) == 0) {
+ if (strncmp(line, S_LEN("regions=")) == 0) {
if (spin->si_region_count > 1) {
smsg(0, _("Duplicate /regions= line ignored in %s line %" PRIdLINENR ": %s"),
fname, lnum, line);
@@ -4765,7 +4766,7 @@ void ex_mkspell(exarg_T *eap)
char *arg = eap->arg;
bool ascii = false;
- if (strncmp(arg, "-ascii", 6) == 0) {
+ if (strncmp(arg, S_LEN("-ascii")) == 0) {
ascii = true;
arg = skipwhite(arg + 6);
}
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index a7de20d14e..436599bb13 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -14,6 +14,7 @@
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -412,9 +413,9 @@ int spell_check_sps(void)
f = SPS_FAST;
} else if (strcmp(buf, "double") == 0) {
f = SPS_DOUBLE;
- } else if (strncmp(buf, "expr:", 5) != 0
- && strncmp(buf, "file:", 5) != 0
- && (strncmp(buf, "timeout:", 8) != 0
+ } else if (strncmp(buf, S_LEN("expr:")) != 0
+ && strncmp(buf, S_LEN("file:")) != 0
+ && (strncmp(buf, S_LEN("timeout:")) != 0
|| (!ascii_isdigit(buf[8])
&& !(buf[8] == '-' && ascii_isdigit(buf[9]))))) {
f = -1;
@@ -542,7 +543,7 @@ void spell_suggest(int count)
msg_row = Rows - 1; // for when 'cmdheight' > 1
lines_left = Rows; // avoid more prompt
char *fmt = _("Change \"%.*s\" to:");
- if (cmdmsg_rl && strncmp(fmt, "Change", 6) == 0) {
+ if (cmdmsg_rl && strncmp(fmt, S_LEN("Change")) == 0) {
// And now the rabbit from the high hat: Avoid showing the
// untranslated message rightleft.
fmt = ":ot \"%.*s\" egnahC";
@@ -642,7 +643,7 @@ void spell_suggest(int count)
int c = (int)(sug.su_badptr - line);
memmove(p, line, (size_t)c);
STRCPY(p + c, stp->st_word);
- STRCAT(p, sug.su_badptr + stp->st_orglen);
+ strcat(p, sug.su_badptr + stp->st_orglen);
// For redo we use a change-word command.
ResetRedobuff();
@@ -791,7 +792,7 @@ static void spell_find_suggest(char *badptr, int badlen, suginfo_T *su, int maxc
for (char *p = sps_copy; *p != NUL;) {
copy_option_part(&p, buf, MAXPATHL, ",");
- if (strncmp(buf, "expr:", 5) == 0) {
+ if (strncmp(buf, S_LEN("expr:")) == 0) {
// Evaluate an expression. Skip this when called recursively,
// when using spellsuggest() in the expression.
if (!expr_busy) {
@@ -799,10 +800,10 @@ static void spell_find_suggest(char *badptr, int badlen, suginfo_T *su, int maxc
spell_suggest_expr(su, buf + 5);
expr_busy = false;
}
- } else if (strncmp(buf, "file:", 5) == 0) {
+ } else if (strncmp(buf, S_LEN("file:")) == 0) {
// Use list of suggestions in a file.
spell_suggest_file(su, buf + 5);
- } else if (strncmp(buf, "timeout:", 8) == 0) {
+ } else if (strncmp(buf, S_LEN("timeout:")) == 0) {
// Limit the time searching for suggestions.
spell_suggest_timeout = atoi(buf + 8);
} else if (!did_intern) {
@@ -1637,7 +1638,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun
// Append a space to preword when splitting.
if (!try_compound && !fword_ends) {
- STRCAT(preword, " ");
+ strcat(preword, " ");
}
sp->ts_prewordlen = (uint8_t)strlen(preword);
sp->ts_splitoff = sp->ts_twordlen;
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index ca7083a9e3..bba209b434 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -1487,7 +1487,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op
new_fmt_p = (char *)memcpy(new_fmt_p, usefmt, parsed_usefmt) + parsed_usefmt;
new_fmt_p = (char *)memcpy(new_fmt_p, str, str_length) + str_length;
- new_fmt_p = (char *)memcpy(new_fmt_p, "%}", 2) + 2;
+ new_fmt_p = (char *)memcpy(new_fmt_p, S_LEN("%}")) + 2;
new_fmt_p = (char *)memcpy(new_fmt_p, fmt_p, fmt_length) + fmt_length;
*new_fmt_p = 0;
new_fmt_p = NULL;
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 8fef4ba7fd..bf7af40a38 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -12,6 +12,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -332,7 +333,7 @@ void vim_strcpy_up(char *restrict dst, const char *restrict src)
while ((c = (uint8_t)(*src++)) != NUL) {
*dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20);
}
- *dst = '\0';
+ *dst = NUL;
}
// strncpy (NUL-terminated) plus vim_strup.
@@ -343,7 +344,7 @@ void vim_strncpy_up(char *restrict dst, const char *restrict src, size_t n)
while (n-- && (c = (uint8_t)(*src++)) != NUL) {
*dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20);
}
- *dst = '\0';
+ *dst = NUL;
}
// memcpy (does not NUL-terminate) plus vim_strup.
@@ -793,10 +794,10 @@ static int format_typeof(const char *type)
FUNC_ATTR_NONNULL_ALL
{
// allowed values: \0, h, l, L
- char length_modifier = '\0';
+ char length_modifier = NUL;
// current conversion specifier character
- char fmt_spec = '\0';
+ char fmt_spec = NUL;
// parse 'h', 'l', 'll' and 'z' length modifiers
if (*type == 'h' || *type == 'l' || *type == 'z') {
@@ -864,7 +865,7 @@ static int format_typeof(const char *type)
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {
- case '\0':
+ case NUL:
case 'h':
// char and short arguments are passed as int.
return TYPE_INT;
@@ -878,7 +879,7 @@ static int format_typeof(const char *type)
} else {
// unsigned
switch (length_modifier) {
- case '\0':
+ case NUL:
case 'h':
return TYPE_UNSIGNEDINT;
case 'l':
@@ -1049,7 +1050,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *
p += n;
} else {
// allowed values: \0, h, l, L
- char length_modifier = '\0';
+ char length_modifier = NUL;
// variable for positional arg
int pos_arg = -1;
@@ -1440,7 +1441,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
int space_for_positive = 1;
// allowed values: \0, h, l, 2 (for ll), z, L
- char length_modifier = '\0';
+ char length_modifier = NUL;
// temporary buffer for simple numeric->string conversion
#define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable
@@ -1465,7 +1466,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
size_t zero_padding_insertion_ind = 0;
// current conversion specifier character
- char fmt_spec = '\0';
+ char fmt_spec = NUL;
// buffer for 's' and 'S' specs
char *tofree = NULL;
@@ -1668,7 +1669,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
case 'o':
case 'x':
case 'X':
- if (tvs && length_modifier == '\0') {
+ if (tvs && length_modifier == NUL) {
length_modifier = 'L';
}
}
@@ -1789,7 +1790,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {
- case '\0':
+ case NUL:
arg = (tvs
? (int)tv_nr(tvs, &arg_idx)
: (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
@@ -1835,7 +1836,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
} else {
// unsigned
switch (length_modifier) {
- case '\0':
+ case NUL:
uarg = (tvs
? (unsigned)tv_nr(tvs, &arg_idx)
: (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
@@ -2222,7 +2223,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
if (str_m > 0) {
// make sure the string is nul-terminated even at the expense of
// overwriting the last character (shouldn't happen, but just in case)
- str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0';
+ str[str_l <= str_m - 1 ? str_l : str_m - 1] = NUL;
}
if (tvs != NULL
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index b63d2a729d..538863326c 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -15,6 +15,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
@@ -3185,7 +3186,7 @@ static void syn_cmd_onoff(exarg_T *eap, char *name)
if (!eap->skip) {
did_syntax_onoff = true;
char buf[100];
- memcpy(buf, "so ", 4);
+ memcpy(buf, S_LEN("so ") + 1);
vim_snprintf(buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name);
do_cmdline_cmd(buf);
}
@@ -4295,7 +4296,7 @@ static void syn_cmd_region(exarg_T *eap, int syncing)
if (item == ITEM_MATCHGROUP) {
char *p = skiptowhite(rest);
- if ((p - rest == 4 && strncmp(rest, "NONE", 4) == 0) || eap->skip) {
+ if ((p - rest == 4 && strncmp(rest, S_LEN("NONE")) == 0) || eap->skip) {
matchgroup_id = 0;
} else {
matchgroup_id = syn_check_group(rest, (size_t)(p - rest));
@@ -4814,10 +4815,10 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
} else if (!eap->skip) {
curwin->w_s->b_syn_sync_id = (int16_t)syn_name2id("Comment");
}
- } else if (strncmp(key, "LINES", 5) == 0
- || strncmp(key, "MINLINES", 8) == 0
- || strncmp(key, "MAXLINES", 8) == 0
- || strncmp(key, "LINEBREAKS", 10) == 0) {
+ } else if (strncmp(key, S_LEN("LINES")) == 0
+ || strncmp(key, S_LEN("MINLINES")) == 0
+ || strncmp(key, S_LEN("MAXLINES")) == 0
+ || strncmp(key, S_LEN("LINEBREAKS")) == 0) {
if (key[4] == 'S') {
arg_end = key + 6;
} else if (key[0] == 'L') {
@@ -4991,7 +4992,7 @@ static int get_id_list(char **const arg, const int keylen, int16_t **const list,
} else {
// Handle match of regexp with group names.
*name = '^';
- STRCAT(name, "$");
+ strcat(name, "$");
regmatch.regprog = vim_regcomp(name, RE_MAGIC);
if (regmatch.regprog == NULL) {
failed = true;
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index e7f483dd3d..1d318fc3c7 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -18,6 +18,7 @@
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
@@ -878,14 +879,14 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha
}
// skip "file:" without a value (static tag)
- if (strncmp(p, "file:", 5) == 0 && ascii_isspace(p[5])) {
+ if (strncmp(p, S_LEN("file:")) == 0 && ascii_isspace(p[5])) {
p += 5;
continue;
}
// skip "kind:<kind>" and "<kind>"
if (p == tagp.tagkind
|| (p + 5 == tagp.tagkind
- && strncmp(p, "kind:", 5) == 0)) {
+ && strncmp(p, S_LEN("kind:")) == 0)) {
p = tagp.tagkind_end;
continue;
}
@@ -1059,7 +1060,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches)
// Precede the tag pattern with \V to make it very
// nomagic.
- STRCAT(cmd, "\\V");
+ strcat(cmd, "\\V");
len += 2;
int cmd_len = (int)(cmd_end - cmd_start + 1);
@@ -1613,16 +1614,16 @@ static tags_read_status_T findtags_get_next_line(findtags_state_T *st, tagsearch
static bool findtags_hdr_parse(findtags_state_T *st)
{
// Header lines in a tags file start with "!_TAG_"
- if (strncmp(st->lbuf, "!_TAG_", 6) != 0) {
+ if (strncmp(st->lbuf, S_LEN("!_TAG_")) != 0) {
// Non-header item before the header, e.g. "!" itself.
return true;
}
// Process the header line.
- if (strncmp(st->lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) {
+ if (strncmp(st->lbuf, S_LEN("!_TAG_FILE_SORTED\t")) == 0) {
st->tag_file_sorted = (uint8_t)st->lbuf[18];
}
- if (strncmp(st->lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) {
+ if (strncmp(st->lbuf, S_LEN("!_TAG_FILE_ENCODING\t")) == 0) {
// Prepare to convert every line from the specified encoding to
// 'encoding'.
char *p;
@@ -1646,7 +1647,7 @@ static bool findtags_start_state_handler(findtags_state_T *st, bool *sortic,
// The header ends when the line sorts below "!_TAG_". When case is
// folded lower case letters sort before "_".
- if (strncmp(st->lbuf, "!_TAG_", 6) <= 0
+ if (strncmp(st->lbuf, S_LEN("!_TAG_")) <= 0
|| (st->lbuf[0] == '!' && ASCII_ISLOWER(st->lbuf[1]))) {
return findtags_hdr_parse(st);
}
@@ -2669,7 +2670,7 @@ static bool test_for_static(tagptrs_T *tagp)
char *p = tagp->command;
while ((p = vim_strchr(p, '\t')) != NULL) {
p++;
- if (strncmp(p, "file:", 5) == 0) {
+ if (strncmp(p, S_LEN("file:")) == 0) {
return true;
}
}
@@ -2727,11 +2728,11 @@ static int parse_match(char *lbuf, tagptrs_T *tagp)
// Accept ASCII alphabetic kind characters and any multi-byte
// character.
while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) {
- if (strncmp(p, "kind:", 5) == 0) {
+ if (strncmp(p, S_LEN("kind:")) == 0) {
tagp->tagkind = p + 5;
- } else if (strncmp(p, "user_data:", 10) == 0) {
+ } else if (strncmp(p, S_LEN("user_data:")) == 0) {
tagp->user_data = p + 10;
- } else if (strncmp(p, "line:", 5) == 0) {
+ } else if (strncmp(p, S_LEN("line:")) == 0) {
tagp->tagline = atoi(p + 5);
}
if (tagp->tagkind != NULL && tagp->user_data != NULL) {
@@ -3173,7 +3174,7 @@ static int find_extra(char **pp)
first_char = *str;
}
- if (str != NULL && strncmp(str, ";\"", 2) == 0) {
+ if (str != NULL && strncmp(str, S_LEN(";\"")) == 0) {
*pp = str;
return OK;
}
@@ -3302,7 +3303,7 @@ int get_tags(list_T *list, char *pat, char *buf_fname)
bool is_static = test_for_static(&tp);
// Skip pseudo-tag lines.
- if (strncmp(tp.tagname, "!_TAG_", 6) == 0) {
+ if (strncmp(tp.tagname, S_LEN("!_TAG_")) == 0) {
xfree(matches[i]);
continue;
}
@@ -3327,10 +3328,10 @@ int get_tags(list_T *list, char *pat, char *buf_fname)
*p != NUL && *p != '\n' && *p != '\r';
MB_PTR_ADV(p)) {
if (p == tp.tagkind
- || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) {
+ || (p + 5 == tp.tagkind && strncmp(p, S_LEN("kind:")) == 0)) {
// skip "kind:<kind>" and "<kind>"
p = tp.tagkind_end - 1;
- } else if (strncmp(p, "file:", 5) == 0) {
+ } else if (strncmp(p, S_LEN("file:")) == 0) {
// skip "file:" (static tag)
p += 4;
} else if (!ascii_iswhite(*p)) {
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 2b05a8047e..000f750413 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -112,6 +112,9 @@ typedef struct {
// libvterm. Improves performance when receiving large bursts of data.
#define REFRESH_DELAY 10
+#define TEXTBUF_SIZE 0x1fff
+#define SELECTIONBUF_SIZE 0x0400
+
static TimeWatcher refresh_timer;
static bool refresh_pending = false;
@@ -127,7 +130,7 @@ struct terminal {
// buffer used to:
// - convert VTermScreen cell arrays into utf8 strings
// - receive data from libvterm as a result of key presses.
- char textbuf[0x1fff];
+ char textbuf[TEXTBUF_SIZE];
ScrollbackLine **sb_buffer; // Scrollback storage.
size_t sb_current; // Lines stored in sb_buffer.
@@ -166,6 +169,9 @@ struct terminal {
// When there is a pending TermRequest autocommand, block and store input.
StringBuilder *pending_send;
+ char *selection_buffer; /// libvterm selection buffer
+ StringBuilder selection; /// Growable array containing full selection data
+
size_t refcount; // reference count
};
@@ -179,6 +185,12 @@ static VTermScreenCallbacks vterm_screen_callbacks = {
.sb_popline = term_sb_pop,
};
+static VTermSelectionCallbacks vterm_selection_callbacks = {
+ .set = term_selection_set,
+ // For security reasons we don't support querying the system clipboard from the embedded terminal
+ .query = NULL,
+};
+
static Set(ptr_t) invalidated_terminals = SET_INIT;
static void emit_termrequest(void **argv)
@@ -315,6 +327,11 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
vterm_screen_set_damage_merge(term->vts, VTERM_DAMAGE_SCROLL);
vterm_screen_reset(term->vts, 1);
vterm_output_set_callback(term->vt, term_output_callback, term);
+
+ term->selection_buffer = xcalloc(SELECTIONBUF_SIZE, 1);
+ vterm_state_set_selection_callbacks(state, &vterm_selection_callbacks, term,
+ term->selection_buffer, SELECTIONBUF_SIZE);
+
// force a initial refresh of the screen to ensure the buffer will always
// have as many lines as screen rows when refresh_scrollback is called
term->invalid_start = 0;
@@ -326,14 +343,6 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
refresh_screen(term, buf);
set_option_value(kOptBuftype, STATIC_CSTR_AS_OPTVAL("terminal"), OPT_LOCAL);
- // Default settings for terminal buffers
- buf->b_p_ma = false; // 'nomodifiable'
- buf->b_p_ul = -1; // 'undolevels'
- buf->b_p_scbk = // 'scrollback' (initialize local from global)
- (p_scbk < 0) ? 10000 : MAX(1, p_scbk);
- buf->b_p_tw = 0; // 'textwidth'
- set_option_value(kOptWrap, BOOLEAN_OPTVAL(false), OPT_LOCAL);
- set_option_value(kOptList, BOOLEAN_OPTVAL(false), OPT_LOCAL);
if (buf->b_ffname != NULL) {
buf_set_term_title(buf, buf->b_ffname, strlen(buf->b_ffname));
}
@@ -769,6 +778,8 @@ void terminal_destroy(Terminal **termpp)
}
xfree(term->sb_buffer);
xfree(term->title);
+ xfree(term->selection_buffer);
+ kv_destroy(term->selection);
vterm_free(term->vt);
xfree(term);
*termpp = NULL; // coverity[dead-store]
@@ -833,9 +844,9 @@ void terminal_paste(int count, char **y_array, size_t y_size)
if (j) {
// terminate the previous line
#ifdef MSWIN
- terminal_send(curbuf->terminal, "\r\n", 2);
+ terminal_send(curbuf->terminal, S_LEN("\r\n"));
#else
- terminal_send(curbuf->terminal, "\n", 1);
+ terminal_send(curbuf->terminal, S_LEN("\n"));
#endif
}
size_t len = strlen(y_array[j]);
@@ -845,7 +856,7 @@ void terminal_paste(int count, char **y_array, size_t y_size)
}
char *dst = buff;
char *src = y_array[j];
- while (*src != '\0') {
+ while (*src != NUL) {
len = (size_t)utf_ptr2len(src);
int c = utf_ptr2char(src);
if (!is_filter_char(c)) {
@@ -1198,6 +1209,54 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
return 1;
}
+static void term_clipboard_set(void **argv)
+{
+ VTermSelectionMask mask = (VTermSelectionMask)(long)argv[0];
+ char *data = argv[1];
+
+ char regname;
+ switch (mask) {
+ case VTERM_SELECTION_CLIPBOARD:
+ regname = '+';
+ break;
+ case VTERM_SELECTION_PRIMARY:
+ regname = '*';
+ break;
+ default:
+ regname = '+';
+ break;
+ }
+
+ list_T *lines = tv_list_alloc(1);
+ tv_list_append_allocated_string(lines, data);
+
+ list_T *args = tv_list_alloc(3);
+ tv_list_append_list(args, lines);
+
+ const char regtype = 'v';
+ tv_list_append_string(args, &regtype, 1);
+
+ tv_list_append_string(args, &regname, 1);
+ eval_call_provider("clipboard", "set", args, true);
+}
+
+static int term_selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user)
+{
+ Terminal *term = user;
+ if (frag.initial) {
+ kv_size(term->selection) = 0;
+ }
+
+ kv_concat_len(term->selection, frag.str, frag.len);
+
+ if (frag.final) {
+ char *data = xmemdupz(term->selection.items, kv_size(term->selection));
+ multiqueue_put(main_loop.events, term_clipboard_set, (void *)mask, data);
+ }
+
+ return 1;
+}
+
// }}}
// input handling {{{
diff --git a/src/nvim/testing.c b/src/nvim/testing.c
index 343568d71e..8041cc2e33 100644
--- a/src/nvim/testing.c
+++ b/src/nvim/testing.c
@@ -7,6 +7,7 @@
#include <string.h>
#include "nvim/ascii_defs.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c
index 1722bcc968..01567c9e01 100644
--- a/src/nvim/textformat.c
+++ b/src/nvim/textformat.c
@@ -1017,7 +1017,7 @@ void format_lines(linenr_T line_count, bool avoid_fex)
// and this line has a line comment after some text, the
// paragraph doesn't really end.
if (next_leader_flags == NULL
- || strncmp(next_leader_flags, "://", 3) != 0
+ || strncmp(next_leader_flags, S_LEN("://")) != 0
|| check_linecomment(get_cursor_line_ptr()) == MAXCOL) {
is_end_par = true;
}
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index f1594dfcb9..a5768cfc06 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -15,7 +15,6 @@
#include "nvim/option_vars.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
-#include "nvim/rbuffer.h"
#include "nvim/strings.h"
#include "nvim/tui/input.h"
#include "nvim/tui/input_defs.h"
@@ -28,7 +27,6 @@
#include "nvim/msgpack_rpc/channel.h"
#define READ_STREAM_SIZE 0xfff
-#define KEY_BUFFER_SIZE 0xfff
/// Size of libtermkey's internal input buffer. The buffer may grow larger than
/// this when processing very long escape sequences, but will shrink back to
@@ -132,7 +130,6 @@ void tinput_init(TermInput *input, Loop *loop)
input->key_encoding = kKeyEncodingLegacy;
input->ttimeout = (bool)p_ttimeout;
input->ttimeoutlen = p_ttm;
- input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE);
for (size_t i = 0; i < ARRAY_SIZE(kitty_key_map_entry); i++) {
pmap_put(int)(&kitty_key_map, kitty_key_map_entry[i].key, (ptr_t)kitty_key_map_entry[i].name);
@@ -155,7 +152,7 @@ void tinput_init(TermInput *input, Loop *loop)
termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS);
// setup input handle
- rstream_init_fd(loop, &input->read_stream, input->in_fd, READ_STREAM_SIZE);
+ rstream_init_fd(loop, &input->read_stream, input->in_fd);
// initialize a timer handle for handling ESC with libtermkey
uv_timer_init(&loop->uv, &input->timer_handle);
@@ -165,9 +162,8 @@ void tinput_init(TermInput *input, Loop *loop)
void tinput_destroy(TermInput *input)
{
map_destroy(int, &kitty_key_map);
- rbuffer_free(input->key_buffer);
uv_close((uv_handle_t *)&input->timer_handle, NULL);
- stream_close(&input->read_stream, NULL, NULL);
+ rstream_may_close(&input->read_stream);
termkey_destroy(input->tk);
}
@@ -191,44 +187,38 @@ static void tinput_done_event(void **argv)
/// Send all pending input in key buffer to Nvim server.
static void tinput_flush(TermInput *input)
{
+ String keys = { .data = input->key_buffer, .size = input->key_buffer_len };
if (input->paste) { // produce exactly one paste event
- const size_t len = rbuffer_size(input->key_buffer);
- String keys = { .data = xmallocz(len), .size = len };
- rbuffer_read(input->key_buffer, keys.data, len);
MAXSIZE_TEMP_ARRAY(args, 3);
ADD_C(args, STRING_OBJ(keys)); // 'data'
ADD_C(args, BOOLEAN_OBJ(true)); // 'crlf'
ADD_C(args, INTEGER_OBJ(input->paste)); // 'phase'
rpc_send_event(ui_client_channel_id, "nvim_paste", args);
- api_free_string(keys);
if (input->paste == 1) {
// Paste phase: "continue"
input->paste = 2;
}
- rbuffer_reset(input->key_buffer);
} else { // enqueue input
- RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
- const String keys = { .data = buf, .size = len };
+ if (input->key_buffer_len > 0) {
MAXSIZE_TEMP_ARRAY(args, 1);
ADD_C(args, STRING_OBJ(keys));
// NOTE: This is non-blocking and won't check partially processed input,
// but should be fine as all big sends are handled with nvim_paste, not nvim_input
rpc_send_event(ui_client_channel_id, "nvim_input", args);
- rbuffer_consumed(input->key_buffer, len);
- rbuffer_reset(input->key_buffer);
}
}
+ input->key_buffer_len = 0;
}
-static void tinput_enqueue(TermInput *input, char *buf, size_t size)
+static void tinput_enqueue(TermInput *input, const char *buf, size_t size)
{
- if (rbuffer_size(input->key_buffer) >
- rbuffer_capacity(input->key_buffer) - 0xff) {
- // don't ever let the buffer get too full or we risk putting incomplete keys
- // into it
+ if (input->key_buffer_len > KEY_BUFFER_SIZE - size) {
+ // don't ever let the buffer get too full or we risk putting incomplete keys into it
tinput_flush(input);
}
- rbuffer_write(input->key_buffer, buf, size);
+ size_t to_copy = MIN(size, KEY_BUFFER_SIZE - input->key_buffer_len);
+ memcpy(input->key_buffer + input->key_buffer_len, buf, to_copy);
+ input->key_buffer_len += to_copy;
}
/// Handle TERMKEY_KEYMOD_* modifiers, i.e. Shift, Alt and Ctrl.
@@ -472,8 +462,10 @@ static void tinput_timer_cb(uv_timer_t *handle)
TermInput *input = handle->data;
// If the raw buffer is not empty, process the raw buffer first because it is
// processing an incomplete bracketed paster sequence.
- if (rbuffer_size(input->read_stream.buffer)) {
- handle_raw_buffer(input, true);
+ size_t size = rstream_available(&input->read_stream);
+ if (size) {
+ size_t consumed = handle_raw_buffer(input, true, input->read_stream.read_pos, size);
+ rstream_consume(&input->read_stream, consumed);
}
tk_getkeys(input, true);
tinput_flush(input);
@@ -487,39 +479,37 @@ static void tinput_timer_cb(uv_timer_t *handle)
///
/// @param input the input stream
/// @return true iff handle_focus_event consumed some input
-static bool handle_focus_event(TermInput *input)
+static size_t handle_focus_event(TermInput *input, const char *ptr, size_t size)
{
- if (rbuffer_size(input->read_stream.buffer) > 2
- && (!rbuffer_cmp(input->read_stream.buffer, "\x1b[I", 3)
- || !rbuffer_cmp(input->read_stream.buffer, "\x1b[O", 3))) {
- bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I';
- // Advance past the sequence
- rbuffer_consumed(input->read_stream.buffer, 3);
+ if (size >= 3
+ && (!memcmp(ptr, "\x1b[I", 3)
+ || !memcmp(ptr, "\x1b[O", 3))) {
+ bool focus_gained = ptr[2] == 'I';
MAXSIZE_TEMP_ARRAY(args, 1);
ADD_C(args, BOOLEAN_OBJ(focus_gained));
rpc_send_event(ui_client_channel_id, "nvim_ui_set_focus", args);
- return true;
+ return 3; // Advance past the sequence
}
- return false;
+ return 0;
}
#define START_PASTE "\x1b[200~"
#define END_PASTE "\x1b[201~"
-static HandleState handle_bracketed_paste(TermInput *input)
+static size_t handle_bracketed_paste(TermInput *input, const char *ptr, size_t size,
+ bool *incomplete)
{
- size_t buf_size = rbuffer_size(input->read_stream.buffer);
- if (buf_size > 5
- && (!rbuffer_cmp(input->read_stream.buffer, START_PASTE, 6)
- || !rbuffer_cmp(input->read_stream.buffer, END_PASTE, 6))) {
- bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0';
+ if (size >= 6
+ && (!memcmp(ptr, START_PASTE, 6)
+ || !memcmp(ptr, END_PASTE, 6))) {
+ bool enable = ptr[4] == '0';
if (input->paste && enable) {
- return kNotApplicable; // Pasting "start paste" code literally.
+ return 0; // Pasting "start paste" code literally.
}
+
// Advance past the sequence
- rbuffer_consumed(input->read_stream.buffer, 6);
if (!!input->paste == enable) {
- return kComplete; // Spurious "disable paste" code.
+ return 6; // Spurious "disable paste" code.
}
if (enable) {
@@ -534,15 +524,15 @@ static HandleState handle_bracketed_paste(TermInput *input)
// Paste phase: "disabled".
input->paste = 0;
}
- return kComplete;
- } else if (buf_size < 6
- && (!rbuffer_cmp(input->read_stream.buffer, START_PASTE, buf_size)
- || !rbuffer_cmp(input->read_stream.buffer,
- END_PASTE, buf_size))) {
+ return 6;
+ } else if (size < 6
+ && (!memcmp(ptr, START_PASTE, size)
+ || !memcmp(ptr, END_PASTE, size))) {
// Wait for further input, as the sequence may be split.
- return kIncomplete;
+ *incomplete = true;
+ return 0;
}
- return kNotApplicable;
+ return 0;
}
/// Handle an OSC or DCS response sequence from the terminal.
@@ -653,20 +643,31 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key)
}
}
-static void handle_raw_buffer(TermInput *input, bool force)
+static size_t handle_raw_buffer(TermInput *input, bool force, const char *data, size_t size)
{
- HandleState is_paste = kNotApplicable;
+ const char *ptr = data;
do {
- if (!force
- && (handle_focus_event(input)
- || (is_paste = handle_bracketed_paste(input)) != kNotApplicable)) {
- if (is_paste == kIncomplete) {
+ if (!force) {
+ size_t consumed = handle_focus_event(input, ptr, size);
+ if (consumed) {
+ ptr += consumed;
+ size -= consumed;
+ continue;
+ }
+
+ bool incomplete = false;
+ consumed = handle_bracketed_paste(input, ptr, size, &incomplete);
+ if (incomplete) {
+ assert(consumed == 0);
// Wait for the next input, leaving it in the raw buffer due to an
// incomplete sequence.
- return;
+ return (size_t)(ptr - data);
+ } else if (consumed) {
+ ptr += consumed;
+ size -= consumed;
+ continue;
}
- continue;
}
//
@@ -675,55 +676,47 @@ static void handle_raw_buffer(TermInput *input, bool force)
// calls (above) depend on this.
//
size_t count = 0;
- RBUFFER_EACH(input->read_stream.buffer, c, i) {
+ for (size_t i = 0; i < size; i++) {
count = i + 1;
- if (c == '\x1b' && count > 1) {
+ if (ptr[i] == '\x1b' && count > 1) {
count--;
break;
}
}
// Push bytes directly (paste).
if (input->paste) {
- RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
- size_t consumed = MIN(count, len);
- assert(consumed <= input->read_stream.buffer->size);
- tinput_enqueue(input, ptr, consumed);
- rbuffer_consumed(input->read_stream.buffer, consumed);
- if (!(count -= consumed)) {
- break;
- }
- }
+ tinput_enqueue(input, ptr, count);
+ ptr += count;
+ size -= count;
continue;
}
+
// Push through libtermkey (translates to "<keycode>" strings, etc.).
- RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
- const size_t size = MIN(count, len);
- if (size > termkey_get_buffer_remaining(input->tk)) {
+ {
+ const size_t to_use = MIN(count, size);
+ if (to_use > termkey_get_buffer_remaining(input->tk)) {
// We are processing a very long escape sequence. Increase termkey's
// internal buffer size. We don't handle out of memory situations so
// abort if it fails
- const size_t delta = size - termkey_get_buffer_remaining(input->tk);
+ const size_t delta = to_use - termkey_get_buffer_remaining(input->tk);
const size_t bufsize = termkey_get_buffer_size(input->tk);
if (!termkey_set_buffer_size(input->tk, MAX(bufsize + delta, bufsize * 2))) {
abort();
}
}
- size_t consumed = termkey_push_bytes(input->tk, ptr, size);
+ size_t consumed = termkey_push_bytes(input->tk, ptr, to_use);
// We resize termkey's buffer when it runs out of space, so this should
// never happen
- assert(consumed <= rbuffer_size(input->read_stream.buffer));
- rbuffer_consumed(input->read_stream.buffer, consumed);
+ assert(consumed <= to_use);
+ ptr += consumed;
+ size -= consumed;
// Process the input buffer now for any keys
tk_getkeys(input, false);
-
- if (!(count -= consumed)) {
- break;
- }
}
- } while (rbuffer_size(input->read_stream.buffer));
+ } while (size);
const size_t tk_size = termkey_get_buffer_size(input->tk);
const size_t tk_remaining = termkey_get_buffer_remaining(input->tk);
@@ -735,23 +728,25 @@ static void handle_raw_buffer(TermInput *input, bool force)
abort();
}
}
+
+ return (size_t)(ptr - data);
}
-static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *data, bool eof)
+static size_t tinput_read_cb(RStream *stream, const char *buf, size_t count_, void *data, bool eof)
{
TermInput *input = data;
+ size_t consumed = handle_raw_buffer(input, false, buf, count_);
+ tinput_flush(input);
+
if (eof) {
loop_schedule_fast(&main_loop, event_create(tinput_done_event, NULL));
- return;
+ return consumed;
}
- handle_raw_buffer(input, false);
- tinput_flush(input);
-
// An incomplete sequence was found. Leave it in the raw buffer and wait for
// the next input.
- if (rbuffer_size(input->read_stream.buffer)) {
+ if (consumed < count_) {
// If 'ttimeout' is not set, start the timer with a timeout of 0 to process
// the next input.
int64_t ms = input->ttimeout
@@ -759,11 +754,7 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *da
// Stop the current timer if already running
uv_timer_stop(&input->timer_handle);
uv_timer_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0);
- return;
}
- // Make sure the next input escape sequence fits into the ring buffer without
- // wraparound, else it could be misinterpreted (because rbuffer_read_ptr()
- // exposes the underlying buffer to callers unaware of the wraparound).
- rbuffer_reset(input->read_stream.buffer);
+ return consumed;
}
diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h
index bf6d0f2978..8d0c0c20e9 100644
--- a/src/nvim/tui/input.h
+++ b/src/nvim/tui/input.h
@@ -5,7 +5,6 @@
#include <uv.h>
#include "nvim/event/defs.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/tui/input_defs.h" // IWYU pragma: keep
#include "nvim/tui/tui_defs.h"
#include "nvim/types_defs.h"
@@ -17,6 +16,7 @@ typedef enum {
kKeyEncodingXterm, ///< Xterm's modifyOtherKeys encoding (XTMODKEYS)
} KeyEncoding;
+#define KEY_BUFFER_SIZE 0x1000
typedef struct {
int in_fd;
// Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk
@@ -33,17 +33,12 @@ typedef struct {
TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook
uv_timer_t timer_handle;
Loop *loop;
- Stream read_stream;
- RBuffer *key_buffer;
+ RStream read_stream;
TUIData *tui_data;
+ char key_buffer[KEY_BUFFER_SIZE];
+ size_t key_buffer_len;
} TermInput;
-typedef enum {
- kIncomplete = -1,
- kNotApplicable = 0,
- kComplete = 1,
-} HandleState;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/input.h.generated.h"
#endif
diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c
index 3cf9650428..657bd6dd10 100644
--- a/src/nvim/tui/terminfo.c
+++ b/src/nvim/tui/terminfo.c
@@ -35,7 +35,7 @@ bool terminfo_is_term_family(const char *term, const char *family)
// The screen terminfo may have a terminal name like screen.xterm. By making
// the dot(.) a valid separator, such terminal names will also be the
// terminal family of the screen.
- && ('\0' == term[flen] || '-' == term[flen] || '.' == term[flen]);
+ && (NUL == term[flen] || '-' == term[flen] || '.' == term[flen]);
}
bool terminfo_is_bsd_console(const char *term)
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index dc8c8def5b..57696b1839 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1855,20 +1855,12 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name)
return -1;
}
-/// Determine if the terminal supports truecolor or not:
+/// Determine if the terminal supports truecolor or not.
///
-/// 1. If $COLORTERM is "24bit" or "truecolor", return true
-/// 2. Else, check terminfo for Tc, RGB, setrgbf, or setrgbb capabilities. If
-/// found, return true
-/// 3. Else, return false
+/// If terminfo contains Tc, RGB, or both setrgbf and setrgbb capabilities, return true.
static bool term_has_truecolor(TUIData *tui, const char *colorterm)
{
- // Check $COLORTERM
- if (strequal(colorterm, "truecolor") || strequal(colorterm, "24bit")) {
- return true;
- }
-
- // Check for Tc and RGB
+ // Check for Tc or RGB
for (size_t i = 0; i < unibi_count_ext_bool(tui->ut); i++) {
const char *n = unibi_get_ext_bool_name(tui->ut, i);
if (n && (!strcmp(n, "Tc") || !strcmp(n, "RGB"))) {
@@ -2508,7 +2500,7 @@ static const char *tui_get_stty_erase(int fd)
struct termios t;
if (tcgetattr(fd, &t) != -1) {
stty_erase[0] = (char)t.c_cc[VERASE];
- stty_erase[1] = '\0';
+ stty_erase[1] = NUL;
DLOG("stty/termios:erase=%s", stty_erase);
}
#endif
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index ba720c9f6a..ed5c9a508c 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -92,6 +92,7 @@
#include "nvim/decoration.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds_defs.h"
diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c
index e3d9dc5f54..877624b07e 100644
--- a/src/nvim/usercmd.c
+++ b/src/nvim/usercmd.c
@@ -422,10 +422,10 @@ char *get_user_cmd_complete(expand_T *xp, int idx)
int cmdcomplete_str_to_type(const char *complete_str)
{
- if (strncmp(complete_str, "custom,", 7) == 0) {
+ if (strncmp(complete_str, S_LEN("custom,")) == 0) {
return EXPAND_USER_DEFINED;
}
- if (strncmp(complete_str, "customlist,", 11) == 0) {
+ if (strncmp(complete_str, S_LEN("customlist,")) == 0) {
return EXPAND_USER_LIST;
}
@@ -580,7 +580,7 @@ static void uc_list(char *name, size_t name_len)
IObuff[len++] = ' ';
} while ((int64_t)len < 25 - over);
- IObuff[len] = '\0';
+ IObuff[len] = NUL;
msg_outtrans(IObuff, 0);
if (cmd->uc_luaref != LUA_NOREF) {
@@ -831,7 +831,7 @@ invalid_count:
}
} else {
char ch = attr[len];
- attr[len] = '\0';
+ attr[len] = NUL;
semsg(_("E181: Invalid attribute: %s"), attr);
attr[len] = ch;
return FAIL;
@@ -1056,7 +1056,7 @@ void ex_delcommand(exarg_T *eap)
const char *arg = eap->arg;
bool buffer_only = false;
- if (strncmp(arg, "-buffer", 7) == 0 && ascii_iswhite(arg[7])) {
+ if (strncmp(arg, S_LEN("-buffer")) == 0 && ascii_iswhite(arg[7])) {
buffer_only = true;
arg = skipwhite(arg + 7);
}
@@ -1274,9 +1274,9 @@ static size_t add_cmd_modifier(char *buf, char *mod_str, bool *multi_mods)
if (buf != NULL) {
if (*multi_mods) {
- STRCAT(buf, " ");
+ strcat(buf, " ");
}
- STRCAT(buf, mod_str);
+ strcat(buf, mod_str);
}
*multi_mods = true;
@@ -1364,7 +1364,7 @@ size_t uc_mods(char *buf, const cmdmod_T *cmod, bool quote)
if (quote) {
*buf++ = '"';
}
- *buf = '\0';
+ *buf = NUL;
}
// the modifiers that are simple flags
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 1a6c3f7263..732ba6566b 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -22,6 +22,7 @@
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -788,7 +789,7 @@ int win_fdccol_count(win_T *wp)
const char *fdc = wp->w_p_fdc;
// auto:<NUM>
- if (strncmp(fdc, "auto", 4) == 0) {
+ if (strncmp(fdc, S_LEN("auto")) == 0) {
const int fdccol = fdc[4] == ':' ? fdc[5] - '0' : 1;
int needed_fdccols = getDeepestNesting(wp);
return MIN(fdccol, needed_fdccols);
diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c
index e3ca0ff139..77bbaed105 100644
--- a/src/nvim/winfloat.c
+++ b/src/nvim/winfloat.c
@@ -11,6 +11,7 @@
#include "nvim/autocmd.h"
#include "nvim/buffer_defs.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/grid_defs.h"