aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clint.py5
-rw-r--r--src/nvim/CMakeLists.txt19
-rw-r--r--src/nvim/api/buffer.c1
-rw-r--r--src/nvim/api/deprecated.c11
-rw-r--r--src/nvim/api/keysets_defs.h8
-rw-r--r--src/nvim/api/options.c110
-rw-r--r--src/nvim/api/private/converter.c31
-rw-r--r--src/nvim/api/private/helpers.c4
-rw-r--r--src/nvim/api/vim.c7
-rw-r--r--src/nvim/api/vimscript.c9
-rw-r--r--src/nvim/autocmd.c4
-rw-r--r--src/nvim/autocmd.h6
-rw-r--r--src/nvim/buffer.c76
-rw-r--r--src/nvim/buffer_defs.h11
-rw-r--r--src/nvim/channel.c4
-rw-r--r--src/nvim/context.c10
-rw-r--r--src/nvim/decoration.c170
-rw-r--r--src/nvim/decoration.h2
-rw-r--r--src/nvim/diff.c4
-rw-r--r--src/nvim/drawline.c4
-rw-r--r--src/nvim/drawscreen.c52
-rw-r--r--src/nvim/eval.c69
-rw-r--r--src/nvim/eval.lua4
-rw-r--r--src/nvim/eval/decode.c14
-rw-r--r--src/nvim/eval/funcs.c31
-rw-r--r--src/nvim/eval/userfunc.c4
-rw-r--r--src/nvim/eval/vars.c26
-rw-r--r--src/nvim/ex_cmds.c18
-rw-r--r--src/nvim/ex_docmd.c6
-rw-r--r--src/nvim/ex_getln.c13
-rw-r--r--src/nvim/extmark.c26
-rw-r--r--src/nvim/extmark.h8
-rw-r--r--src/nvim/fileio.c4
-rw-r--r--src/nvim/generators/gen_options.lua23
-rw-r--r--src/nvim/globals.h3
-rw-r--r--src/nvim/help.c8
-rw-r--r--src/nvim/highlight_group.c7
-rw-r--r--src/nvim/indent.c4
-rw-r--r--src/nvim/log.c2
-rw-r--r--src/nvim/lua/converter.c8
-rw-r--r--src/nvim/lua/executor.c2
-rw-r--r--src/nvim/lua/stdlib.c7
-rw-r--r--src/nvim/main.c24
-rw-r--r--src/nvim/map.c3
-rw-r--r--src/nvim/map_defs.h3
-rw-r--r--src/nvim/mapping.c4
-rw-r--r--src/nvim/mark.c6
-rw-r--r--src/nvim/marktree.c15
-rw-r--r--src/nvim/marktree.h83
-rw-r--r--src/nvim/marktree_defs.h83
-rw-r--r--src/nvim/memline.c2
-rw-r--r--src/nvim/message.c2
-rw-r--r--src/nvim/move.c2
-rw-r--r--src/nvim/ops.c4
-rw-r--r--src/nvim/option.c651
-rw-r--r--src/nvim/option.h11
-rw-r--r--src/nvim/option_defs.h5
-rw-r--r--src/nvim/options.lua586
-rw-r--r--src/nvim/optionstr.c87
-rw-r--r--src/nvim/path.c2
-rw-r--r--src/nvim/plines.c1
-rw-r--r--src/nvim/plines.h4
-rw-r--r--src/nvim/popupmenu.c10
-rw-r--r--src/nvim/quickfix.c16
-rw-r--r--src/nvim/runtime.c2
-rw-r--r--src/nvim/shada.c2
-rw-r--r--src/nvim/spell.c6
-rw-r--r--src/nvim/spellfile.c2
-rw-r--r--src/nvim/statusline.c38
-rw-r--r--src/nvim/statusline.h1
-rw-r--r--src/nvim/terminal.c6
-rw-r--r--src/nvim/textformat.c6
-rw-r--r--src/nvim/tui/input.c24
-rw-r--r--src/nvim/tui/input.h3
-rw-r--r--src/nvim/tui/tui.c178
-rw-r--r--src/nvim/types_defs.h7
-rw-r--r--src/nvim/ui.c23
-rw-r--r--src/nvim/ui_client.c9
-rw-r--r--src/nvim/undo.c2
-rw-r--r--src/nvim/version.c2
-rw-r--r--src/nvim/window.c2
81 files changed, 1393 insertions, 1359 deletions
diff --git a/src/clint.py b/src/clint.py
index 596e2d8a26..ed5aaf43d2 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -900,16 +900,13 @@ def CheckIncludes(filename, lines, error):
# These should be synced with the ignored headers in the `iwyu` target in
# the Makefile.
check_includes_ignore = [
- "src/nvim/api/extmark.h",
"src/nvim/api/private/helpers.h",
"src/nvim/api/private/validate.h",
"src/nvim/assert_defs.h",
- "src/nvim/autocmd.h",
"src/nvim/buffer.h",
"src/nvim/buffer_defs.h",
"src/nvim/channel.h",
"src/nvim/charset.h",
- "src/nvim/decoration.h",
"src/nvim/drawline.h",
"src/nvim/eval.h",
"src/nvim/eval/encode.h",
@@ -927,7 +924,6 @@ def CheckIncludes(filename, lines, error):
"src/nvim/event/stream.h",
"src/nvim/event/time.h",
"src/nvim/event/wstream.h",
- "src/nvim/extmark.h",
"src/nvim/garray.h",
"src/nvim/globals.h",
"src/nvim/grid.h",
@@ -946,7 +942,6 @@ def CheckIncludes(filename, lines, error):
"src/nvim/os/pty_conpty_win.h",
"src/nvim/os/pty_process_unix.h",
"src/nvim/os/pty_process_win.h",
- "src/nvim/plines.h",
"src/nvim/tui/input.h",
"src/nvim/ui.h",
"src/nvim/viml/parser/expressions.h",
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 0cdce539eb..2ccb8071c6 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -11,17 +11,9 @@ set_target_properties(nvim
#-------------------------------------------------------------------------------
add_library(libuv INTERFACE)
-find_package(libuv CONFIG QUIET)
-if(TARGET libuv::uv_a)
- target_link_libraries(libuv INTERFACE libuv::uv_a)
- mark_as_advanced(libuv_DIR)
-else()
- # Fall back to find module for libuv versions older than v1.45.0 which don't
- # provide a config file
- find_package(Libuv 1.28.0 REQUIRED MODULE)
- target_include_directories(libuv SYSTEM BEFORE INTERFACE ${LIBUV_INCLUDE_DIR})
- target_link_libraries(libuv INTERFACE ${LIBUV_LIBRARIES})
-endif()
+find_package(Libuv 1.28.0 REQUIRED)
+target_include_directories(libuv SYSTEM BEFORE INTERFACE ${LIBUV_INCLUDE_DIR})
+target_link_libraries(libuv INTERFACE ${LIBUV_LIBRARIES})
add_library(nlua0 MODULE)
if(WIN32)
@@ -332,6 +324,7 @@ set(GENERATED_KEYSETS_DEFS ${GENERATED_DIR}/keysets_defs.generated.h)
set(GENERATED_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h)
set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h)
set(GENERATED_OPTIONS ${GENERATED_DIR}/options.generated.h)
+set(GENERATED_OPTIONS_ENUM ${GENERATED_DIR}/options_enum.generated.h)
set(EX_CMDS_GENERATOR ${GENERATOR_DIR}/gen_ex_cmds.lua)
set(FUNCS_GENERATOR ${GENERATOR_DIR}/gen_eval.lua)
set(EVENTS_GENERATOR ${GENERATOR_DIR}/gen_events.lua)
@@ -676,8 +669,8 @@ add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
DEPENDS ${LUA_GEN_DEPS} ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua
)
-add_custom_command(OUTPUT ${GENERATED_OPTIONS}
- COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS}
+add_custom_command(OUTPUT ${GENERATED_OPTIONS} ${GENERATED_OPTIONS_ENUM}
+ COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS} ${GENERATED_OPTIONS_ENUM}
DEPENDS ${LUA_GEN_DEPS} ${OPTIONS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua
)
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index e0dd265167..99d261e73d 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -12,6 +12,7 @@
#include "nvim/api/buffer.h"
#include "nvim/api/keysets_defs.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/ascii_defs.h"
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index d6a76617a7..371361c5a1 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -643,7 +643,7 @@ static Object get_option_from(void *from, OptReqScope req_scope, String name, Er
return (Object)OBJECT_INIT;
});
- OptVal value = get_option_value_strict(name.data, req_scope, from, err);
+ OptVal value = get_option_value_strict(findoption(name.data), req_scope, from, err);
if (ERROR_SET(err)) {
return (Object)OBJECT_INIT;
}
@@ -669,8 +669,8 @@ static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope,
return;
});
- int flags = get_option_attrs(name.data);
- VALIDATE_S(flags != 0, "option name", name.data, {
+ OptIndex opt_idx = findoption(name.data);
+ VALIDATE_S(opt_idx != kOptInvalid, "option name", name.data, {
return;
});
@@ -685,13 +685,14 @@ static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope,
return;
});
+ int attrs = get_option_attrs(opt_idx);
// For global-win-local options -> setlocal
// For win-local options -> setglobal and setlocal (opt_flags == 0)
- const int opt_flags = (req_scope == kOptReqWin && !(flags & SOPT_GLOBAL))
+ const int opt_flags = (req_scope == kOptReqWin && !(attrs & SOPT_GLOBAL))
? 0
: (req_scope == kOptReqGlobal) ? OPT_GLOBAL : OPT_LOCAL;
WITH_SCRIPT_CONTEXT(channel_id, {
- set_option_value_for(name.data, optval, opt_flags, req_scope, to, err);
+ set_option_value_for(name.data, opt_idx, optval, opt_flags, req_scope, to, err);
});
}
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index 5aae88f7b3..d1cbe43de0 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -3,6 +3,10 @@
#include "nvim/api/private/defs.h"
typedef struct {
+ OptionalKeys is_set__empty_;
+} Dict(empty);
+
+typedef struct {
OptionalKeys is_set__context_;
Array types;
} Dict(context);
@@ -338,10 +342,6 @@ typedef struct {
} Dict(buf_delete);
typedef struct {
- OptionalKeys is_set__empty_;
-} Dict(empty);
-
-typedef struct {
OptionalKeys is_set__open_term_;
LuaRef on_input;
} Dict(open_term);
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index 9cf91bad42..54a2fbf385 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -23,9 +23,9 @@
# include "api/options.c.generated.h"
#endif
-static int validate_option_value_args(Dict(option) *opts, char *name, int *scope,
- OptReqScope *req_scope, void **from, char **filetype,
- Error *err)
+static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *opt_idxp,
+ int *scope, OptReqScope *req_scope, void **from,
+ char **filetype, Error *err)
{
#define HAS_KEY_X(d, v) HAS_KEY(d, option, v)
if (HAS_KEY_X(opts, scope)) {
@@ -79,7 +79,8 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope
return FAIL;
});
- int flags = get_option_attrs(name);
+ *opt_idxp = findoption(name);
+ int flags = get_option_attrs(*opt_idxp);
if (flags == 0) {
// hidden or unknown option
api_set_error(err, kErrorTypeValidation, "Unknown option '%s'", name);
@@ -119,10 +120,10 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err)
aucmd_prepbuf(aco, ftbuf);
TRY_WRAP(err, {
- set_option_value("bufhidden", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
- set_option_value("buftype", STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
- set_option_value("swapfile", BOOLEAN_OPTVAL(false), OPT_LOCAL);
- set_option_value("modeline", BOOLEAN_OPTVAL(false), OPT_LOCAL); // 'nomodeline'
+ set_option_value(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
+ set_option_value(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
+ set_option_value(kOptSwapfile, BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ set_option_value(kOptModeline, BOOLEAN_OPTVAL(false), OPT_LOCAL); // 'nomodeline'
ftbuf->b_p_ft = xstrdup(filetype);
do_filetype_autocmd(ftbuf, false);
@@ -152,23 +153,22 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err)
Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
FUNC_API_SINCE(9)
{
- Object rv = OBJECT_INIT;
- OptVal value = NIL_OPTVAL;
-
+ OptIndex opt_idx = 0;
int scope = 0;
OptReqScope req_scope = kOptReqGlobal;
void *from = NULL;
char *filetype = NULL;
- if (!validate_option_value_args(opts, name.data, &scope, &req_scope, &from, &filetype, err)) {
- goto err;
+ if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &from, &filetype,
+ err)) {
+ return (Object)OBJECT_INIT;
}
aco_save_T aco;
buf_T *ftbuf = do_ft_buf(filetype, &aco, err);
if (ERROR_SET(err)) {
- goto err;
+ return (Object)OBJECT_INIT;
}
if (ftbuf != NULL) {
@@ -176,8 +176,8 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
from = ftbuf;
}
- bool hidden;
- value = get_option_value_for(name.data, NULL, scope, &hidden, req_scope, from, err);
+ OptVal value = get_option_value_for(opt_idx, scope, req_scope, from, err);
+ bool hidden = is_option_hidden(opt_idx);
if (ftbuf != NULL) {
// restore curwin/curbuf and a few other things
@@ -198,7 +198,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
return optval_as_object(value);
err:
optval_free(value);
- return rv;
+ return (Object)OBJECT_INIT;
}
/// Sets the value of an option. The behavior of this function matches that of
@@ -219,10 +219,11 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(
Error *err)
FUNC_API_SINCE(9)
{
+ OptIndex opt_idx = 0;
int scope = 0;
OptReqScope req_scope = kOptReqGlobal;
void *to = NULL;
- if (!validate_option_value_args(opts, name.data, &scope, &req_scope, &to, NULL, err)) {
+ if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &to, NULL, err)) {
return;
}
@@ -233,7 +234,7 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(
//
// Then force scope to local since we don't want to change the global option
if (req_scope == kOptReqWin && scope == 0) {
- int flags = get_option_attrs(name.data);
+ int flags = get_option_attrs(opt_idx);
if (flags & SOPT_GLOBAL) {
scope = OPT_LOCAL;
}
@@ -251,7 +252,7 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(
});
WITH_SCRIPT_CONTEXT(channel_id, {
- set_option_value_for(name.data, optval, scope, req_scope, to, err);
+ set_option_value_for(name.data, opt_idx, optval, scope, req_scope, to, err);
});
}
@@ -305,10 +306,12 @@ Dictionary nvim_get_all_options_info(Error *err)
Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Error *err)
FUNC_API_SINCE(11)
{
+ OptIndex opt_idx = 0;
int scope = 0;
OptReqScope req_scope = kOptReqGlobal;
void *from = NULL;
- if (!validate_option_value_args(opts, name.data, &scope, &req_scope, &from, NULL, err)) {
+ if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &from, NULL,
+ err)) {
return (Dictionary)ARRAY_DICT_INIT;
}
@@ -384,25 +387,19 @@ static void restore_option_context(void *const ctx, OptReqScope req_scope)
/// Get attributes for an option.
///
-/// @param name Option name.
+/// @param opt_idx Option index in options[] table.
///
/// @return Option attributes.
/// 0 for hidden or unknown option.
/// See SOPT_* in option_defs.h for other flags.
-int get_option_attrs(char *name)
+int get_option_attrs(OptIndex opt_idx)
{
- int opt_idx = findoption(name);
-
- if (opt_idx < 0) {
+ if (opt_idx == kOptInvalid) {
return 0;
}
vimoption_T *opt = get_option(opt_idx);
- if (is_tty_option(opt->fullname)) {
- return SOPT_STRING | SOPT_GLOBAL;
- }
-
// Hidden option
if (opt->var == NULL) {
return 0;
@@ -410,14 +407,6 @@ int get_option_attrs(char *name)
int attrs = 0;
- if (opt->flags & P_BOOL) {
- attrs |= SOPT_BOOL;
- } else if (opt->flags & P_NUM) {
- attrs |= SOPT_NUM;
- } else if (opt->flags & P_STRING) {
- attrs |= SOPT_STRING;
- }
-
if (opt->indir == PV_NONE || (opt->indir & PV_BOTH)) {
attrs |= SOPT_GLOBAL;
}
@@ -432,15 +421,13 @@ int get_option_attrs(char *name)
/// Check if option has a value in the requested scope.
///
-/// @param name Option name.
+/// @param opt_idx Option index in options[] table.
/// @param req_scope Requested option scope. See OptReqScope in option.h.
///
/// @return true if option has a value in the requested scope, false otherwise.
-static bool option_has_scope(char *name, OptReqScope req_scope)
+static bool option_has_scope(OptIndex opt_idx, OptReqScope req_scope)
{
- int opt_idx = findoption(name);
-
- if (opt_idx < 0) {
+ if (opt_idx == kOptInvalid) {
return false;
}
@@ -468,7 +455,7 @@ static bool option_has_scope(char *name, OptReqScope req_scope)
/// Get the option value in the requested scope.
///
-/// @param name Option name.
+/// @param opt_idx Option index in options[] table.
/// @param req_scope Requested option scope. See OptReqScope in option.h.
/// @param[in] from Pointer to buffer or window for local option value.
/// @param[out] err Error message, if any.
@@ -476,21 +463,12 @@ static bool option_has_scope(char *name, OptReqScope req_scope)
/// @return Option value in the requested scope. Returns a Nil option value if option is not found,
/// hidden or if it isn't present in the requested scope. (i.e. has no global, window-local or
/// buffer-local value depending on opt_scope).
-OptVal get_option_value_strict(char *name, OptReqScope req_scope, void *from, Error *err)
+OptVal get_option_value_strict(OptIndex opt_idx, OptReqScope req_scope, void *from, Error *err)
{
- OptVal retv = NIL_OPTVAL;
-
- if (!option_has_scope(name, req_scope)) {
- return retv;
- }
- if (get_tty_option(name, &retv.data.string.data)) {
- retv.type = kOptValTypeString;
- return retv;
+ if (opt_idx == kOptInvalid || !option_has_scope(opt_idx, req_scope)) {
+ return NIL_OPTVAL;
}
- int opt_idx = findoption(name);
- assert(opt_idx != 0); // option_has_scope() already verifies if option name is valid.
-
vimoption_T *opt = get_option(opt_idx);
switchwin_T switchwin;
aco_save_T aco;
@@ -498,11 +476,11 @@ OptVal get_option_value_strict(char *name, OptReqScope req_scope, void *from, Er
: (req_scope == kOptReqBuf ? (void *)&aco : NULL);
bool switched = switch_option_context(ctx, req_scope, from, err);
if (ERROR_SET(err)) {
- return retv;
+ return NIL_OPTVAL;
}
char *varp = get_varp_scope(opt, req_scope == kOptReqGlobal ? OPT_GLOBAL : OPT_LOCAL);
- retv = optval_from_varp(opt_idx, varp);
+ OptVal retv = optval_from_varp(opt_idx, varp);
if (switched) {
restore_option_context(ctx, req_scope);
@@ -513,7 +491,7 @@ OptVal get_option_value_strict(char *name, OptReqScope req_scope, void *from, Er
/// Get option value for buffer / window.
///
-/// @param[in] name Option name.
+/// @param opt_idx Option index in options[] table.
/// @param[out] flagsp Set to the option flags (P_xxxx) (if not NULL).
/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination).
/// @param[out] hidden Whether option is hidden.
@@ -522,8 +500,8 @@ OptVal get_option_value_strict(char *name, OptReqScope req_scope, void *from, Er
/// @param[out] err Error message, if any.
///
/// @return Option value. Must be freed by caller.
-OptVal get_option_value_for(const char *const name, uint32_t *flagsp, int scope, bool *hidden,
- const OptReqScope req_scope, void *const from, Error *err)
+OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptReqScope req_scope,
+ void *const from, Error *err)
{
switchwin_T switchwin;
aco_save_T aco;
@@ -535,7 +513,7 @@ OptVal get_option_value_for(const char *const name, uint32_t *flagsp, int scope,
return NIL_OPTVAL;
}
- OptVal retv = get_option_value(name, flagsp, scope, hidden);
+ OptVal retv = get_option_value(opt_idx, scope);
if (switched) {
restore_option_context(ctx, req_scope);
@@ -546,14 +524,16 @@ OptVal get_option_value_for(const char *const name, uint32_t *flagsp, int scope,
/// Set option value for buffer / window.
///
-/// @param[in] name Option name.
+/// @param name Option name.
+/// @param opt_idx Option index in options[] table.
/// @param[in] value Option value.
/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
/// @param req_scope Requested option scope. See OptReqScope in option.h.
/// @param[in] from Target buffer/window.
/// @param[out] err Error message, if any.
-void set_option_value_for(const char *const name, OptVal value, const int opt_flags,
+void set_option_value_for(const char *name, OptIndex opt_idx, OptVal value, const int opt_flags,
const OptReqScope req_scope, void *const from, Error *err)
+ FUNC_ATTR_NONNULL_ARG(1)
{
switchwin_T switchwin;
aco_save_T aco;
@@ -565,7 +545,7 @@ void set_option_value_for(const char *const name, OptVal value, const int opt_fl
return;
}
- const char *const errmsg = set_option_value(name, value, opt_flags);
+ const char *const errmsg = set_option_value_handle_tty(name, opt_idx, value, opt_flags);
if (errmsg) {
api_set_error(err, kErrorTypeException, "%s", errmsg);
}
diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c
index ef57bde32d..e7b8934c97 100644
--- a/src/nvim/api/private/converter.c
+++ b/src/nvim/api/private/converter.c
@@ -258,9 +258,7 @@ Object vim_to_object(typval_T *obj)
/// @param tv Conversion result is placed here. On failure member v_type is
/// set to VAR_UNKNOWN (no allocation was made for this variable).
/// @param err Error object.
-///
-/// @returns true if conversion is successful, otherwise false.
-bool object_to_vim(Object obj, typval_T *tv, Error *err)
+void object_to_vim(Object obj, typval_T *tv, Error *err)
{
tv->v_type = VAR_UNKNOWN;
tv->v_lock = VAR_UNLOCKED;
@@ -307,12 +305,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
for (uint32_t i = 0; i < obj.data.array.size; i++) {
Object item = obj.data.array.items[i];
typval_T li_tv;
-
- if (!object_to_vim(item, &li_tv, err)) {
- tv_list_free(list);
- return false;
- }
-
+ object_to_vim(item, &li_tv, err);
tv_list_append_owned_tv(list, li_tv);
}
tv_list_ref(list);
@@ -328,24 +321,8 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
KeyValuePair item = obj.data.dictionary.items[i];
String key = item.key;
-
- if (key.size == 0) {
- api_set_error(err, kErrorTypeValidation,
- "Empty dictionary keys aren't allowed");
- // cleanup
- tv_dict_free(dict);
- return false;
- }
-
dictitem_T *const di = tv_dict_item_alloc(key.data);
-
- if (!object_to_vim(item.value, &di->di_tv, err)) {
- // cleanup
- tv_dict_item_free(di);
- tv_dict_free(dict);
- return false;
- }
-
+ object_to_vim(item.value, &di->di_tv, err);
tv_dict_add(dict, di);
}
dict->dv_refcount++;
@@ -362,6 +339,4 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
break;
}
}
-
- return true;
}
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index b23684aee9..2772fa8b59 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -253,9 +253,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
typval_T tv;
// Convert the object to a vimscript type in the temporary variable
- if (!object_to_vim(value, &tv, err)) {
- return rv;
- }
+ object_to_vim(value, &tv, err);
typval_T oldtv = TV_INITIAL_VALUE;
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 0842469c59..a52d7493e3 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -948,8 +948,8 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
if (scratch) {
- set_string_option_direct_in_buf(buf, "bufhidden", -1, "hide", OPT_LOCAL, 0);
- set_string_option_direct_in_buf(buf, "buftype", -1, "nofile", OPT_LOCAL, 0);
+ set_string_option_direct_in_buf(buf, kOptBufhidden, "hide", OPT_LOCAL, 0);
+ set_string_option_direct_in_buf(buf, kOptBuftype, "nofile", OPT_LOCAL, 0);
assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already
buf->b_p_swf = false;
buf->b_p_ml = false;
@@ -2189,7 +2189,6 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
int cul_id = 0;
int num_id = 0;
linenr_T lnum = statuscol_lnum;
- wp->w_scwidth = win_signcol_count(wp);
decor_redraw_signs(wp, wp->w_buffer, lnum - 1, sattrs, &line_id, &cul_id, &num_id);
statuscol.sattrs = sattrs;
@@ -2240,7 +2239,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
buf,
sizeof(buf),
str.data,
- NULL,
+ -1,
0,
fillchar,
maxwidth,
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 25a34f769c..3bca988030 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -207,9 +207,7 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
typval_T vim_args[MAX_FUNC_ARGS + 1];
size_t i = 0; // also used for freeing the variables
for (; i < args.size; i++) {
- if (!object_to_vim(args.items[i], &vim_args[i], err)) {
- goto free_vim_args;
- }
+ object_to_vim(args.items[i], &vim_args[i], err);
}
// Initialize `force_abort` and `suppress_errthrow` at the top level.
@@ -243,7 +241,6 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
tv_clear(&rettv);
recursive--;
-free_vim_args:
while (i > 0) {
tv_clear(&vim_args[--i]);
}
@@ -297,9 +294,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
mustfree = true;
break;
case kObjectTypeDictionary:
- if (!object_to_vim(dict, &rettv, err)) {
- goto end;
- }
+ object_to_vim(dict, &rettv, err);
break;
default:
api_set_error(err, kErrorTypeValidation,
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 46a08c5706..72b0852d8d 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -704,7 +704,7 @@ char *au_event_disable(char *what)
} else {
STRCAT(new_ei, what);
}
- set_string_option_direct("ei", -1, new_ei, OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptEventignore, new_ei, OPT_FREE, SID_NONE);
xfree(new_ei);
return save_ei;
}
@@ -712,7 +712,7 @@ char *au_event_disable(char *what)
void au_event_restore(char *old_ei)
{
if (old_ei != NULL) {
- set_string_option_direct("ei", -1, old_ei, OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptEventignore, old_ei, OPT_FREE, SID_NONE);
xfree(old_ei);
}
}
diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h
index 8ff4d75ddf..ea8f32feb2 100644
--- a/src/nvim/autocmd.h
+++ b/src/nvim/autocmd.h
@@ -1,9 +1,10 @@
#pragma once
#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
+#include <stddef.h> // IWYU pragma: keep
+#include <stdint.h> // IWYU pragma: keep
+#include "klib/kvec.h"
#include "nvim/api/private/defs.h" // IWYU pragma: keep
#include "nvim/autocmd_defs.h" // IWYU pragma: export
#include "nvim/buffer_defs.h"
@@ -12,7 +13,6 @@
#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
#include "nvim/macros_defs.h"
#include "nvim/pos_defs.h"
-#include "nvim/types_defs.h"
// Set by the apply_autocmds_group function if the given event is equal to
// EVENT_FILETYPE. Used by the readfile function in order to determine if
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 8a594dea92..0392ff6ebd 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -750,6 +750,8 @@ void buf_clear(void)
{
linenr_T line_count = curbuf->b_ml.ml_line_count;
extmark_free_all(curbuf); // delete any extmarks
+ map_destroy(int, curbuf->b_signcols.invalid);
+ *curbuf->b_signcols.invalid = (Map(int, SignRange)) MAP_INIT;
while (!(curbuf->b_ml.ml_flags & ML_EMPTY)) {
ml_delete(1, false);
}
@@ -920,6 +922,8 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
}
uc_clear(&buf->b_ucmds); // clear local user commands
extmark_free_all(buf); // delete any extmarks
+ map_destroy(int, buf->b_signcols.invalid);
+ *buf->b_signcols.invalid = (Map(int, SignRange)) MAP_INIT;
map_clear_mode(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_mode(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc);
@@ -1844,7 +1848,6 @@ buf_T *buflist_new(char *ffname_arg, char *sfname_arg, linenr_T lnum, int flags)
buf = xcalloc(1, sizeof(buf_T));
// init b: variables
buf->b_vars = tv_dict_alloc();
- buf->b_signcols.sentinel = 0;
init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
buf_init_changedtick(buf);
}
@@ -3278,7 +3281,7 @@ void maketitle(void)
if (*p_titlestring != NUL) {
if (stl_syntax & STL_IN_TITLE) {
build_stl_str_hl(curwin, buf, sizeof(buf), p_titlestring,
- "titlestring", 0, 0, maxlen, NULL, NULL, NULL);
+ kOptTitlestring, 0, 0, maxlen, NULL, NULL, NULL);
title_str = buf;
} else {
title_str = p_titlestring;
@@ -3383,7 +3386,7 @@ void maketitle(void)
if (*p_iconstring != NUL) {
if (stl_syntax & STL_IN_ICON) {
build_stl_str_hl(curwin, icon_str, sizeof(buf), p_iconstring,
- "iconstring", 0, 0, 0, NULL, NULL, NULL);
+ kOptIconstring, 0, 0, 0, NULL, NULL, NULL);
} else {
icon_str = p_iconstring;
}
@@ -4026,67 +4029,6 @@ char *buf_spname(buf_T *buf)
return NULL;
}
-/// Invalidate the signcolumn if needed after deleting a sign ranging from line1 to line2.
-void buf_signcols_del_check(buf_T *buf, linenr_T line1, linenr_T line2)
-{
- linenr_T sent = buf->b_signcols.sentinel;
- if (sent >= line1 && sent <= line2) {
- // When removed sign overlaps the sentinel line, entire buffer needs to be checked.
- buf->b_signcols.sentinel = buf->b_signcols.size = 0;
- }
-}
-
-/// Invalidate the signcolumn if needed after adding a sign ranging from line1 to line2.
-void buf_signcols_add_check(buf_T *buf, linenr_T line1, linenr_T line2)
-{
- if (!buf->b_signcols.sentinel) {
- return;
- }
-
- linenr_T sent = buf->b_signcols.sentinel;
- if (sent >= line1 && sent <= line2) {
- // If added sign overlaps sentinel line, increment without invalidating.
- if (buf->b_signcols.size == buf->b_signcols.max) {
- buf->b_signcols.max++;
- }
- buf->b_signcols.size++;
- return;
- }
-
- if (line1 < buf->b_signcols.invalid_top) {
- buf->b_signcols.invalid_top = line1;
- }
- if (line2 > buf->b_signcols.invalid_bot) {
- buf->b_signcols.invalid_bot = line2;
- }
-}
-
-int buf_signcols(buf_T *buf, int max)
-{
- if (!buf->b_signs_with_text) {
- buf->b_signcols.size = 0;
- } else if (max <= 1 && buf->b_signs_with_text >= (size_t)max) {
- buf->b_signcols.size = max;
- } else {
- linenr_T sent = buf->b_signcols.sentinel;
- if (!sent || max > buf->b_signcols.max) {
- // Recheck if the window scoped maximum 'signcolumn' is greater than the
- // previous maximum or if there is no sentinel line yet.
- buf->b_signcols.invalid_top = sent ? sent : 1;
- buf->b_signcols.invalid_bot = sent ? sent : buf->b_ml.ml_line_count;
- }
-
- if (buf->b_signcols.invalid_bot) {
- decor_validate_signcols(buf, max);
- }
- }
-
- buf->b_signcols.max = max;
- buf->b_signcols.invalid_top = MAXLNUM;
- buf->b_signcols.invalid_bot = 0;
- return buf->b_signcols.size;
-}
-
/// Get "buf->b_fname", use "[No Name]" if it is NULL.
char *buf_get_fname(const buf_T *buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
@@ -4205,9 +4147,9 @@ int buf_open_scratch(handle_T bufnr, char *bufname)
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
(void)setfname(curbuf, bufname, NULL, true);
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
- set_option_value_give_err("bh", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
- set_option_value_give_err("bt", STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
- set_option_value_give_err("swf", BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
+ set_option_value_give_err(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
+ set_option_value_give_err(kOptSwapfile, BOOLEAN_OPTVAL(false), OPT_LOCAL);
RESET_BINDING(curwin);
return OK;
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index b26d42385b..beb3ec95b8 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -26,7 +26,7 @@ typedef struct {
#include "nvim/map_defs.h"
#include "nvim/mapping_defs.h"
#include "nvim/mark_defs.h"
-#include "nvim/marktree.h"
+#include "nvim/marktree_defs.h"
#include "nvim/option_vars.h"
#include "nvim/pos_defs.h"
#include "nvim/statusline_defs.h"
@@ -703,11 +703,10 @@ struct file_buffer {
// may use a different synblock_T.
struct {
- int size; // last calculated number of sign columns
- int max; // maximum value size is valid for.
- linenr_T sentinel; // a line number which is holding up the signcolumn
- linenr_T invalid_top; // first invalid line number that needs to be checked
- linenr_T invalid_bot; // last invalid line number that needs to be checked
+ int max; // maximum number of signs on a single line
+ int max_count; // number of lines with max number of signs
+ bool resized; // whether max changed at start of redraw
+ Map(int, SignRange) invalid[1]; // map of invalid ranges to be checked
} b_signcols;
Terminal *terminal; // Terminal instance associated with the buffer
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 767c8d29b8..ca8cbed8f9 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -233,7 +233,7 @@ void channel_create_event(Channel *chan, const char *ext_source)
typval_T tv = TV_INITIAL_VALUE;
// TODO(bfredl): do the conversion in one step. Also would be nice
// to pretty print top level dict in defined order
- (void)object_to_vim(DICTIONARY_OBJ(info), &tv, NULL);
+ object_to_vim(DICTIONARY_OBJ(info), &tv, NULL);
assert(tv.v_type == VAR_DICT);
char *str = encode_tv2json(&tv, NULL);
ILOG("new channel %" PRIu64 " (%s) : %s", chan->id, source, str);
@@ -865,7 +865,7 @@ static void set_info_event(void **argv)
dict_T *dict = get_v_event(&save_v_event);
Dictionary info = channel_info(chan->id);
typval_T retval;
- (void)object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
+ object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
assert(retval.v_type == VAR_DICT);
tv_dict_add_dict(dict, S_LEN("info"), retval.vval.v_dict);
tv_dict_set_keys_readonly(dict);
diff --git a/src/nvim/context.c b/src/nvim/context.c
index 5f47cfc225..dfb214d065 100644
--- a/src/nvim/context.c
+++ b/src/nvim/context.c
@@ -138,8 +138,8 @@ bool ctx_restore(Context *ctx, const int flags)
free_ctx = true;
}
- OptVal op_shada = get_option_value("shada", NULL, OPT_GLOBAL, NULL);
- set_option_value("shada", STATIC_CSTR_AS_OPTVAL("!,'100,%"), OPT_GLOBAL);
+ OptVal op_shada = get_option_value(kOptShada, OPT_GLOBAL);
+ set_option_value(kOptShada, STATIC_CSTR_AS_OPTVAL("!,'100,%"), OPT_GLOBAL);
if (flags & kCtxRegs) {
ctx_restore_regs(ctx);
@@ -165,7 +165,7 @@ bool ctx_restore(Context *ctx, const int flags)
ctx_free(ctx);
}
- set_option_value("shada", op_shada, OPT_GLOBAL);
+ set_option_value(kOptShada, op_shada, OPT_GLOBAL);
optval_free(op_shada);
return true;
@@ -326,9 +326,7 @@ static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err)
msgpack_sbuffer_init(&sbuf);
typval_T list_tv;
- if (!object_to_vim(ARRAY_OBJ(array), &list_tv, err)) {
- return sbuf;
- }
+ object_to_vim(ARRAY_OBJ(array), &list_tv, err);
assert(list_tv.v_type == VAR_LIST);
if (!encode_vim_list_to_buf(list_tv.vval.v_list, &sbuf.size, &sbuf.data)) {
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 11204a1b31..74056b7c26 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -14,6 +14,7 @@
#include "nvim/grid.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
+#include "nvim/marktree.h"
#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/option_vars.h"
@@ -202,21 +203,21 @@ void buf_put_decor_virt(buf_T *buf, DecorVirtText *vt)
}
static int sign_add_id = 0;
-void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row, int row2)
+void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
{
if (sh->flags & kSHIsSign) {
sh->sign_add_id = sign_add_id++;
buf->b_signs++;
if (sh->text.ptr) {
buf->b_signs_with_text++;
- buf_signcols_add_check(buf, row + 1, row2 + 1);
+ buf_signcols_invalidate_range(buf, row1, row2, 1);
}
}
}
-void buf_decor_remove(buf_T *buf, int row, int row2, DecorInline decor, bool free)
+void buf_decor_remove(buf_T *buf, int row1, int row2, DecorInline decor, bool free)
{
- decor_redraw(buf, row, row2, decor);
+ decor_redraw(buf, row1, row2, decor);
if (decor.ext) {
DecorVirtText *vt = decor.data.ext.vt;
while (vt) {
@@ -226,7 +227,7 @@ void buf_decor_remove(buf_T *buf, int row, int row2, DecorInline decor, bool fre
uint32_t idx = decor.data.ext.sh_idx;
while (idx != DECOR_ID_INVALID) {
DecorSignHighlight *sh = &kv_A(decor_items, idx);
- buf_remove_decor_sh(buf, row, row2, sh);
+ buf_remove_decor_sh(buf, row1, row2, sh);
idx = sh->next;
}
if (free) {
@@ -248,7 +249,7 @@ void buf_remove_decor_virt(buf_T *buf, DecorVirtText *vt)
}
}
-void buf_remove_decor_sh(buf_T *buf, int row, int row2, DecorSignHighlight *sh)
+void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh)
{
if (sh->flags & kSHIsSign) {
assert(buf->b_signs > 0);
@@ -256,8 +257,8 @@ void buf_remove_decor_sh(buf_T *buf, int row, int row2, DecorSignHighlight *sh)
if (sh->text.ptr) {
assert(buf->b_signs_with_text > 0);
buf->b_signs_with_text--;
- if (row2 >= row) {
- buf_signcols_del_check(buf, row + 1, row2 + 1);
+ if (row2 >= row1) {
+ buf_signcols_invalidate_range(buf, row1, row2, -1);
}
}
}
@@ -718,7 +719,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[],
int *cul_id, int *num_id)
{
MarkTreeIter itr[1];
- if (!buf->b_signs || !marktree_itr_get_overlap(buf->b_marktree, row, 0, itr)) {
+ if (!marktree_itr_get_overlap(buf->b_marktree, row, 0, itr)) {
return;
}
@@ -791,50 +792,129 @@ DecorSignHighlight *decor_find_sign(DecorInline decor)
}
}
-// Increase the signcolumn size and update the sentinel line if necessary for
-// the invalidated range.
-void decor_validate_signcols(buf_T *buf, int max)
+static void buf_signcols_validate_row(buf_T *buf, int count, int add)
{
- int signcols = 0; // highest value of count
- int currow = buf->b_signcols.invalid_top - 1;
- // TODO(bfredl): only need to use marktree_itr_get_overlap once.
- // then we can process both start and end events and update state for each row
- for (; currow < buf->b_signcols.invalid_bot; currow++) {
- MarkTreeIter itr[1];
- if (!marktree_itr_get_overlap(buf->b_marktree, currow, 0, itr)) {
- continue;
- }
+ // If "count" is greater than current max, set it and reset "max_count".
+ if (count > buf->b_signcols.max) {
+ buf->b_signcols.max = count;
+ buf->b_signcols.max_count = 0;
+ buf->b_signcols.resized = true;
+ }
+ // If row has or had "max" signs, adjust "max_count" with sign of "add".
+ if (count == buf->b_signcols.max - (add < 0 ? -add : 0)) {
+ buf->b_signcols.max_count += (add > 0) - (add < 0);
+ }
+}
- int count = 0;
- MTPair pair;
- while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
- if (!mt_invalid(pair.start) && (pair.start.flags & MT_FLAG_DECOR_SIGNTEXT)) {
- count++;
- }
- }
+/// Validate a range by counting the number of overlapping signs and adjusting
+/// "b_signcols" accordingly.
+static void buf_signcols_validate_range(buf_T *buf, int row1, int row2, int add)
+{
+ if (-add == buf->b_signcols.max) {
+ buf->b_signcols.max_count -= (row2 + 1 - row1);
+ return; // max signs were removed from the range, no need to count.
+ }
- while (itr->x) {
- MTKey mark = marktree_itr_current(itr);
- if (mark.pos.row != currow) {
- break;
- }
- if (!mt_invalid(mark) && !mt_end(mark) && (mark.flags & MT_FLAG_DECOR_SIGNTEXT)) {
- count++;
- }
- marktree_itr_next(buf->b_marktree, itr);
+ int currow = row1;
+ MTPair pair = { 0 };
+ MarkTreeIter itr[1];
+
+ // Allocate an array of integers holding the overlapping signs in the range.
+ assert(row2 >= row1);
+ int *overlap = xcalloc(sizeof(int), (size_t)(row2 + 1 - row1));
+
+ // First find the number of overlapping signs at "row1".
+ (void)marktree_itr_get_overlap(buf->b_marktree, currow, 0, itr);
+ while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
+ if (!mt_invalid(pair.start) && pair.start.flags & MT_FLAG_DECOR_SIGNTEXT) {
+ overlap[0]++;
}
+ }
- if (count > signcols) {
- if (count >= buf->b_signcols.size) {
- buf->b_signcols.size = count;
- buf->b_signcols.sentinel = currow + 1;
- }
- if (count >= max) {
- return;
+ // Continue traversing the marktree until beyond "row2".
+ while (itr->x) {
+ MTKey mark = marktree_itr_current(itr);
+ if (mark.pos.row > row2) {
+ break;
+ }
+ // Finish the count at the previous row.
+ if (mark.pos.row != currow) {
+ buf_signcols_validate_row(buf, overlap[currow - row1], add);
+ currow = mark.pos.row;
+ }
+ // Increment overlap array for the start and range of a paired sign mark.
+ if (!mt_invalid(mark) && !mt_end(mark) && (mark.flags & MT_FLAG_DECOR_SIGNTEXT)) {
+ MTPos end = marktree_get_altpos(buf->b_marktree, mark, NULL);
+ for (int i = currow; i <= MIN(row2, end.row < 0 ? currow : end.row); i++) {
+ overlap[i - row1]++;
}
- signcols = count;
}
+
+ marktree_itr_next(buf->b_marktree, itr);
+ }
+ buf_signcols_validate_row(buf, overlap[currow - row1], add);
+ xfree(overlap);
+}
+
+int buf_signcols_validate(win_T *wp, buf_T *buf, bool stc_check)
+{
+ if (!map_size(buf->b_signcols.invalid)) {
+ return buf->b_signcols.max;
+ }
+
+ int start;
+ SignRange range;
+ map_foreach(buf->b_signcols.invalid, start, range, {
+ // Leave rest of the ranges invalid if max is already at configured
+ // maximum or resize is detected for a 'statuscolumn' rebuild.
+ if ((stc_check && buf->b_signcols.resized)
+ || (!stc_check && range.add > 0 && buf->b_signcols.max >= wp->w_maxscwidth)) {
+ return wp->w_maxscwidth;
+ }
+ buf_signcols_validate_range(buf, start, range.end, range.add);
+ });
+
+ // Check if we need to scan the entire buffer.
+ if (buf->b_signcols.max_count == 0) {
+ buf->b_signcols.max = 0;
+ buf->b_signcols.resized = true;
+ buf_signcols_validate_range(buf, 0, buf->b_ml.ml_line_count, 1);
+ }
+
+ map_clear(int, buf->b_signcols.invalid);
+ return buf->b_signcols.max;
+}
+
+static void buf_signcols_invalidate_range(buf_T *buf, int row1, int row2, int add)
+{
+ if (!buf->b_signs_with_text) {
+ buf->b_signcols.max = buf->b_signcols.max_count = 0;
+ buf->b_signcols.resized = true;
+ map_clear(int, buf->b_signcols.invalid);
+ return;
}
+
+ // Remove an invalid range if sum of added/removed signs is now 0.
+ SignRange *srp = map_ref(int, SignRange)(buf->b_signcols.invalid, row1, NULL);
+ if (srp && srp->end == row2 && srp->add + add == 0) {
+ map_del(int, SignRange)(buf->b_signcols.invalid, row1, NULL);
+ return;
+ }
+
+ // Merge with overlapping invalid range.
+ int start;
+ SignRange range;
+ map_foreach(buf->b_signcols.invalid, start, range, {
+ if (row1 <= range.end && start <= row2) {
+ row1 = MIN(row1, start);
+ row2 = MAX(row2, range.end);
+ break;
+ }
+ });
+
+ srp = map_put_ref(int, SignRange)(buf->b_signcols.invalid, row1, NULL, NULL);
+ srp->end = row2;
+ srp->add += add;
}
void decor_redraw_end(DecorState *state)
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index e5bac169dc..92e0cbc76b 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -8,7 +8,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/decoration_defs.h" // IWYU pragma: export
#include "nvim/macros_defs.h"
-#include "nvim/marktree.h"
+#include "nvim/marktree_defs.h"
#include "nvim/pos_defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h"
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 6578a1121c..483182dc25 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -1389,7 +1389,7 @@ static void set_diff_option(win_T *wp, bool value)
curwin = wp;
curbuf = curwin->w_buffer;
curbuf->b_ro_locked++;
- set_option_value_give_err("diff", BOOLEAN_OPTVAL(value), OPT_LOCAL);
+ set_option_value_give_err(kOptDiff, BOOLEAN_OPTVAL(value), OPT_LOCAL);
curbuf->b_ro_locked--;
curwin = old_curwin;
curbuf = curwin->w_buffer;
@@ -1430,7 +1430,7 @@ void diff_win_options(win_T *wp, int addbuf)
}
wp->w_p_fdm_save = xstrdup(wp->w_p_fdm);
}
- set_string_option_direct_in_win(wp, "fdm", -1, "diff", OPT_LOCAL | OPT_FREE, 0);
+ set_string_option_direct_in_win(wp, kOptFoldmethod, "diff", OPT_LOCAL | OPT_FREE, 0);
if (!wp->w_p_diff) {
wp->w_p_fen_save = wp->w_p_fen;
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index e0887ed1d0..77bd05eb55 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -704,8 +704,8 @@ static void handle_breakindent(win_T *wp, winlinevars_T *wlv)
if (wlv->draw_state == WL_BRI - 1 && wlv->n_extra == 0) {
wlv->draw_state = WL_BRI;
// if wlv->need_showbreak is set, breakindent also applies
- if (wp->w_p_bri && (wlv->row != wlv->startrow || wlv->need_showbreak)
- && wlv->filler_lines == 0) {
+ if (wp->w_p_bri && (wlv->row > wlv->startrow + wlv->filler_lines
+ || wlv->need_showbreak)) {
wlv->char_attr = 0;
if (wlv->diff_hlf != (hlf_T)0) {
wlv->char_attr = win_hl_attr(wp, (int)wlv->diff_hlf);
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 85f62db774..314764d117 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -603,15 +603,6 @@ int update_screen(void)
buf->b_mod_tick_decor = display_tick;
}
}
-
- // Reset 'statuscolumn' if there is no dedicated signcolumn but it is invalid.
- if (*wp->w_p_stc != NUL && wp->w_minscwidth <= SCL_NO
- && (wp->w_buffer->b_signcols.invalid_bot || !wp->w_buffer->b_signcols.sentinel)) {
- wp->w_nrwidth_line_count = 0;
- wp->w_valid &= ~VALID_WCOL;
- wp->w_redr_type = UPD_NOT_VALID;
- wp->w_buffer->b_signcols.invalid_bot = 0;
- }
}
// Go from top to bottom through the windows, redrawing the ones that need it.
@@ -658,10 +649,11 @@ int update_screen(void)
win_check_ns_hl(NULL);
- // Reset b_mod_set flags. Going through all windows is probably faster
- // than going through all buffers (there could be many buffers).
+ // Reset b_mod_set and b_signcols.resized flags. Going through all windows is
+ // probably faster than going through all buffers (there could be many buffers).
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
wp->w_buffer->b_mod_set = false;
+ wp->w_buffer->b_signcols.resized = false;
}
updating_screen = 0;
@@ -1200,17 +1192,31 @@ void comp_col(void)
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
}
-static void redraw_win_signcol(win_T *wp)
+/// Redraw entire window "wp" if configured 'signcolumn' width changes.
+static bool win_redraw_signcols(win_T *wp)
{
- // If we can compute a change in the automatic sizing of the sign column
- // under 'signcolumn=auto:X' and signs currently placed in the buffer, better
- // figuring it out here so we can redraw the entire screen for it.
- int scwidth = wp->w_scwidth;
- wp->w_scwidth = win_signcol_count(wp);
- if (wp->w_scwidth != scwidth) {
- changed_line_abv_curs_win(wp);
- redraw_later(wp, UPD_NOT_VALID);
+ int width;
+ bool rebuild_stc = false;
+ buf_T *buf = wp->w_buffer;
+
+ if (wp->w_minscwidth <= SCL_NO) {
+ if (*wp->w_p_stc) {
+ buf_signcols_validate(wp, buf, true);
+ if (buf->b_signcols.resized) {
+ rebuild_stc = true;
+ wp->w_nrwidth_line_count = 0;
+ }
+ }
+ width = 0;
+ } else if (wp->w_maxscwidth <= 1 && buf->b_signs_with_text >= (size_t)wp->w_maxscwidth) {
+ width = wp->w_maxscwidth;
+ } else {
+ width = buf_signcols_validate(wp, buf, false);
}
+
+ int scwidth = wp->w_scwidth;
+ wp->w_scwidth = MAX(wp->w_minscwidth, width);
+ return (wp->w_scwidth != scwidth || rebuild_stc);
}
/// Check if horizontal separator of window "wp" at specified window corner is connected to the
@@ -1490,7 +1496,11 @@ static void win_update(win_T *wp, DecorProviders *providers)
DecorProviders line_providers;
decor_providers_invoke_win(wp, providers, &line_providers);
- redraw_win_signcol(wp);
+ if (win_redraw_signcols(wp)) {
+ wp->w_lines_valid = 0;
+ wp->w_redr_type = UPD_NOT_VALID;
+ changed_line_abv_curs_win(wp);
+ }
init_search_hl(wp, &screen_search_hl);
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index ae34f5715f..1fdaa95076 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -681,7 +681,7 @@ int eval_charconvert(const char *const enc_from, const char *const enc_to,
set_vim_var_string(VV_CC_TO, enc_to, -1);
set_vim_var_string(VV_FNAME_IN, fname_from, -1);
set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
- sctx_T *ctx = get_option_sctx("charconvert");
+ sctx_T *ctx = get_option_sctx(kOptCharconvert);
if (ctx != NULL) {
current_sctx = *ctx;
}
@@ -710,7 +710,7 @@ void eval_diff(const char *const origfile, const char *const newfile, const char
set_vim_var_string(VV_FNAME_NEW, newfile, -1);
set_vim_var_string(VV_FNAME_OUT, outfile, -1);
- sctx_T *ctx = get_option_sctx("diffexpr");
+ sctx_T *ctx = get_option_sctx(kOptDiffexpr);
if (ctx != NULL) {
current_sctx = *ctx;
}
@@ -732,7 +732,7 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch
set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
set_vim_var_string(VV_FNAME_OUT, outfile, -1);
- sctx_T *ctx = get_option_sctx("patchexpr");
+ sctx_T *ctx = get_option_sctx(kOptPatchexpr);
if (ctx != NULL) {
current_sctx = *ctx;
}
@@ -1134,7 +1134,7 @@ list_T *eval_spell_expr(char *badword, char *expr)
if (p_verbose == 0) {
emsg_off++;
}
- sctx_T *ctx = get_option_sctx("spellsuggest");
+ sctx_T *ctx = get_option_sctx(kOptSpellsuggest);
if (ctx != NULL) {
current_sctx = *ctx;
}
@@ -1278,7 +1278,7 @@ void *call_func_retlist(const char *func, int argc, typval_T *argv)
int eval_foldexpr(win_T *wp, int *cp)
{
const sctx_T saved_sctx = current_sctx;
- const bool use_sandbox = was_set_insecurely(wp, "foldexpr", OPT_LOCAL);
+ const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL);
char *arg = wp->w_p_fde;
current_sctx = wp->w_p_script_ctx[WV_FDE].script_ctx;
@@ -1326,7 +1326,7 @@ int eval_foldexpr(win_T *wp, int *cp)
/// Evaluate 'foldtext', returning an Array or a String (NULL_STRING on failure).
Object eval_foldtext(win_T *wp)
{
- const bool use_sandbox = was_set_insecurely(wp, "foldtext", OPT_LOCAL);
+ const bool use_sandbox = was_set_insecurely(wp, kOptFoldtext, OPT_LOCAL);
char *arg = wp->w_p_fdt;
funccal_entry_T funccal_entry;
@@ -3735,7 +3735,11 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv
dictitem_T *const item = tv_dict_find(rettv->vval.v_dict, key, keylen);
if (item == NULL && verbose) {
- semsg(_(e_dictkey), key);
+ if (keylen > 0) {
+ semsg(_(e_dictkey_len), keylen, key);
+ } else {
+ semsg(_(e_dictkey), key);
+ }
}
if (item == NULL || tv_is_luafunc(&item->di_tv)) {
return FAIL;
@@ -3780,37 +3784,32 @@ int eval_option(const char **const arg, typval_T *const rettv, const bool evalua
}
int ret = OK;
- bool hidden;
char c = *option_end;
*option_end = NUL;
- OptVal value = get_option_value(*arg, NULL, scope, &hidden);
- if (rettv != NULL) {
- switch (value.type) {
- case kOptValTypeNil:
+ bool is_tty_opt = is_tty_option(*arg);
+ OptIndex opt_idx = is_tty_opt ? kOptInvalid : findoption(*arg);
+
+ if (opt_idx == kOptInvalid && !is_tty_opt) {
+ // Only give error if result is going to be used.
+ if (rettv != NULL) {
semsg(_("E113: Unknown option: %s"), *arg);
- ret = FAIL;
- break;
- case kOptValTypeBoolean:
- rettv->v_type = VAR_NUMBER;
- rettv->vval.v_number = value.data.boolean;
- break;
- case kOptValTypeNumber:
- rettv->v_type = VAR_NUMBER;
- rettv->vval.v_number = value.data.number;
- break;
- case kOptValTypeString:
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = value.data.string.data;
- break;
}
- } else {
- // Value isn't being used, free it.
- optval_free(value);
- if (value.type == kOptValTypeNil || (working && hidden)) {
- ret = FAIL;
+ ret = FAIL;
+ } else if (rettv != NULL) {
+ OptVal value = is_tty_opt ? get_tty_option(*arg) : get_option_value(opt_idx, scope);
+ assert(value.type != kOptValTypeNil);
+
+ *rettv = optval_as_tv(value);
+
+ // Convert boolean option value to number for backwards compatibility.
+ if (rettv->v_type == VAR_BOOL) {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = rettv->vval.v_bool == kBoolVarTrue ? 1 : 0;
}
+ } else if (working && !is_tty_opt && is_option_hidden(opt_idx)) {
+ ret = FAIL;
}
*option_end = c; // put back for error messages
@@ -4711,7 +4710,7 @@ bool set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack)
/// @param ht_stack Used to add hashtabs to be marked. Can be NULL.
///
/// @returns true if setting references failed somehow.
-bool set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack)
+bool set_ref_in_list_items(list_T *l, int copyID, ht_stack_T **ht_stack)
FUNC_ATTR_WARN_UNUSED_RESULT
{
bool abort = false;
@@ -4788,7 +4787,7 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack
// Didn't see this list yet.
ll->lv_copyID = copyID;
if (list_stack == NULL) {
- abort = set_ref_in_list(ll, copyID, ht_stack);
+ abort = set_ref_in_list_items(ll, copyID, ht_stack);
} else {
list_stack_T *const newitem = xmalloc(sizeof(list_stack_T));
newitem->list = ll;
@@ -5030,7 +5029,7 @@ size_t string2float(const char *const text, float_T *const ret_value)
return 3;
}
if (STRNICMP(text, "-inf", 3) == 0) {
- *ret_value = (float_T) - INFINITY;
+ *ret_value = (float_T)(-INFINITY);
return 4;
}
if (STRNICMP(text, "nan", 3) == 0) {
@@ -8716,7 +8715,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
// If it's still empty it was changed and restored, need to restore in
// the complicated way.
if (*p_cpo == NUL) {
- set_option_value_give_err("cpo", CSTR_AS_OPTVAL(save_cpo), 0);
+ set_option_value_give_err(kOptCpoptions, CSTR_AS_OPTVAL(save_cpo), 0);
}
free_string_option(save_cpo);
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 59423808be..51cf7bb0ea 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -5735,8 +5735,7 @@ M.funcs = {
Vim value. In the following cases it will output
|msgpack-special-dict|:
1. Dictionary contains duplicate key.
- 2. Dictionary contains empty key.
- 3. String contains NUL byte. Two special dictionaries: for
+ 2. String contains NUL byte. Two special dictionaries: for
dictionary and for string will be emitted in case string
with NUL byte was a dictionary key.
@@ -7155,7 +7154,6 @@ M.funcs = {
are binary strings).
2. String with NUL byte inside.
3. Duplicate key.
- 4. Empty key.
ext |List| with two values: first is a signed integer
representing extension type. Second is
|readfile()|-style list of strings.
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index a6407693d7..64b65b42a5 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -141,9 +141,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, ValuesStack *const stack
ValuesStackItem key = kv_pop(*stack);
if (last_container.special_val == NULL) {
// These cases should have already been handled.
- assert(!(key.is_special_string
- || key.val.vval.v_string == NULL
- || *key.val.vval.v_string == NUL));
+ assert(!(key.is_special_string || key.val.vval.v_string == NULL));
dictitem_T *const obj_di = tv_dict_item_alloc(key.val.vval.v_string);
tv_clear(&key.val);
if (tv_dict_add(last_container.container.vval.v_dict, obj_di)
@@ -170,11 +168,10 @@ static inline int json_decoder_pop(ValuesStackItem obj, ValuesStack *const stack
tv_clear(&obj.val);
return FAIL;
}
- // Handle empty key and key represented as special dictionary
+ // Handle special dictionaries
if (last_container.special_val == NULL
&& (obj.is_special_string
|| obj.val.vval.v_string == NULL
- || *obj.val.vval.v_string == NUL
|| tv_dict_find(last_container.container.vval.v_dict, obj.val.vval.v_string, -1))) {
tv_clear(&obj.val);
@@ -404,13 +401,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
semsg(_("E474: Expected string end: %.*s"), (int)buf_len, buf);
goto parse_json_string_fail;
}
- if (len == 0) {
- POP(((typval_T) {
- .v_type = VAR_STRING,
- .vval = { .v_string = NULL },
- }), false);
- goto parse_json_string_ret;
- }
char *str = xmalloc(len + 1);
int fst_in_pair = 0;
char *str_end = str;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 0054c47678..c35e0b2ada 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -355,10 +355,7 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
goto end;
}
- if (!object_to_vim(result, rettv, &err)) {
- assert(ERROR_SET(&err));
- semsg(_("Error converting the call result: %s"), err.msg);
- }
+ object_to_vim(result, rettv, &err);
end:
api_free_array(args);
@@ -428,7 +425,7 @@ static void f_and(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void f_api_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
Dictionary metadata = api_metadata();
- (void)object_to_vim(DICTIONARY_OBJ(metadata), rettv, NULL);
+ object_to_vim(DICTIONARY_OBJ(metadata), rettv, NULL);
}
/// "atan2()" function
@@ -1023,7 +1020,7 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
Dictionary ctx_dict = ctx_to_dict(ctx);
Error err = ERROR_INIT;
- (void)object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err);
+ object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err);
api_free_dictionary(ctx_dict);
api_clear_error(&err);
}
@@ -2174,7 +2171,7 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
- if (f <= (float_T) - VARNUMBER_MAX + DBL_EPSILON) {
+ if (f <= (float_T)(-VARNUMBER_MAX) + DBL_EPSILON) {
rettv->vval.v_number = -VARNUMBER_MAX;
} else if (f >= (float_T)VARNUMBER_MAX - DBL_EPSILON) {
rettv->vval.v_number = VARNUMBER_MAX;
@@ -3898,13 +3895,16 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = 1;
}
-static const char *ignored_env_vars[] = {
+static const char *pty_ignored_env_vars[] = {
#ifndef MSWIN
"COLUMNS",
"LINES",
"TERMCAP",
"COLORFGBG",
+ "COLORTERM",
#endif
+ "VIM",
+ "VIMRUNTIME",
NULL
};
@@ -3943,9 +3943,9 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
// child process. We're removing them here so the user can still decide
// they want to explicitly set them.
for (size_t i = 0;
- i < ARRAY_SIZE(ignored_env_vars) && ignored_env_vars[i];
+ i < ARRAY_SIZE(pty_ignored_env_vars) && pty_ignored_env_vars[i];
i++) {
- dictitem_T *dv = tv_dict_find(env, ignored_env_vars[i], -1);
+ dictitem_T *dv = tv_dict_find(env, pty_ignored_env_vars[i], -1);
if (dv) {
tv_dict_item_remove(env, dv);
}
@@ -3953,10 +3953,6 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
#ifndef MSWIN
// Set COLORTERM to "truecolor" if termguicolors is set
if (p_tgc) {
- dictitem_T *dv = tv_dict_find(env, S_LEN("COLORTERM"));
- if (dv) {
- tv_dict_item_remove(env, dv);
- }
tv_dict_add_str(env, S_LEN("COLORTERM"), "truecolor");
}
#endif
@@ -6754,10 +6750,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
goto end;
}
- if (!object_to_vim(result, rettv, &err)) {
- assert(ERROR_SET(&err));
- semsg(_("Error converting the call result: %s"), err.msg);
- }
+ object_to_vim(result, rettv, &err);
end:
arena_mem_free(res_mem);
@@ -7246,7 +7239,7 @@ int do_searchpair(const char *spat, const char *mpat, const char *epat, int dir,
// If it's still empty it was changed and restored, need to restore in
// the complicated way.
if (*p_cpo == NUL) {
- set_option_value_give_err("cpo", CSTR_AS_OPTVAL(save_cpo), 0);
+ set_option_value_give_err(kOptCpoptions, CSTR_AS_OPTVAL(save_cpo), 0);
}
free_string_option(save_cpo);
}
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index e0bf30b158..ebc84922cb 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -3818,7 +3818,7 @@ bool set_ref_in_previous_funccal(int copyID)
fc->fc_copyID = copyID + 1;
if (set_ref_in_ht(&fc->fc_l_vars.dv_hashtab, copyID + 1, NULL)
|| set_ref_in_ht(&fc->fc_l_avars.dv_hashtab, copyID + 1, NULL)
- || set_ref_in_list(&fc->fc_l_varlist, copyID + 1, NULL)) {
+ || set_ref_in_list_items(&fc->fc_l_varlist, copyID + 1, NULL)) {
return true;
}
}
@@ -3831,7 +3831,7 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID)
fc->fc_copyID = copyID;
if (set_ref_in_ht(&fc->fc_l_vars.dv_hashtab, copyID, NULL)
|| set_ref_in_ht(&fc->fc_l_avars.dv_hashtab, copyID, NULL)
- || set_ref_in_list(&fc->fc_l_varlist, copyID, NULL)
+ || set_ref_in_list_items(&fc->fc_l_varlist, copyID, NULL)
|| set_ref_in_func(NULL, fc->fc_func, copyID)) {
return true;
}
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 670ee39f4b..73c8ae1191 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -773,11 +773,14 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
const char c1 = *p;
*p = NUL;
- uint32_t opt_p_flags;
- bool hidden;
- OptVal curval = get_option_value(arg, &opt_p_flags, scope, &hidden);
+ bool is_tty_opt = is_tty_option(arg);
+ OptIndex opt_idx = is_tty_opt ? kOptInvalid : findoption(arg);
+ uint32_t opt_p_flags = get_option_flags(opt_idx);
+ bool hidden = is_option_hidden(opt_idx);
+ OptVal curval = is_tty_opt ? get_tty_option(arg) : get_option_value(opt_idx, scope);
OptVal newval = NIL_OPTVAL;
- if (curval.type == kOptValTypeNil && arg[0] != 't' && arg[1] != '_') {
+
+ if (curval.type == kOptValTypeNil) {
semsg(_(e_unknown_option2), arg);
goto theend;
}
@@ -831,7 +834,7 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
}
}
- const char *err = set_option_value(arg, newval, scope);
+ const char *err = set_option_value_handle_tty(arg, opt_idx, newval, scope);
arg_end = p;
if (err != NULL) {
emsg(_(err));
@@ -1937,20 +1940,23 @@ typval_T optval_as_tv(OptVal value)
/// Set option "varname" to the value of "varp" for the current buffer/window.
static void set_option_from_tv(const char *varname, typval_T *varp)
{
- int opt_idx = findoption(varname);
- if (opt_idx < 0) {
+ OptIndex opt_idx = findoption(varname);
+ if (opt_idx == kOptInvalid) {
semsg(_(e_unknown_option2), varname);
return;
}
- uint32_t opt_p_flags = get_option(opt_idx)->flags;
bool error = false;
+ uint32_t opt_p_flags = get_option_flags(opt_idx);
OptVal value = tv_to_optval(varp, varname, opt_p_flags, &error);
if (!error) {
- set_option_value_give_err(varname, value, OPT_LOCAL);
- }
+ const char *errmsg = set_option_value_handle_tty(varname, opt_idx, value, OPT_LOCAL);
+ if (errmsg) {
+ emsg(errmsg);
+ }
+ }
optval_free(value);
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 0711d82fe5..786612070e 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -4265,7 +4265,7 @@ skip:
// Show 'inccommand' preview if there are matched lines.
if (cmdpreview_ns > 0 && !aborting()) {
if (got_quit || profile_passed_limit(timeout)) { // Too slow, disable.
- set_string_option_direct("icm", -1, "", OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptInccommand, "", OPT_FREE, SID_NONE);
} else if (*p_icm != NUL && pat != NULL) {
if (pre_hl_id == 0) {
pre_hl_id = syn_check_group(S_LEN("Substitute"));
@@ -4544,8 +4544,8 @@ bool prepare_tagpreview(bool undo_sync)
curwin->w_p_wfh = true;
RESET_BINDING(curwin); // don't take over 'scrollbind' and 'cursorbind'
curwin->w_p_diff = false; // no 'diff'
- set_string_option_direct("fdc", -1, // no 'foldcolumn'
- "0", OPT_FREE, SID_NONE);
+
+ set_string_option_direct(kOptFoldcolumn, "0", OPT_FREE, SID_NONE); // no 'foldcolumn'
return true;
}
@@ -4564,7 +4564,7 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i
buf_T *cmdpreview_buf = NULL;
// disable file info message
- set_string_option_direct("shm", -1, "F", OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptShortmess, "F", OPT_FREE, SID_NONE);
// Update the topline to ensure that main window is on the correct line
update_topline(curwin);
@@ -4580,7 +4580,6 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i
}
// Width of the "| lnum|..." column which displays the line numbers.
- linenr_T highest_num_line = 0;
int col_width = 0;
// Use preview window only when inccommand=split and range is not just the current line
bool preview = (*p_icm == 's') && (eap->line1 != old_cusr.lnum || eap->line2 != old_cusr.lnum);
@@ -4590,8 +4589,11 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i
assert(cmdpreview_buf != NULL);
if (lines.subresults.size > 0) {
- highest_num_line = kv_last(lines.subresults).end.lnum;
- col_width = (int)log10(highest_num_line) + 1 + 3;
+ SubResult last_match = kv_last(lines.subresults);
+ // `last_match.end.lnum` may be 0 when using 'n' flag.
+ linenr_T highest_lnum = MAX(last_match.start.lnum, last_match.end.lnum);
+ assert(highest_lnum > 0);
+ col_width = (int)log10(highest_lnum) + 1 + 3;
}
}
@@ -4663,7 +4665,7 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i
xfree(str);
- set_string_option_direct("shm", -1, save_shm_p, OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptShortmess, save_shm_p, OPT_FREE, SID_NONE);
xfree(save_shm_p);
return preview ? 2 : 1;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 90b816bb6f..ff80ee9e54 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -2653,7 +2653,7 @@ static void apply_cmdmod(cmdmod_T *cmod)
// Set 'eventignore' to "all".
// First save the existing option value for restoring it later.
cmod->cmod_save_ei = xstrdup(p_ei);
- set_string_option_direct("ei", -1, "all", OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptEventignore, "all", OPT_FREE, SID_NONE);
}
}
@@ -2673,7 +2673,7 @@ void undo_cmdmod(cmdmod_T *cmod)
if (cmod->cmod_save_ei != NULL) {
// Restore 'eventignore' to the value before ":noautocmd".
- set_string_option_direct("ei", -1, cmod->cmod_save_ei, OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptEventignore, cmod->cmod_save_ei, OPT_FREE, SID_NONE);
free_string_option(cmod->cmod_save_ei);
cmod->cmod_save_ei = NULL;
}
@@ -7306,7 +7306,7 @@ static void ex_setfiletype(exarg_T *eap)
arg += 9;
}
- set_option_value_give_err("filetype", CSTR_AS_OPTVAL(arg), OPT_LOCAL);
+ set_option_value_give_err(kOptFiletype, CSTR_AS_OPTVAL(arg), OPT_LOCAL);
if (arg != eap->arg) {
did_filetype = false;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index f31f8fec55..afaf0a6e2b 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -152,6 +152,8 @@ typedef struct cmdpreview_buf_info {
buf_T *buf;
OptInt save_b_p_ul;
int save_b_changed;
+ pos_T save_b_op_start;
+ pos_T save_b_op_end;
varnumber_T save_changedtick;
CpUndoInfo undo_info;
} CpBufInfo;
@@ -903,7 +905,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
need_wait_return = false;
}
- set_string_option_direct("icm", -1, s->save_p_icm, OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptInccommand, s->save_p_icm, OPT_FREE, SID_NONE);
State = s->save_State;
if (cmdpreview != save_cmdpreview) {
cmdpreview = save_cmdpreview; // restore preview state
@@ -2360,6 +2362,8 @@ static void cmdpreview_prepare(CpInfo *cpinfo)
cp_bufinfo.buf = buf;
cp_bufinfo.save_b_p_ul = buf->b_p_ul;
cp_bufinfo.save_b_changed = buf->b_changed;
+ cp_bufinfo.save_b_op_start = buf->b_op_start;
+ cp_bufinfo.save_b_op_end = buf->b_op_end;
cp_bufinfo.save_changedtick = buf_get_changedtick(buf);
cmdpreview_save_undo(&cp_bufinfo.undo_info, buf);
kv_push(cpinfo->buf_info, cp_bufinfo);
@@ -2438,6 +2442,9 @@ static void cmdpreview_restore_state(CpInfo *cpinfo)
u_blockfree(buf);
cmdpreview_restore_undo(&cp_bufinfo.undo_info, buf);
+ buf->b_op_start = cp_bufinfo.save_b_op_start;
+ buf->b_op_end = cp_bufinfo.save_b_op_end;
+
if (cp_bufinfo.save_changedtick != buf_get_changedtick(buf)) {
buf_set_changedtick(buf, cp_bufinfo.save_changedtick);
}
@@ -4319,7 +4326,7 @@ static int open_cmdwin(void)
return Ctrl_C;
}
// Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer.
- set_option_value_give_err("bh", STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL);
+ set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL);
curbuf->b_p_ma = true;
curwin->w_p_fen = false;
curwin->w_p_rl = cmdmsg_rl;
@@ -4337,7 +4344,7 @@ static int open_cmdwin(void)
add_map("<Tab>", "<C-X><C-V>", MODE_INSERT, true);
add_map("<Tab>", "a<C-X><C-V>", MODE_NORMAL, true);
}
- set_option_value_give_err("ft", STATIC_CSTR_AS_OPTVAL("vim"), OPT_LOCAL);
+ set_option_value_give_err(kOptFiletype, STATIC_CSTR_AS_OPTVAL("vim"), OPT_LOCAL);
}
curbuf->b_ro_locked--;
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index f510845ec7..92fbc6fb79 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -67,18 +67,18 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
} else {
assert(marktree_itr_valid(itr));
if (old_mark.pos.row == row && old_mark.pos.col == col) {
+ // not paired: we can revise in place
if (mt_decor_any(old_mark)) {
+ mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_DECOR_SIGNTEXT;
buf_decor_remove(buf, row, row, mt_decor(old_mark), true);
}
-
- // not paired: we can revise in place
mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK;
mt_itr_rawkey(itr).flags |= flags;
mt_itr_rawkey(itr).decor_data = decor.data;
goto revised;
}
- buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, mt_decor(old_mark), true);
marktree_del_itr(buf->b_marktree, itr, false);
+ buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, mt_decor(old_mark), true);
}
} else {
*ns = MAX(*ns, id);
@@ -389,6 +389,9 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
} else if (undo_info.type == kExtmarkSavePos) {
ExtmarkSavePos pos = undo_info.data.savepos;
if (undo) {
+ if (pos.old_row >= 0) {
+ extmark_setraw(curbuf, pos.mark, pos.old_row, pos.old_col);
+ }
if (pos.invalidated) {
MarkTreeIter itr[1] = { 0 };
MTKey mark = marktree_lookup(curbuf->b_marktree, pos.mark, itr);
@@ -396,9 +399,6 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
MTPos end = marktree_get_altpos(curbuf->b_marktree, mark, itr);
buf_put_decor(curbuf, mt_decor(mark), mark.pos.row, end.row < 0 ? mark.pos.row : end.row);
}
- if (pos.old_row >= 0) {
- extmark_setraw(curbuf, pos.mark, pos.old_row, pos.old_col);
- }
// Redo
} else {
if (pos.row >= 0) {
@@ -515,20 +515,6 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
extmark_splice_delete(buf, start_row, start_col, end_row, end_col, uvp, false, undo);
}
- // Move the signcolumn sentinel line
- if (buf->b_signs_with_text && buf->b_signcols.sentinel) {
- linenr_T se_lnum = buf->b_signcols.sentinel;
- if (se_lnum >= start_row) {
- if (old_row != 0 && se_lnum > old_row + start_row) {
- buf->b_signcols.sentinel += new_row - old_row;
- } else if (new_row == 0) {
- buf->b_signcols.sentinel = 0;
- } else {
- buf->b_signcols.sentinel += new_row;
- }
- }
- }
-
marktree_splice(buf->b_marktree, (int32_t)start_row, start_col,
old_row, old_col,
new_row, new_col);
diff --git a/src/nvim/extmark.h b/src/nvim/extmark.h
index 1a7a1ddeff..5ba079bd12 100644
--- a/src/nvim/extmark.h
+++ b/src/nvim/extmark.h
@@ -1,17 +1,15 @@
#pragma once
#include <stdbool.h>
-#include <stddef.h>
#include <stdint.h>
#include "klib/kvec.h"
-#include "nvim/buffer_defs.h"
-#include "nvim/decoration.h"
+#include "nvim/buffer_defs.h" // IWYU pragma: keep
+#include "nvim/decoration_defs.h" // IWYU pragma: keep
#include "nvim/extmark_defs.h" // IWYU pragma: export
#include "nvim/macros_defs.h"
-#include "nvim/marktree.h"
+#include "nvim/marktree_defs.h" // IWYU pragma: keep
#include "nvim/pos_defs.h"
-#include "nvim/types_defs.h"
EXTERN int curbuf_splice_pending INIT( = 0);
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 4fe5b1cd44..0e2959835b 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1617,7 +1617,7 @@ failed:
save_file_ff(curbuf);
// If editing a new file: set 'fenc' for the current buffer.
// Also for ":read ++edit file".
- set_string_option_direct("fenc", -1, fenc, OPT_FREE | OPT_LOCAL, 0);
+ set_string_option_direct(kOptFileencoding, fenc, OPT_FREE | OPT_LOCAL, 0);
}
if (fenc_alloced) {
xfree(fenc);
@@ -1965,7 +1965,7 @@ void set_forced_fenc(exarg_T *eap)
}
char *fenc = enc_canonize(eap->cmd + eap->force_enc);
- set_string_option_direct("fenc", -1, fenc, OPT_FREE|OPT_LOCAL, 0);
+ set_string_option_direct(kOptFileencoding, fenc, OPT_FREE|OPT_LOCAL, 0);
xfree(fenc);
}
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index 3a355634f3..b7356a7bb1 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -1,4 +1,5 @@
local options_file = arg[1]
+local options_enum_file = arg[2]
local opt_fd = assert(io.open(options_file, 'w'))
@@ -41,6 +42,12 @@ local list_flags = {
flagscomma = 'P_COMMA|P_FLAGLIST',
}
+--- @param s string
+--- @return string
+local lowercase_to_titlecase = function(s)
+ return s:sub(1, 1):upper() .. s:sub(2)
+end
+
--- @param o vim.option_meta
--- @return string
local function get_flags(o)
@@ -222,11 +229,25 @@ static vimoption_T options[] = {]])
for i, o in ipairs(options.options) do
dump_option(i, o)
end
-w(' [' .. ('%u'):format(#options.options) .. ']={.fullname=NULL}')
w('};')
w('')
for _, v in ipairs(defines) do
w('#define ' .. v[1] .. ' ' .. v[2])
end
+
+-- Generate options enum file
+opt_fd = assert(io.open(options_enum_file, 'w'))
+
+w('typedef enum {')
+w(' kOptInvalid = -1,')
+
+for i, o in ipairs(options.options) do
+ w((' kOpt%s = %u,'):format(lowercase_to_titlecase(o.full_name), i - 1))
+end
+
+w(' // Option count, used when iterating through options')
+w('#define kOptIndexCount ' .. tostring(#options.options))
+w('} OptIndex;')
+
opt_fd:close()
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 1299aa12e5..c0fa63818e 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -672,7 +672,7 @@ EXTERN bool must_redraw_pum INIT( = false); // redraw pum. NB: must_redraw
EXTERN bool need_highlight_changed INIT( = true);
-EXTERN FILE *scriptout INIT( = NULL); ///< Stream to write script to.
+EXTERN FILE *scriptout INIT( = NULL); ///< Write input to this file ("nvim -w").
// Note that even when handling SIGINT, volatile is not necessary because the
// callback is not called directly from the signal handlers.
@@ -887,6 +887,7 @@ 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"));
diff --git a/src/nvim/help.c b/src/nvim/help.c
index dc4f6c44ff..28b95b2346 100644
--- a/src/nvim/help.c
+++ b/src/nvim/help.c
@@ -608,7 +608,7 @@ void cleanup_help_tags(int num_file, char **file)
void prepare_help_buffer(void)
{
curbuf->b_help = true;
- set_string_option_direct("buftype", -1, "help", OPT_FREE|OPT_LOCAL, 0);
+ set_string_option_direct(kOptBuftype, "help", OPT_FREE|OPT_LOCAL, 0);
// Always set these options after jumping to a help tag, because the
// user may have an autocommand that gets in the way.
@@ -617,13 +617,13 @@ void prepare_help_buffer(void)
// Only set it when needed, buf_init_chartab() is some work.
char *p = "!-~,^*,^|,^\",192-255";
if (strcmp(curbuf->b_p_isk, p) != 0) {
- set_string_option_direct("isk", -1, p, OPT_FREE|OPT_LOCAL, 0);
+ set_string_option_direct(kOptIskeyword, p, OPT_FREE|OPT_LOCAL, 0);
check_buf_options(curbuf);
(void)buf_init_chartab(curbuf, false);
}
// Don't use the global foldmethod.
- set_string_option_direct("fdm", -1, "manual", OPT_FREE|OPT_LOCAL, 0);
+ set_string_option_direct(kOptFoldmethod, "manual", OPT_FREE|OPT_LOCAL, 0);
curbuf->b_p_ts = 8; // 'tabstop' is 8.
curwin->w_p_list = false; // No list mode.
@@ -649,7 +649,7 @@ void fix_help_buffer(void)
// Set filetype to "help".
if (strcmp(curbuf->b_p_ft, "help") != 0) {
curbuf->b_ro_locked++;
- set_option_value_give_err("ft", STATIC_CSTR_AS_OPTVAL("help"), OPT_LOCAL);
+ set_option_value_give_err(kOptFiletype, STATIC_CSTR_AS_OPTVAL("help"), OPT_LOCAL);
curbuf->b_ro_locked--;
}
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 3bd4aa4f64..4add1e3591 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -1337,9 +1337,10 @@ void do_highlight(const char *line, const bool forceit, const bool init)
// wrong.
if (dark != -1
&& dark != (*p_bg == 'd')
- && !option_was_set("bg")) {
- set_option_value_give_err("bg", CSTR_AS_OPTVAL(dark ? "dark" : "light"), 0);
- reset_option_was_set("bg");
+ && !option_was_set(kOptBackground)) {
+ set_option_value_give_err(kOptBackground,
+ CSTR_AS_OPTVAL(dark ? "dark" : "light"), 0);
+ reset_option_was_set(kOptBackground);
}
}
}
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 5dced37b40..925317e7cb 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -1091,7 +1091,7 @@ void ex_retab(exarg_T *eap)
colnr_T *old_vts_ary = curbuf->b_p_vts_array;
if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1) {
- set_string_option_direct("vts", -1, new_ts_str, OPT_FREE | OPT_LOCAL, 0);
+ set_string_option_direct(kOptVartabstop, new_ts_str, OPT_FREE | OPT_LOCAL, 0);
curbuf->b_p_vts_array = new_vts_array;
xfree(old_vts_ary);
} else {
@@ -1115,7 +1115,7 @@ int get_expr_indent(void)
colnr_T save_curswant;
int save_set_curswant;
int save_State;
- int use_sandbox = was_set_insecurely(curwin, "indentexpr", OPT_LOCAL);
+ int use_sandbox = was_set_insecurely(curwin, kOptIndentexpr, OPT_LOCAL);
const sctx_T save_sctx = current_sctx;
// Save and restore cursor position and curswant, in case it was changed
diff --git a/src/nvim/log.c b/src/nvim/log.c
index a93dab6238..4370693f49 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -295,7 +295,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
FUNC_ATTR_PRINTF(7, 0)
{
// Name of the Nvim instance that produced the log.
- static char name[16] = { 0 };
+ static char name[32] = { 0 };
static const char *log_levels[] = {
[LOGLVL_DBG] = "DBG",
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index fd2bdbd677..e26e38f577 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -148,7 +148,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate)
}
} else {
if (tsize == 0
- || (tsize == ret.maxidx
+ || (tsize <= ret.maxidx
&& other_keys_num == 0
&& ret.string_keys_num == 0)) {
ret.type = kObjectTypeArray;
@@ -1129,10 +1129,6 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
}
const size_t idx = cur.obj->data.array.size++;
lua_rawgeti(lstate, -1, (int)idx + 1);
- if (lua_isnil(lstate, -1)) {
- lua_pop(lstate, 2);
- continue;
- }
kvi_push(stack, cur);
cur = (ObjPopStackItem) {
.obj = &cur.obj->data.array.items[idx],
@@ -1258,7 +1254,7 @@ handle_T nlua_pop_handle(lua_State *lstate, Error *err)
handle_T ret;
if (lua_type(lstate, -1) != LUA_TNUMBER) {
api_set_error(err, kErrorTypeValidation, "Expected Lua number");
- ret = (handle_T) - 1;
+ ret = (handle_T)(-1);
} else {
ret = (handle_T)lua_tonumber(lstate, -1);
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index d63a9a1307..e665732c1a 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -115,7 +115,7 @@ lua_State *get_global_lstate(void)
/// Convert lua error into a Vim error message
///
/// @param lstate Lua interpreter state.
-/// @param[in] msg Message base, must contain one `%*s`.
+/// @param[in] msg Message base, must contain one `%.*s`.
void nlua_error(lua_State *const lstate, const char *const msg)
FUNC_ATTR_NONNULL_ALL
{
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index d7a7abe3c8..fc2fedeaa1 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -536,11 +536,14 @@ static int nlua_iconv(lua_State *lstate)
return 1;
}
-// Like 'zx' but don't call newFoldLevel()
+// Update foldlevels (e.g., by evaluating 'foldexpr') for all lines in the current window without
+// invoking other side effects. Unlike `zx`, it does not close manually opened folds and does not
+// open folds under the cursor.
static int nlua_foldupdate(lua_State *lstate)
{
curwin->w_foldinvalid = true; // recompute folds
- foldOpenCursor();
+ foldUpdate(curwin, 1, (linenr_T)MAXLNUM);
+ curwin->w_foldinvalid = false;
return 0;
}
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 216e39f3e8..521d67a638 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -1123,7 +1123,7 @@ static void command_line_scan(mparm_T *parmp)
} else if (STRNICMP(argv[0] + argv_idx, "clean", 5) == 0) {
parmp->use_vimrc = "NONE";
parmp->clean = true;
- set_option_value_give_err("shadafile", STATIC_CSTR_AS_OPTVAL("NONE"), 0);
+ set_option_value_give_err(kOptShadafile, STATIC_CSTR_AS_OPTVAL("NONE"), 0);
} else if (STRNICMP(argv[0] + argv_idx, "luamod-dev", 9) == 0) {
nlua_disable_preload = true;
} else {
@@ -1137,7 +1137,7 @@ static void command_line_scan(mparm_T *parmp)
}
break;
case 'A': // "-A" start in Arabic mode.
- set_option_value_give_err("arabic", BOOLEAN_OPTVAL(true), 0);
+ set_option_value_give_err(kOptArabic, BOOLEAN_OPTVAL(true), 0);
break;
case 'b': // "-b" binary mode.
// Needs to be effective before expanding file names, because
@@ -1167,8 +1167,8 @@ static void command_line_scan(mparm_T *parmp)
usage();
os_exit(0);
case 'H': // "-H" start in Hebrew mode: rl + keymap=hebrew set.
- set_option_value_give_err("keymap", STATIC_CSTR_AS_OPTVAL("hebrew"), 0);
- set_option_value_give_err("rl", BOOLEAN_OPTVAL(true), 0);
+ set_option_value_give_err(kOptKeymap, STATIC_CSTR_AS_OPTVAL("hebrew"), 0);
+ set_option_value_give_err(kOptRightleft, BOOLEAN_OPTVAL(true), 0);
break;
case 'M': // "-M" no changes or writing of files
reset_modifiable();
@@ -1248,7 +1248,7 @@ static void command_line_scan(mparm_T *parmp)
// default is 10: a little bit verbose
p_verbose = get_number_arg(argv[0], &argv_idx, 10);
if (argv[0][argv_idx] != NUL) {
- set_option_value_give_err("verbosefile", CSTR_AS_OPTVAL(argv[0] + argv_idx), 0);
+ set_option_value_give_err(kOptVerbosefile, CSTR_AS_OPTVAL(argv[0] + argv_idx), 0);
argv_idx = (int)strlen(argv[0]);
}
break;
@@ -1256,7 +1256,7 @@ static void command_line_scan(mparm_T *parmp)
// "-w {scriptout}" write to script
if (ascii_isdigit((argv[0])[argv_idx])) {
n = get_number_arg(argv[0], &argv_idx, 10);
- set_option_value_give_err("window", NUMBER_OPTVAL((OptInt)n), 0);
+ set_option_value_give_err(kOptWindow, NUMBER_OPTVAL((OptInt)n), 0);
break;
}
want_argument = true;
@@ -1352,7 +1352,7 @@ static void command_line_scan(mparm_T *parmp)
break;
case 'i': // "-i {shada}" use for shada
- set_option_value_give_err("shadafile", CSTR_AS_OPTVAL(argv[0]), 0);
+ set_option_value_give_err(kOptShadafile, CSTR_AS_OPTVAL(argv[0]), 0);
break;
case 'l': // "-l" Lua script: args after "-l".
@@ -1362,7 +1362,7 @@ static void command_line_scan(mparm_T *parmp)
parmp->no_swap_file = true;
parmp->use_vimrc = parmp->use_vimrc ? parmp->use_vimrc : "NONE";
if (p_shadafile == NULL || *p_shadafile == NUL) {
- set_option_value_give_err("shadafile", STATIC_CSTR_AS_OPTVAL("NONE"), 0);
+ set_option_value_give_err(kOptShadafile, STATIC_CSTR_AS_OPTVAL("NONE"), 0);
}
parmp->luaf = argv[0];
argc--;
@@ -1398,7 +1398,7 @@ scripterror:
if (ascii_isdigit(*(argv[0]))) {
argv_idx = 0;
n = get_number_arg(argv[0], &argv_idx, 10);
- set_option_value_give_err("window", NUMBER_OPTVAL((OptInt)n), 0);
+ set_option_value_give_err(kOptWindow, NUMBER_OPTVAL((OptInt)n), 0);
argv_idx = -1;
break;
}
@@ -1549,7 +1549,7 @@ static void handle_quickfix(mparm_T *paramp)
{
if (paramp->edit_type == EDIT_QF) {
if (paramp->use_ef != NULL) {
- set_string_option_direct("ef", -1, paramp->use_ef, OPT_FREE, SID_CARG);
+ set_string_option_direct(kOptErrorfile, paramp->use_ef, OPT_FREE, SID_CARG);
}
vim_snprintf(IObuff, IOSIZE, "cfile %s", p_ef);
if (qf_init(NULL, p_ef, p_efm, true, IObuff, p_menc) < 0) {
@@ -1794,7 +1794,7 @@ static void edit_buffers(mparm_T *parmp, char *cwd)
p_shm_save = xstrdup(p_shm);
snprintf(buf, sizeof(buf), "F%s", p_shm);
- set_option_value_give_err("shm", CSTR_AS_OPTVAL(buf), 0);
+ set_option_value_give_err(kOptShortmess, CSTR_AS_OPTVAL(buf), 0);
}
} else {
if (curwin->w_next == NULL) { // just checking
@@ -1839,7 +1839,7 @@ static void edit_buffers(mparm_T *parmp, char *cwd)
}
if (p_shm_save != NULL) {
- set_option_value_give_err("shm", CSTR_AS_OPTVAL(p_shm_save), 0);
+ set_option_value_give_err(kOptShortmess, CSTR_AS_OPTVAL(p_shm_save), 0);
xfree(p_shm_save);
}
diff --git a/src/nvim/map.c b/src/nvim/map.c
index be6bf58daa..0011c97f9b 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -111,6 +111,9 @@ void mh_clear(MapHash *h)
#define VAL_NAME(x) quasiquote(x, String)
#include "nvim/map_value_impl.c.h"
#undef VAL_NAME
+#define VAL_NAME(x) quasiquote(x, SignRange)
+#include "nvim/map_value_impl.c.h"
+#undef VAL_NAME
#undef KEY_NAME
#define KEY_NAME(x) x##ptr_t
diff --git a/src/nvim/map_defs.h b/src/nvim/map_defs.h
index f3c4e4ea95..b85ba5acaf 100644
--- a/src/nvim/map_defs.h
+++ b/src/nvim/map_defs.h
@@ -48,6 +48,7 @@ static const uint64_t value_init_uint64_t = 0;
static const int64_t value_init_int64_t = 0;
static const String value_init_String = STRING_INIT;
static const ColorItem value_init_ColorItem = COLOR_ITEM_INITIALIZER;
+static const SignRange value_init_SignRange = SIGNRANGE_INIT;
// layer 0: type non-specific code
@@ -150,6 +151,7 @@ KEY_DECLS(uint32_t)
KEY_DECLS(String)
KEY_DECLS(HlEntry)
KEY_DECLS(ColorKey)
+KEY_DECLS(SignRange)
MAP_DECLS(int, int)
MAP_DECLS(int, ptr_t)
@@ -166,6 +168,7 @@ MAP_DECLS(uint32_t, uint32_t)
MAP_DECLS(String, int)
MAP_DECLS(int, String)
MAP_DECLS(ColorKey, ColorItem)
+MAP_DECLS(int, SignRange)
#define set_has(T, set, key) set_has_##T(set, key)
#define set_put(T, set, key) set_put_##T(set, key, NULL)
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 56544a9956..345ec45152 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -2199,7 +2199,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
Dictionary dict = mapblock_fill_dict(mp,
did_simplify ? keys_simplified : NULL,
buffer_local, abbr, true);
- (void)object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL);
+ object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL);
api_free_dictionary(dict);
} else {
// Return an empty dictionary.
@@ -2407,7 +2407,7 @@ void f_maplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
did_simplify ? keys_buf : NULL,
buffer_local, abbr, true);
typval_T d = TV_INITIAL_VALUE;
- (void)object_to_vim(DICTIONARY_OBJ(dict), &d, NULL);
+ object_to_vim(DICTIONARY_OBJ(dict), &d, NULL);
assert(d.v_type == VAR_DICT);
tv_list_append_dict(rettv->vval.v_list, d.vval.v_dict);
api_free_dictionary(dict);
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 5839cf7a2e..1e2462970f 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -1288,12 +1288,12 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount
if (posp->lnum == lnum && posp->col >= mincol) { \
posp->lnum += lnum_amount; \
assert(col_amount > INT_MIN && col_amount <= INT_MAX); \
- if (col_amount < 0 && posp->col <= (colnr_T) - col_amount) { \
+ if (col_amount < 0 && posp->col <= -col_amount) { \
posp->col = 0; \
} else if (posp->col < spaces_removed) { \
- posp->col = (int)col_amount + spaces_removed; \
+ posp->col = col_amount + spaces_removed; \
} else { \
- posp->col += (colnr_T)col_amount; \
+ posp->col += col_amount; \
} \
} \
}
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index f14da1b605..fa5e7dcbe2 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -50,15 +50,15 @@
#include <sys/types.h>
#include "klib/kvec.h"
-#include "nvim/garray.h"
+#include "nvim/macros_defs.h"
+#include "nvim/map_defs.h"
#include "nvim/marktree.h"
#include "nvim/memory.h"
#include "nvim/pos_defs.h"
// only for debug functions
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/garray_defs.h"
-#include "nvim/macros_defs.h"
+#include "nvim/garray.h"
#define T MT_BRANCH_FACTOR
#define ILEN (sizeof(MTNode) + (2 * T) * sizeof(void *))
@@ -2200,7 +2200,12 @@ String mt_inspect(MarkTree *b, bool keys, bool dot)
return ga_take_string(ga);
}
-void mt_inspect_node(MarkTree *b, garray_T *ga, bool keys, MTNode *n, MTPos off)
+static inline uint64_t mt_dbg_id(uint64_t id)
+{
+ return (id >> 1) & 0xffffffff;
+}
+
+static void mt_inspect_node(MarkTree *b, garray_T *ga, bool keys, MTNode *n, MTPos off)
{
static char buf[1024];
GA_PUT("[");
@@ -2240,7 +2245,7 @@ void mt_inspect_node(MarkTree *b, garray_T *ga, bool keys, MTNode *n, MTPos off)
ga_concat(ga, "]");
}
-void mt_inspect_dotfile_node(MarkTree *b, garray_T *ga, MTNode *n, MTPos off, char *parent)
+static void mt_inspect_dotfile_node(MarkTree *b, garray_T *ga, MTNode *n, MTPos off, char *parent)
{
static char buf[1024];
char namebuf[64];
diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h
index c76359d3f9..46d60a2b69 100644
--- a/src/nvim/marktree.h
+++ b/src/nvim/marktree.h
@@ -1,69 +1,15 @@
#pragma once
#include <stdbool.h>
-#include <stddef.h>
+#include <stddef.h> // IWYU pragma: keep
#include <stdint.h>
-#include "klib/kvec.h"
#include "nvim/decoration_defs.h"
-#include "nvim/garray_defs.h" // IWYU pragma: keep
-#include "nvim/map_defs.h"
+#include "nvim/marktree_defs.h" // IWYU pragma: export
#include "nvim/pos_defs.h" // IWYU pragma: keep
// only for debug functions:
#include "nvim/api/private/defs.h" // IWYU pragma: keep
-#define MT_MAX_DEPTH 20
-#define MT_BRANCH_FACTOR 10
-// note max branch is actually 2*MT_BRANCH_FACTOR
-// and strictly this is ceil(log2(2*MT_BRANCH_FACTOR + 1))
-// as we need a pseudo-index for "right before this node"
-#define MT_LOG2_BRANCH 5
-
-typedef struct {
- int32_t row;
- int32_t col;
-} MTPos;
-#define MTPos(r, c) ((MTPos){ .row = (r), .col = (c) })
-
-typedef struct mtnode_s MTNode;
-
-typedef struct {
- MTPos pos;
- int lvl;
- MTNode *x;
- int i;
- struct {
- int oldcol;
- int i;
- } s[MT_MAX_DEPTH];
-
- size_t intersect_idx;
- MTPos intersect_pos;
- MTPos intersect_pos_x;
-} MarkTreeIter;
-
-#define marktree_itr_valid(itr) ((itr)->x != NULL)
-// access raw key: flags in MT_FLAG_EXTERNAL_MASK and decor_data are safe to modify.
-#define mt_itr_rawkey(itr) ((itr)->x->key[(itr)->i])
-
-// Internal storage
-//
-// NB: actual marks have flags > 0, so we can use (row,col,0) pseudo-key for
-// "space before (row,col)"
-typedef struct {
- MTPos pos;
- uint32_t ns;
- uint32_t id;
- uint16_t flags;
- DecorInlineData decor_data; // "ext" tag in flags
-} MTKey;
-
-typedef struct {
- MTKey start;
- MTPos end_pos;
- bool end_right_gravity;
-} MTPair;
-
#define MT_INVALID_KEY (MTKey) { { -1, -1 }, 0, 0, 0, { .hl = DECOR_HIGHLIGHT_INLINE_INIT } }
#define MT_FLAG_REAL (((uint16_t)1) << 0)
@@ -179,31 +125,6 @@ static inline DecorInline mt_decor(MTKey key)
return (DecorInline){ .ext = key.flags & MT_FLAG_DECOR_EXT, .data = key.decor_data };
}
-typedef kvec_withinit_t(uint64_t, 4) Intersection;
-
-struct mtnode_s {
- int32_t n;
- int16_t level;
- int16_t p_idx; // index in parent
- Intersection intersect;
- // TODO(bfredl): we could consider having a only-sometimes-valid
- // index into parent for faster "cached" lookup.
- MTNode *parent;
- MTKey key[2 * MT_BRANCH_FACTOR - 1];
- MTNode *ptr[];
-};
-
-static inline uint64_t mt_dbg_id(uint64_t id)
-{
- return (id>>1)&0xffffffff;
-}
-
-typedef struct {
- MTNode *root;
- size_t n_keys, n_nodes;
- PMap(uint64_t) id2node[1];
-} MarkTree;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "marktree.h.generated.h"
#endif
diff --git a/src/nvim/marktree_defs.h b/src/nvim/marktree_defs.h
new file mode 100644
index 0000000000..8aa1b1e376
--- /dev/null
+++ b/src/nvim/marktree_defs.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "klib/kvec.h"
+#include "nvim/decoration_defs.h"
+#include "nvim/map_defs.h"
+
+enum {
+ MT_MAX_DEPTH = 20,
+ MT_BRANCH_FACTOR = 10,
+ // note max branch is actually 2*MT_BRANCH_FACTOR
+ // and strictly this is ceil(log2(2*MT_BRANCH_FACTOR + 1))
+ // as we need a pseudo-index for "right before this node"
+ MT_LOG2_BRANCH = 5,
+};
+
+typedef struct {
+ int32_t row;
+ int32_t col;
+} MTPos;
+#define MTPos(r, c) ((MTPos){ .row = (r), .col = (c) })
+
+typedef struct mtnode_s MTNode;
+
+typedef struct {
+ MTPos pos;
+ int lvl;
+ MTNode *x;
+ int i;
+ struct {
+ int oldcol;
+ int i;
+ } s[MT_MAX_DEPTH];
+
+ size_t intersect_idx;
+ MTPos intersect_pos;
+ MTPos intersect_pos_x;
+} MarkTreeIter;
+
+#define marktree_itr_valid(itr) ((itr)->x != NULL)
+// access raw key: flags in MT_FLAG_EXTERNAL_MASK and decor_data are safe to modify.
+#define mt_itr_rawkey(itr) ((itr)->x->key[(itr)->i])
+
+// Internal storage
+//
+// NB: actual marks have flags > 0, so we can use (row,col,0) pseudo-key for
+// "space before (row,col)"
+typedef struct {
+ MTPos pos;
+ uint32_t ns;
+ uint32_t id;
+ uint16_t flags;
+ DecorInlineData decor_data; // "ext" tag in flags
+} MTKey;
+
+typedef struct {
+ MTKey start;
+ MTPos end_pos;
+ bool end_right_gravity;
+} MTPair;
+
+typedef kvec_withinit_t(uint64_t, 4) Intersection;
+
+struct mtnode_s {
+ int32_t n;
+ int16_t level;
+ int16_t p_idx; // index in parent
+ Intersection intersect;
+ // TODO(bfredl): we could consider having a only-sometimes-valid
+ // index into parent for faster "cached" lookup.
+ MTNode *parent;
+ MTKey key[2 * MT_BRANCH_FACTOR - 1];
+ MTNode *ptr[];
+};
+
+typedef struct {
+ MTNode *root;
+ size_t n_keys, n_nodes;
+ PMap(uint64_t) id2node[1];
+} MarkTree;
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 709c7f3d40..38ac3b7bcf 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -974,7 +974,7 @@ void ml_recover(bool checkext)
set_fileformat(b0_ff - 1, OPT_LOCAL);
}
if (b0_fenc != NULL) {
- set_option_value_give_err("fenc", CSTR_AS_OPTVAL(b0_fenc), OPT_LOCAL);
+ set_option_value_give_err(kOptFileencoding, CSTR_AS_OPTVAL(b0_fenc), OPT_LOCAL);
xfree(b0_fenc);
}
unchanged(curbuf, true, true);
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 219532e45e..b9935d5b5d 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -2833,7 +2833,7 @@ static int do_more_prompt(int typed_char)
} else {
// redisplay all lines
// TODO(bfredl): this case is not optimized (though only concerns
- // event fragmentization, not unnecessary scroll events).
+ // event fragmentation, not unnecessary scroll events).
grid_fill(&msg_grid_adj, 0, Rows, 0, Columns, ' ', ' ',
HL_ATTR(HLF_MSG));
for (int i = 0; mp != NULL && i < Rows - 1; i++) {
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 227d064a27..12fb7d1f82 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -760,7 +760,7 @@ int win_col_off(win_T *wp)
return ((wp->w_p_nu || wp->w_p_rnu || *wp->w_p_stc != NUL)
? (number_width(wp) + (*wp->w_p_stc == NUL)) : 0)
+ ((cmdwin_type == 0 || wp != curwin) ? 0 : 1)
- + win_fdccol_count(wp) + (win_signcol_count(wp) * SIGN_WIDTH);
+ + win_fdccol_count(wp) + (wp->w_scwidth * SIGN_WIDTH);
}
int curwin_col_off(void)
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 3a4e87edf7..16aa46e97d 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -4630,13 +4630,13 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
if (!pre) {
if (subtract) {
if (n > oldn) {
- n = 1 + (n ^ (uvarnumber_T) - 1);
+ n = 1 + (n ^ (uvarnumber_T)(-1));
negative ^= true;
}
} else {
// add
if (n < oldn) {
- n = (n ^ (uvarnumber_T) - 1);
+ n = (n ^ (uvarnumber_T)(-1));
negative ^= true;
}
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index ba9d1262d4..6aa22c19af 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -156,19 +156,19 @@ typedef enum {
# include "options.generated.h"
#endif
-static char *(p_bin_dep_opts[]) = {
- "textwidth", "wrapmargin", "modeline", "expandtab", NULL
+static int p_bin_dep_opts[] = {
+ kOptTextwidth, kOptWrapmargin, kOptModeline, kOptExpandtab, kOptInvalid
};
-static char *(p_paste_dep_opts[]) = {
- "autoindent", "expandtab", "ruler", "showmatch", "smarttab",
- "softtabstop", "textwidth", "wrapmargin", "revins", "varsofttabstop", NULL
+
+static int p_paste_dep_opts[] = {
+ kOptAutoindent, kOptExpandtab, kOptRuler, kOptShowmatch, kOptSmarttab, kOptSofttabstop,
+ kOptTextwidth, kOptWrapmargin, kOptRevins, kOptVarsofttabstop, kOptInvalid
};
void set_init_tablocal(void)
{
// susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal!
- int ch_idx = findoption("cmdheight");
- p_ch = (OptInt)(intptr_t)options[ch_idx].def_val;
+ p_ch = (OptInt)(intptr_t)options[kOptCmdheight].def_val;
}
/// Initialize the 'shell' option to a default value.
@@ -182,9 +182,9 @@ static void set_init_default_shell(void)
const size_t len = strlen(shell) + 3; // two quotes and a trailing NUL
char *const cmd = xmalloc(len);
snprintf(cmd, len, "\"%s\"", shell);
- set_string_default("sh", cmd, true);
+ set_string_default(kOptShell, cmd, true);
} else {
- set_string_default("sh", (char *)shell, false);
+ set_string_default(kOptShell, (char *)shell, false);
}
}
}
@@ -199,7 +199,7 @@ static void set_init_default_backupskip(void)
static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" };
#endif
garray_T ga;
- int opt_idx = findoption("backupskip");
+ OptIndex opt_idx = kOptBackupskip;
ga_init(&ga, 1, 100);
for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
@@ -243,7 +243,7 @@ static void set_init_default_backupskip(void)
}
}
if (ga.ga_data != NULL) {
- set_string_default("bsk", ga.ga_data, true);
+ set_string_default(kOptBackupskip, ga.ga_data, true);
}
}
@@ -269,8 +269,8 @@ static void set_init_default_cdpath(void)
}
}
buf[j] = NUL;
- int opt_idx = findoption("cdpath");
- if (opt_idx >= 0) {
+ OptIndex opt_idx = kOptCdpath;
+ if (opt_idx != kOptInvalid) {
options[opt_idx].def_val = buf;
options[opt_idx].flags |= P_DEF_ALLOCED;
} else {
@@ -288,7 +288,7 @@ static void set_init_default_cdpath(void)
/// default.
static void set_init_expand_env(void)
{
- for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
vimoption_T *opt = &options[opt_idx];
if (opt->flags & P_NO_DEF_EXP) {
continue;
@@ -346,20 +346,20 @@ void set_init_1(bool clean_arg)
backupdir = xrealloc(backupdir, backupdir_len + 3);
memmove(backupdir + 2, backupdir, backupdir_len + 1);
memmove(backupdir, ".,", 2);
- set_string_default("backupdir", backupdir, true);
- set_string_default("viewdir", stdpaths_user_state_subpath("view", 2, true),
+ set_string_default(kOptBackupdir, backupdir, true);
+ set_string_default(kOptViewdir, stdpaths_user_state_subpath("view", 2, true),
true);
- set_string_default("directory", stdpaths_user_state_subpath("swap", 2, true),
+ set_string_default(kOptDirectory, stdpaths_user_state_subpath("swap", 2, true),
true);
- set_string_default("undodir", stdpaths_user_state_subpath("undo", 2, true),
+ set_string_default(kOptUndodir, stdpaths_user_state_subpath("undo", 2, true),
true);
// Set default for &runtimepath. All necessary expansions are performed in
// this function.
char *rtp = runtimepath_default(clean_arg);
if (rtp) {
- set_string_default("runtimepath", rtp, true);
+ set_string_default(kOptRuntimepath, rtp, true);
// Make a copy of 'rtp' for 'packpath'
- set_string_default("packpath", rtp, false);
+ set_string_default(kOptPackpath, rtp, false);
rtp = NULL; // ownership taken
}
@@ -398,7 +398,7 @@ void set_init_1(bool clean_arg)
// NOTE: mlterm's author is being asked to 'set' a variable
// instead of an environment variable due to inheritance.
if (os_env_exists("MLTERM")) {
- set_option_value_give_err("tbidi", BOOLEAN_OPTVAL(true), 0);
+ set_option_value_give_err(kOptTermbidi, BOOLEAN_OPTVAL(true), 0);
}
didset_options2();
@@ -420,7 +420,7 @@ void set_init_1(bool clean_arg)
/// This does not take care of side effects!
///
/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
-static void set_option_default(const int opt_idx, int opt_flags)
+static void set_option_default(const OptIndex opt_idx, int opt_flags)
{
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
@@ -430,10 +430,10 @@ static void set_option_default(const int opt_idx, int opt_flags)
uint32_t flags = opt->flags;
if (varp != NULL) { // skip hidden option, nothing to do for it
if (flags & P_STRING) {
- // Use set_string_option_direct() for local options to handle
- // freeing and allocating the value.
+ // Use set_string_option_direct() for local options to handle freeing and allocating the
+ // value.
if (opt->indir != PV_NONE) {
- set_string_option_direct(NULL, opt_idx, opt->def_val, opt_flags, 0);
+ set_string_option_direct(opt_idx, opt->def_val, opt_flags, 0);
} else {
if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) {
free_string_option(*(char **)(varp));
@@ -479,7 +479,7 @@ static void set_option_default(const int opt_idx, int opt_flags)
*flagsp = *flagsp & ~P_INSECURE;
}
- set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+ set_option_sctx(opt_idx, opt_flags, current_sctx);
}
/// Set all options (except terminal options) to their default value.
@@ -487,9 +487,9 @@ static void set_option_default(const int opt_idx, int opt_flags)
/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
static void set_options_default(int opt_flags)
{
- for (int i = 0; options[i].fullname; i++) {
- if (!(options[i].flags & P_NODEFAULT)) {
- set_option_default(i, opt_flags);
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ if (!(options[opt_idx].flags & P_NODEFAULT)) {
+ set_option_default(opt_idx, opt_flags);
}
}
@@ -504,22 +504,23 @@ static void set_options_default(int opt_flags)
/// Set the Vi-default value of a string option.
/// Used for 'sh', 'backupskip' and 'term'.
///
-/// @param name The name of the option
-/// @param val The value of the option
-/// @param allocated If true, do not copy default as it was already allocated.
-static void set_string_default(const char *name, char *val, bool allocated)
+/// @param opt_idx Option index in options[] table.
+/// @param val The value of the option.
+/// @param allocated If true, do not copy default as it was already allocated.
+static void set_string_default(OptIndex opt_idx, char *val, bool allocated)
FUNC_ATTR_NONNULL_ALL
{
- int opt_idx = findoption(name);
- if (opt_idx >= 0) {
- vimoption_T *opt = &options[opt_idx];
- if (opt->flags & P_DEF_ALLOCED) {
- xfree(opt->def_val);
- }
+ if (opt_idx == kOptInvalid) {
+ return;
+ }
- opt->def_val = allocated ? val : xstrdup(val);
- opt->flags |= P_DEF_ALLOCED;
+ vimoption_T *opt = &options[opt_idx];
+ if (opt->flags & P_DEF_ALLOCED) {
+ xfree(opt->def_val);
}
+
+ opt->def_val = allocated ? val : xstrdup(val);
+ opt->flags |= P_DEF_ALLOCED;
}
/// For an option value that contains comma separated items, find "newval" in
@@ -555,10 +556,9 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
/// Set the Vi-default value of a number option.
/// Used for 'lines' and 'columns'.
-void set_number_default(char *name, OptInt val)
+void set_number_default(OptIndex opt_idx, OptInt val)
{
- int opt_idx = findoption(name);
- if (opt_idx >= 0) {
+ if (opt_idx != kOptInvalid) {
options[opt_idx].def_val = (void *)(intptr_t)val;
}
}
@@ -567,18 +567,18 @@ void set_number_default(char *name, OptInt val)
/// Free all options.
void free_all_options(void)
{
- for (int i = 0; options[i].fullname; i++) {
- if (options[i].indir == PV_NONE) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ if (options[opt_idx].indir == PV_NONE) {
// global option: free value and default value.
- if ((options[i].flags & P_ALLOCED) && options[i].var != NULL) {
- optval_free(optval_from_varp(i, options[i].var));
+ if ((options[opt_idx].flags & P_ALLOCED) && options[opt_idx].var != NULL) {
+ optval_free(optval_from_varp(opt_idx, options[opt_idx].var));
}
- if (options[i].flags & P_DEF_ALLOCED) {
- optval_free(optval_from_varp(i, &options[i].def_val));
+ if (options[opt_idx].flags & P_DEF_ALLOCED) {
+ optval_free(optval_from_varp(opt_idx, &options[opt_idx].def_val));
}
- } else if (options[i].var != VAR_WIN) {
+ } else if (options[opt_idx].var != VAR_WIN) {
// buffer-local option: free global value
- optval_free(optval_from_varp(i, options[i].var));
+ optval_free(optval_from_varp(opt_idx, options[opt_idx].var));
}
}
free_operatorfunc_option();
@@ -597,18 +597,17 @@ void set_init_2(bool headless)
// 'scroll' defaults to half the window height. The stored default is zero,
// which results in the actual value computed from the window height.
- int idx = findoption("scroll");
- if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) {
- set_option_default(idx, OPT_LOCAL);
+ if (!(options[kOptScroll].flags & P_WAS_SET)) {
+ set_option_default(kOptScroll, OPT_LOCAL);
}
comp_col();
// 'window' is only for backwards compatibility with Vi.
// Default is Rows - 1.
- if (!option_was_set("window")) {
+ if (!option_was_set(kOptWindow)) {
p_window = Rows - 1;
}
- set_number_default("window", Rows - 1);
+ set_number_default(kOptWindow, Rows - 1);
}
/// Initialize the options, part three: After reading the .vimrc
@@ -619,14 +618,8 @@ void set_init_3(void)
// Set 'shellpipe' and 'shellredir', depending on the 'shell' option.
// This is done after other initializations, where 'shell' might have been
// set, but only if they have not been set before.
- int idx_srr = findoption("srr");
- int do_srr = (idx_srr < 0)
- ? false
- : !(options[idx_srr].flags & P_WAS_SET);
- int idx_sp = findoption("sp");
- int do_sp = (idx_sp < 0)
- ? false
- : !(options[idx_sp].flags & P_WAS_SET);
+ int do_srr = !(options[kOptShellredir].flags & P_WAS_SET);
+ int do_sp = !(options[kOptShellpipe].flags & P_WAS_SET);
size_t len = 0;
char *p = (char *)invocation_path_tail(p_sh, &len);
@@ -641,11 +634,11 @@ void set_init_3(void)
|| path_fnamecmp(p, "tcsh") == 0) {
if (do_sp) {
p_sp = "|& tee";
- options[idx_sp].def_val = p_sp;
+ options[kOptShellpipe].def_val = p_sp;
}
if (do_srr) {
p_srr = ">&";
- options[idx_srr].def_val = p_srr;
+ options[kOptShellredir].def_val = p_srr;
}
} else if (path_fnamecmp(p, "sh") == 0
|| path_fnamecmp(p, "ksh") == 0
@@ -660,11 +653,11 @@ void set_init_3(void)
// Always use POSIX shell style redirection if we reach this
if (do_sp) {
p_sp = "2>&1| tee";
- options[idx_sp].def_val = p_sp;
+ options[kOptShellpipe].def_val = p_sp;
}
if (do_srr) {
p_srr = ">%s 2>&1";
- options[idx_srr].def_val = p_srr;
+ options[kOptShellredir].def_val = p_srr;
}
}
xfree(p);
@@ -694,12 +687,11 @@ void set_helplang_default(const char *lang)
if (lang_len < 2) { // safety check
return;
}
- int idx = findoption("hlg");
- if (idx < 0 || (options[idx].flags & P_WAS_SET)) {
+ if (options[kOptHelplang].flags & P_WAS_SET) {
return;
}
- if (options[idx].flags & P_ALLOCED) {
+ if (options[kOptHelplang].flags & P_ALLOCED) {
free_string_option(p_hlg);
}
p_hlg = xmemdupz(lang, lang_len);
@@ -713,7 +705,7 @@ void set_helplang_default(const char *lang)
p_hlg[1] = 'n';
}
p_hlg[2] = NUL;
- options[idx].flags |= P_ALLOCED;
+ options[kOptHelplang].flags |= P_ALLOCED;
}
/// 'title' and 'icon' only default to true if they have not been set or reset
@@ -726,14 +718,12 @@ void set_title_defaults(void)
// If GUI is (going to be) used, we can always set the window title and
// icon name. Saves a bit of time, because the X11 display server does
// not need to be contacted.
- int idx1 = findoption("title");
- if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) {
- options[idx1].def_val = 0;
+ if (!(options[kOptTitle].flags & P_WAS_SET)) {
+ options[kOptTitle].def_val = 0;
p_title = 0;
}
- idx1 = findoption("icon");
- if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) {
- options[idx1].def_val = 0;
+ if (!(options[kOptIcon].flags & P_WAS_SET)) {
+ options[kOptIcon].def_val = 0;
p_icon = 0;
}
}
@@ -754,7 +744,7 @@ void ex_set(exarg_T *eap)
}
/// Get the default value for a string option.
-static char *stropt_get_default_val(int opt_idx, uint64_t flags)
+static char *stropt_get_default_val(OptIndex opt_idx, uint64_t flags)
{
char *newval = options[opt_idx].def_val;
// expand environment variables and ~ since the default value was
@@ -775,8 +765,7 @@ static char *stropt_get_default_val(int opt_idx, uint64_t flags)
}
/// Copy the new string value into allocated memory for the option.
-/// Can't use set_string_option_direct(), because we need to remove the
-/// backslashes.
+/// Can't use set_string_option_direct(), because we need to remove the backslashes.
static char *stropt_copy_value(char *origval, char **argp, set_op_T op,
uint32_t flags FUNC_ATTR_UNUSED)
{
@@ -824,7 +813,7 @@ static char *stropt_copy_value(char *origval, char **argp, set_op_T op,
}
/// Expand environment variables and ~ in string option value 'newval'.
-static char *stropt_expand_envvar(int opt_idx, char *origval, char *newval, set_op_T op)
+static char *stropt_expand_envvar(OptIndex opt_idx, char *origval, char *newval, set_op_T op)
{
char *s = option_expand(opt_idx, newval);
if (s == NULL) {
@@ -924,8 +913,8 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags)
/// set {opt}<
/// set {opt}={val}
/// set {opt}:{val}
-static char *stropt_get_newval(int nextchar, int opt_idx, char **argp, void *varp, char *origval,
- set_op_T *op_arg, uint32_t flags)
+static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void *varp,
+ char *origval, set_op_T *op_arg, uint32_t flags)
{
char *arg = *argp;
set_op_T op = *op_arg;
@@ -1031,15 +1020,15 @@ static set_prefix_T get_option_prefix(char **argp)
/// @param[out] keyp
/// @param[out] len Length of option name
/// @return FAIL if an error is detected, OK otherwise
-static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp)
+static int parse_option_name(char *arg, int *keyp, int *lenp, OptIndex *opt_idxp)
{
// find end of name
int key = 0;
int len;
- int opt_idx;
+ OptIndex opt_idx;
if (*arg == '<') {
- opt_idx = -1;
+ opt_idx = kOptInvalid;
// look out for <t_>;>
if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) {
len = 5;
@@ -1056,7 +1045,7 @@ static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp)
opt_idx = findoption_len(arg + 1, (size_t)(len - 1));
}
len++;
- if (opt_idx == -1) {
+ if (opt_idx == kOptInvalid) {
key = find_key_option(arg + 1, true);
}
} else {
@@ -1070,7 +1059,7 @@ static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp)
}
}
opt_idx = findoption_len(arg, (size_t)len);
- if (opt_idx == -1) {
+ if (opt_idx == kOptInvalid) {
key = find_key_option(arg, false);
}
}
@@ -1082,7 +1071,7 @@ static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp)
return OK;
}
-static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t flags,
+static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_t flags,
set_prefix_T prefix, const char **errmsg)
{
// Only bools can have a prefix of 'inv' or 'no'
@@ -1094,12 +1083,12 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla
// Skip all options that are not window-local (used when showing
// an already loaded buffer in a window).
if ((opt_flags & OPT_WINONLY)
- && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) {
+ && (opt_idx == kOptInvalid || options[opt_idx].var != VAR_WIN)) {
return FAIL;
}
// Skip all options that are window-local (used for :vimgrep).
- if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
+ if ((opt_flags & OPT_NOWIN) && opt_idx != kOptInvalid
&& options[opt_idx].var == VAR_WIN) {
return FAIL;
}
@@ -1118,7 +1107,7 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla
// 'foldmethod' becomes "marker" instead of "diff" and that
// "wrap" gets set.
if (win->w_p_diff
- && opt_idx >= 0 // shut up coverity warning
+ && opt_idx != kOptInvalid // shut up coverity warning
&& (options[opt_idx].indir == PV_FDM
|| options[opt_idx].indir == PV_WRAP)) {
return FAIL;
@@ -1135,7 +1124,7 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla
}
/// Get new option value from argp. Allocated OptVal must be freed by caller.
-static OptVal get_option_newval(int opt_idx, int opt_flags, set_prefix_T prefix, char **argp,
+static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T prefix, char **argp,
int nextchar, set_op_T op, uint32_t flags, void *varp, char *errbuf,
const size_t errbuflen, const char **errmsg)
FUNC_ATTR_WARN_UNUSED_RESULT
@@ -1275,7 +1264,7 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
// find end of name
int key = 0;
int len;
- int opt_idx;
+ OptIndex opt_idx;
if (parse_option_name(arg, &key, &len, &opt_idx) == FAIL) {
*errmsg = e_invarg;
return;
@@ -1296,7 +1285,7 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
uint8_t nextchar = (uint8_t)arg[len]; // next non-white char after option name
- if (opt_idx == -1 && key == 0) { // found a mismatch: skip
+ if (opt_idx == kOptInvalid && key == 0) { // found a mismatch: skip
*errmsg = e_unknown_option;
return;
}
@@ -1304,7 +1293,7 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
uint32_t flags; // flags for current option
void *varp = NULL; // pointer to variable for current option
- if (opt_idx >= 0) {
+ if (opt_idx != kOptInvalid) {
if (options[opt_idx].var == NULL) { // hidden option: skip
// Only give an error message when requesting the value of
// a hidden option, ignore setting it.
@@ -1357,7 +1346,7 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
gotocmdline(true); // cursor at status line
*did_show = true; // remember that we did a line
}
- if (opt_idx >= 0) {
+ if (opt_idx != kOptInvalid) {
showoneopt(&options[opt_idx], opt_flags);
if (p_verbose > 0) {
// Mention where the option was last set.
@@ -1625,7 +1614,7 @@ char *find_shada_parameter(int type)
/// These string options cannot be indirect!
/// If "val" is NULL expand the current value of the option.
/// Return pointer to NameBuff, or NULL when not expanded.
-static char *option_expand(int opt_idx, char *val)
+static char *option_expand(OptIndex opt_idx, char *val)
{
// if option doesn't need expansion nothing to do
if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) {
@@ -1700,33 +1689,33 @@ static void didset_options2(void)
/// Check for string options that are NULL (normally only termcap options).
void check_options(void)
{
- for (int opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
if ((options[opt_idx].flags & P_STRING) && options[opt_idx].var != NULL) {
check_string_option((char **)get_varp(&(options[opt_idx])));
}
}
}
-/// Return true when option "opt" was set from a modeline or in secure mode.
-/// Return false when it wasn't.
-/// Return -1 for an unknown option.
-int was_set_insecurely(win_T *const wp, char *opt, int opt_flags)
+/// Check if option was set insecurely.
+///
+/// @param wp Window.
+/// @param opt_idx Option index in options[] table.
+/// @param opt_flags Option flags.
+///
+/// @return True if option was set from a modeline or in secure mode, false if it wasn't.
+int was_set_insecurely(win_T *const wp, OptIndex opt_idx, int opt_flags)
{
- int idx = findoption(opt);
+ assert(opt_idx != kOptInvalid);
- if (idx >= 0) {
- uint32_t *flagp = insecure_flag(wp, idx, opt_flags);
- return (*flagp & P_INSECURE) != 0;
- }
- internal_error("was_set_insecurely()");
- return -1;
+ uint32_t *flagp = insecure_flag(wp, opt_idx, opt_flags);
+ return (*flagp & P_INSECURE) != 0;
}
/// Get a pointer to the flags used for the P_INSECURE flag of option
/// "opt_idx". For some local options a local flags field is used.
/// NOTE: Caller must make sure that "wp" is set to the window from which
/// the option is used.
-uint32_t *insecure_flag(win_T *const wp, int opt_idx, int opt_flags)
+uint32_t *insecure_flag(win_T *const wp, OptIndex opt_idx, int opt_flags)
{
if (opt_flags & OPT_LOCAL) {
assert(wp != NULL);
@@ -1829,21 +1818,16 @@ bool parse_winhl_opt(win_T *wp)
return true;
}
-/// Get the script context of global option "name".
-sctx_T *get_option_sctx(const char *const name)
+/// Get the script context of global option at index opt_idx.
+sctx_T *get_option_sctx(OptIndex opt_idx)
{
- int idx = findoption(name);
-
- if (idx >= 0) {
- return &options[idx].last_set.script_ctx;
- }
- siemsg("no such option: %s", name);
- return NULL;
+ assert(opt_idx != kOptInvalid);
+ return &options[opt_idx].last_set.script_ctx;
}
/// Set the script_ctx for an option, taking care of setting the buffer- or
/// window-local value.
-void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
+void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx)
{
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
int indir = (int)options[opt_idx].indir;
@@ -1877,7 +1861,7 @@ void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
}
/// Apply the OptionSet autocommand.
-static void apply_optionset_autocmd(int opt_idx, int opt_flags, OptVal oldval, OptVal oldval_g,
+static void apply_optionset_autocmd(OptIndex opt_idx, int opt_flags, OptVal oldval, OptVal oldval_g,
OptVal oldval_l, OptVal newval, const char *errmsg)
{
// Don't do this while starting up, failure or recursively.
@@ -1952,7 +1936,7 @@ static const char *did_set_arabic(optset_T *args)
p_deco = true;
// Force-set the necessary keymap for arabic.
- errmsg = set_option_value("keymap", STATIC_CSTR_AS_OPTVAL("arabic"), OPT_LOCAL);
+ errmsg = set_option_value(kOptKeymap, STATIC_CSTR_AS_OPTVAL("arabic"), OPT_LOCAL);
} else {
// 'arabic' is reset, handle various sub-settings.
if (!p_tbidi) {
@@ -2809,7 +2793,7 @@ static const char *check_num_option_bounds(OptInt *pp, OptInt old_value, char *e
cmdline_row = new_row;
}
}
- if (p_window >= Rows || !option_was_set("window")) {
+ if (p_window >= Rows || !option_was_set(kOptWindow)) {
p_window = Rows - 1;
}
}
@@ -3029,8 +3013,8 @@ void check_redraw(uint32_t flags)
/// @param[in] arg Option to find index for.
/// @param[in] len Length of the option.
///
-/// @return Index of the option or -1 if option was not found.
-int findoption_len(const char *const arg, const size_t len)
+/// @return Index of the option or kOptInvalid if option was not found.
+OptIndex findoption_len(const char *const arg, const size_t len)
{
const char *s;
static int quick_tab[27] = { 0, 0 }; // quick access table
@@ -3040,7 +3024,9 @@ int findoption_len(const char *const arg, const size_t len)
// letter. There are 26 letters, plus the first "t_" option.
if (quick_tab[1] == 0) {
const char *p = options[0].fullname;
- for (uint16_t i = 1; (s = options[i].fullname) != NULL; i++) {
+ for (OptIndex i = 1; i < kOptIndexCount; i++) {
+ s = options[i].fullname;
+
if (s[0] != p[0]) {
if (s[0] == 't' && s[1] == '_') {
quick_tab[26] = i;
@@ -3054,10 +3040,10 @@ int findoption_len(const char *const arg, const size_t len)
// Check for name starting with an illegal character.
if (len == 0 || arg[0] < 'a' || arg[0] > 'z') {
- return -1;
+ return kOptInvalid;
}
- int opt_idx;
+ OptIndex opt_idx;
const bool is_term_opt = (len > 2 && arg[0] == 't' && arg[1] == '_');
if (is_term_opt) {
opt_idx = quick_tab[26];
@@ -3065,24 +3051,31 @@ int findoption_len(const char *const arg, const size_t len)
opt_idx = quick_tab[CHAR_ORD_LOW(arg[0])];
}
// Match full name
- for (; (s = options[opt_idx].fullname) != NULL; opt_idx++) {
+ for (; opt_idx < kOptIndexCount; opt_idx++) {
+ s = options[opt_idx].fullname;
+
+ // Break if first character no longer matches.
+ if (s[0] != arg[0]) {
+ opt_idx = kOptIndexCount;
+ break;
+ }
+
if (strncmp(arg, s, len) == 0 && s[len] == NUL) {
break;
}
}
- if (s == NULL && !is_term_opt) {
+ if (opt_idx == kOptIndexCount && !is_term_opt) {
opt_idx = quick_tab[CHAR_ORD_LOW(arg[0])];
// Match short name
- for (; options[opt_idx].fullname != NULL; opt_idx++) {
+ for (; opt_idx < kOptIndexCount; opt_idx++) {
s = options[opt_idx].shortname;
if (s != NULL && strncmp(arg, s, len) == 0 && s[len] == NUL) {
break;
}
- s = NULL;
}
}
- if (s == NULL) {
- opt_idx = -1;
+ if (opt_idx == kOptIndexCount) {
+ opt_idx = kOptInvalid;
} else {
// Nvim: handle option aliases.
if (strncmp(options[opt_idx].fullname, "viminfo", 7) == 0) {
@@ -3099,51 +3092,36 @@ int findoption_len(const char *const arg, const size_t len)
bool is_tty_option(const char *name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return (name[0] == 't' && name[1] == '_')
- || strequal(name, "term")
- || strequal(name, "ttytype");
+ return (name[0] == 't' && name[1] == '_') || strequal(name, "term") || strequal(name, "ttytype");
}
#define TCO_BUFFER_SIZE 8
-/// @param name TUI-related option
-/// @param[out,allocated] value option string value
-bool get_tty_option(const char *name, char **value)
+/// Get value of TTY option.
+///
+/// @param name Name of TTY option.
+///
+/// @return [allocated] TTY option value. Returns NIL_OPTVAL if option isn't a TTY option.
+OptVal get_tty_option(const char *name)
{
- if (strequal(name, "t_Co")) {
- if (value) {
- if (t_colors <= 1) {
- *value = xstrdup("");
- } else {
- *value = xmalloc(TCO_BUFFER_SIZE);
- snprintf(*value, TCO_BUFFER_SIZE, "%d", t_colors);
- }
- }
- return true;
- }
-
- if (strequal(name, "term")) {
- if (value) {
- *value = p_term ? xstrdup(p_term) : xstrdup("nvim");
- }
- return true;
- }
-
- if (strequal(name, "ttytype")) {
- if (value) {
- *value = p_ttytype ? xstrdup(p_ttytype) : xstrdup("nvim");
- }
- return true;
- }
+ char *value = NULL;
- if (is_tty_option(name)) {
- if (value) {
- // XXX: All other t_* options were removed in 3baba1e7.
- *value = xstrdup("");
+ if (strequal(name, "t_Co")) {
+ if (t_colors <= 1) {
+ value = xstrdup("");
+ } else {
+ value = xmalloc(TCO_BUFFER_SIZE);
+ snprintf(value, TCO_BUFFER_SIZE, "%d", t_colors);
}
- return true;
+ } else if (strequal(name, "term")) {
+ value = p_term ? xstrdup(p_term) : xstrdup("nvim");
+ } else if (strequal(name, "ttytype")) {
+ value = p_ttytype ? xstrdup(p_ttytype) : xstrdup("nvim");
+ } else if (is_tty_option(name)) {
+ // XXX: All other t_* options were removed in 3baba1e7.
+ value = xstrdup("");
}
- return false;
+ return value == NULL ? NIL_OPTVAL : CSTR_AS_OPTVAL(value);
}
bool set_tty_option(const char *name, char *value)
@@ -3171,8 +3149,8 @@ bool set_tty_option(const char *name, char *value)
///
/// @param[in] arg Option name.
///
-/// @return Option index or -1 if option was not found.
-int findoption(const char *const arg)
+/// @return Option index or kOptInvalid if option was not found.
+OptIndex findoption(const char *const arg)
FUNC_ATTR_NONNULL_ALL
{
return findoption_len(arg, strlen(arg));
@@ -3232,9 +3210,9 @@ bool optval_equal(OptVal o1, OptVal o2)
/// Match type of OptVal with the type of the target option. Returns true if the types match and
/// false otherwise.
-static bool optval_match_type(OptVal o, int opt_idx)
+static bool optval_match_type(OptVal o, OptIndex opt_idx)
{
- assert(opt_idx >= 0);
+ assert(opt_idx != kOptInvalid);
uint32_t flags = options[opt_idx].flags;
switch (o.type) {
@@ -3254,7 +3232,7 @@ static bool optval_match_type(OptVal o, int opt_idx)
///
/// @param opt_idx Option index in options[] table.
/// @param[out] varp Pointer to option variable.
-OptVal optval_from_varp(int opt_idx, void *varp)
+OptVal optval_from_varp(OptIndex opt_idx, void *varp)
{
// Special case: 'modified' is b_changed, but we also want to consider it set when 'ff' or 'fenc'
// changed.
@@ -3294,7 +3272,7 @@ OptVal optval_from_varp(int opt_idx, void *varp)
/// @param[out] varp Pointer to option variable.
/// @param[in] value New option value.
/// @param free_oldval Free old value.
-static void set_option_varp(int opt_idx, void *varp, OptVal value, bool free_oldval)
+static void set_option_varp(OptIndex opt_idx, void *varp, OptVal value, bool free_oldval)
FUNC_ATTR_NONNULL_ARG(2)
{
assert(optval_match_type(value, opt_idx));
@@ -3390,7 +3368,7 @@ OptVal object_as_optval(Object o, bool *error)
/// @param[in] varp Pointer to option variable.
///
/// @return [allocated] Option value equal to the unset value for the option.
-static OptVal optval_unset_local(int opt_idx, void *varp)
+static OptVal optval_unset_local(OptIndex opt_idx, void *varp)
{
vimoption_T *opt = &options[opt_idx];
// For global-local options, use the unset value of the local value.
@@ -3412,14 +3390,14 @@ static OptVal optval_unset_local(int opt_idx, void *varp)
}
}
// For options that aren't global-local, just set the local value to the global value.
- return get_option_value(opt->fullname, NULL, OPT_GLOBAL, NULL);
+ return get_option_value(opt_idx, OPT_GLOBAL);
}
/// Get an allocated string containing a list of valid types for an option.
/// For options with a singular type, it returns the name of the type. For options with multiple
/// possible types, it returns a slash separated list of types. For example, if an option can be a
/// number, boolean or string, the function returns "Number/Boolean/String"
-static char *option_get_valid_types(int opt_idx)
+static char *option_get_valid_types(OptIndex opt_idx)
{
uint32_t flags = options[opt_idx].flags;
uint32_t type_count = 0;
@@ -3458,52 +3436,48 @@ static char *option_get_valid_types(int opt_idx)
#undef OPTION_ADD_TYPE
}
-/// Gets the value for an option.
+/// Check if option is hidden.
///
-/// @param[in] name Option name.
-/// @param[out] flagsp Set to the option flags (P_xxxx) (if not NULL).
-/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination).
-/// @param[out] hidden Whether option is hidden.
+/// @param opt_idx Option index in options[] table.
///
-/// @return [allocated] Option value. Returns NIL_OPTVAL for invalid options.
-OptVal get_option_value(const char *name, uint32_t *flagsp, int scope, bool *hidden)
+/// @return True if option is hidden, false otherwise. Returns false if option name is invalid.
+bool is_option_hidden(OptIndex opt_idx)
{
- // Make sure that hidden and flagsp are never returned uninitialized
- if (hidden != NULL) {
- *hidden = false;
- }
- if (flagsp != NULL) {
- *flagsp = 0;
- }
+ return opt_idx == kOptInvalid ? false : get_varp(&options[opt_idx]) == NULL;
+}
- char *str;
- if (get_tty_option(name, &str)) {
- return CSTR_AS_OPTVAL(str);
- }
+/// Get option flags.
+///
+/// @param opt_idx Option index in options[] table.
+///
+/// @return Option flags. Returns 0 for invalid option name.
+uint32_t get_option_flags(OptIndex opt_idx)
+{
+ return opt_idx == kOptInvalid ? 0 : options[opt_idx].flags;
+}
- int opt_idx = findoption(name);
- if (opt_idx < 0) { // option not in the table
+/// Gets the value for an option.
+///
+/// @param opt_idx Option index in options[] table.
+/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination).
+///
+/// @return [allocated] Option value. Returns NIL_OPTVAL for invalid option index.
+OptVal get_option_value(OptIndex opt_idx, int scope)
+{
+ if (opt_idx == kOptInvalid) { // option not in the options[] table.
return NIL_OPTVAL;
}
vimoption_T *opt = &options[opt_idx];
void *varp = get_varp_scope(opt, scope);
- if (hidden != NULL) {
- *hidden = varp == NULL;
- }
-
- if (flagsp != NULL) {
- // Return the P_xxxx option flags.
- *flagsp = opt->flags;
- }
-
return optval_copy(optval_from_varp(opt_idx, varp));
}
/// Return information for option at 'opt_idx'
-vimoption_T *get_option(int opt_idx)
+vimoption_T *get_option(OptIndex opt_idx)
{
+ assert(opt_idx != kOptInvalid);
return &options[opt_idx];
}
@@ -3529,7 +3503,7 @@ static bool is_option_local_value_unset(vimoption_T *opt, buf_T *buf, win_T *win
/// Handle side-effects of setting an option.
///
-/// @param opt_idx Index in options[] table. Must be >= 0.
+/// @param opt_idx Index in options[] table. Must not be kOptInvalid.
/// @param[in] varp Option variable pointer, cannot be NULL.
/// @param old_value Old option value.
/// @param new_value New option value.
@@ -3540,7 +3514,7 @@ static bool is_option_local_value_unset(vimoption_T *opt, buf_T *buf, win_T *win
/// @param errbuflen Length of error buffer.
///
/// @return NULL on success, an untranslated error message on error.
-static const char *did_set_option(int opt_idx, void *varp, OptVal old_value, OptVal new_value,
+static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value, OptVal new_value,
int opt_flags, bool *value_checked, bool value_replaced,
char *errbuf, size_t errbuflen)
{
@@ -3607,7 +3581,7 @@ static const char *did_set_option(int opt_idx, void *varp, OptVal old_value, Opt
new_value = optval_from_varp(opt_idx, varp);
// Remember where the option was set.
- set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+ set_option_sctx(opt_idx, opt_flags, current_sctx);
// Free options that are in allocated memory.
// Use "free_oldval", because recursiveness may change the flags (esp. init_highlight()).
if (free_oldval) {
@@ -3687,7 +3661,7 @@ static const char *did_set_option(int opt_idx, void *varp, OptVal old_value, Opt
/// Set the value of an option using an OptVal.
///
-/// @param opt_idx Index in options[] table. Must be >= 0.
+/// @param opt_idx Index in options[] table. Must not be kOptInvalid.
/// @param[in] varp Option variable pointer, cannot be NULL.
/// @param value New option value. Might get freed.
/// @param opt_flags Option flags.
@@ -3696,10 +3670,10 @@ static const char *did_set_option(int opt_idx, void *varp, OptVal old_value, Opt
/// @param errbuflen Length of error buffer.
///
/// @return NULL on success, an untranslated error message on error.
-static const char *set_option(const int opt_idx, void *varp, OptVal value, int opt_flags,
+static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, int opt_flags,
const bool value_replaced, char *errbuf, size_t errbuflen)
{
- assert(opt_idx >= 0 && varp != NULL);
+ assert(opt_idx != kOptInvalid && varp != NULL);
const char *errmsg = NULL;
bool value_checked = false;
@@ -3827,29 +3801,20 @@ err:
return errmsg;
}
-/// Set the value of an option
+/// Set the value of an option.
///
-/// @param[in] name Option name.
+/// @param opt_idx Index in options[] table. Must not be kOptInvalid.
/// @param[in] value Option value. If NIL_OPTVAL, the option value is cleared.
/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
///
/// @return NULL on success, an untranslated error message on error.
-const char *set_option_value(const char *const name, const OptVal value, int opt_flags)
- FUNC_ATTR_NONNULL_ARG(1)
+const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt_flags)
{
- static char errbuf[IOSIZE];
-
- if (is_tty_option(name)) {
- return NULL; // Fail silently; many old vimrcs set t_xx options.
- }
-
- int opt_idx = findoption(name);
- if (opt_idx < 0) {
- snprintf(errbuf, sizeof(errbuf), _(e_unknown_option2), name);
- return errbuf;
- }
+ assert(opt_idx != kOptInvalid);
+ static char errbuf[IOSIZE];
uint32_t flags = options[opt_idx].flags;
+
// Disallow changing some options in the sandbox
if (sandbox > 0 && (flags & P_SECURE)) {
return _(e_sandbox);
@@ -3861,31 +3826,51 @@ const char *set_option_value(const char *const name, const OptVal value, int opt
return NULL;
}
- const char *errmsg = NULL;
+ return set_option(opt_idx, varp, optval_copy(value), opt_flags, true, errbuf, sizeof(errbuf));
+}
- errmsg = set_option(opt_idx, varp, optval_copy(value), opt_flags, true, errbuf, sizeof(errbuf));
+/// Set the value of an option. Supports TTY options, unlike set_option_value().
+///
+/// @param name Option name. Used for error messages and for setting TTY options.
+/// @param opt_idx Option indx in options[] table. If less than zero, `name` is used to
+/// check if the option is a TTY option, and an error is shown if it's not.
+/// If the option is a TTY option, the function fails silently.
+/// @param value Option value. If NIL_OPTVAL, the option value is cleared.
+/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
+///
+/// @return NULL on success, an untranslated error message on error.
+const char *set_option_value_handle_tty(const char *name, OptIndex opt_idx, const OptVal value,
+ int opt_flags)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ static char errbuf[IOSIZE];
- return errmsg;
+ if (opt_idx == kOptInvalid) {
+ if (is_tty_option(name)) {
+ return NULL; // Fail silently; many old vimrcs set t_xx options.
+ }
+
+ snprintf(errbuf, sizeof(errbuf), _(e_unknown_option2), name);
+ return errbuf;
+ }
+
+ return set_option_value(opt_idx, value, opt_flags);
}
-/// Call set_option_value() and when an error is returned report it.
+/// Call set_option_value() and when an error is returned, report it.
///
-/// @param opt_flags OPT_LOCAL or 0 (both)
-void set_option_value_give_err(const char *name, OptVal value, int opt_flags)
+/// @param opt_idx Option index in options[] table.
+/// @param value Option value. If NIL_OPTVAL, the option value is cleared.
+/// @param opt_flags OPT_LOCAL or 0 (both)
+void set_option_value_give_err(const OptIndex opt_idx, OptVal value, int opt_flags)
{
- const char *errmsg = set_option_value(name, value, opt_flags);
+ const char *errmsg = set_option_value(opt_idx, value, opt_flags);
if (errmsg != NULL) {
emsg(_(errmsg));
}
}
-bool is_option_allocated(const char *name)
-{
- int idx = findoption(name);
- return idx >= 0 && (options[idx].flags & P_ALLOCED);
-}
-
// Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number.
// When "has_lt" is true there is a '<' before "*arg_arg".
// Returns 0 when the key is not recognized.
@@ -3942,33 +3927,35 @@ static void showoptions(bool all, int opt_flags)
for (int run = 1; run <= 2 && !got_int; run++) {
// collect the items in items[]
int item_count = 0;
- for (vimoption_T *p = &options[0]; p->fullname != NULL; p++) {
+ vimoption_T *opt;
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ opt = &options[opt_idx];
// apply :filter /pat/
- if (message_filtered(p->fullname)) {
+ if (message_filtered(opt->fullname)) {
continue;
}
void *varp = NULL;
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) {
- if (p->indir != PV_NONE) {
- varp = get_varp_scope(p, opt_flags);
+ if (opt->indir != PV_NONE) {
+ varp = get_varp_scope(opt, opt_flags);
}
} else {
- varp = get_varp(p);
+ varp = get_varp(opt);
}
- if (varp != NULL && (all || !optval_default(p, varp))) {
+ if (varp != NULL && (all || !optval_default(opt, varp))) {
int len;
if (opt_flags & OPT_ONECOLUMN) {
len = Columns;
- } else if (p->flags & P_BOOL) {
+ } else if (opt->flags & P_BOOL) {
len = 1; // a toggle option fits always
} else {
- option_value2string(p, opt_flags);
- len = (int)strlen(p->fullname) + vim_strsize(NameBuff) + 1;
+ option_value2string(opt, opt_flags);
+ len = (int)strlen(opt->fullname) + vim_strsize(NameBuff) + 1;
}
if ((len <= INC - GAP && run == 1)
|| (len > INC - GAP && run == 2)) {
- items[item_count++] = p;
+ items[item_count++] = opt;
}
}
}
@@ -4025,7 +4012,7 @@ static int optval_default(vimoption_T *p, const void *varp)
/// Send update to UIs with values of UI relevant options
void ui_refresh_options(void)
{
- for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
uint32_t flags = options[opt_idx].flags;
if (!(flags & P_UI_OPTION)) {
continue;
@@ -4112,39 +4099,42 @@ int makeset(FILE *fd, int opt_flags, int local_only)
// Do the loop over "options[]" twice: once for options with the
// P_PRI_MKRC flag and once without.
for (int pri = 1; pri >= 0; pri--) {
- for (vimoption_T *p = &options[0]; p->fullname; p++) {
- if (!(p->flags & P_NO_MKRC)
- && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0))) {
+ vimoption_T *opt;
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ opt = &options[opt_idx];
+
+ if (!(opt->flags & P_NO_MKRC)
+ && ((pri == 1) == ((opt->flags & P_PRI_MKRC) != 0))) {
// skip global option when only doing locals
- if (p->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) {
+ if (opt->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) {
continue;
}
// Do not store options like 'bufhidden' and 'syntax' in a vimrc
// file, they are always buffer-specific.
- if ((opt_flags & OPT_GLOBAL) && (p->flags & P_NOGLOB)) {
+ if ((opt_flags & OPT_GLOBAL) && (opt->flags & P_NOGLOB)) {
continue;
}
- void *varp = get_varp_scope(p, opt_flags); // currently used value
+ void *varp = get_varp_scope(opt, opt_flags); // currently used value
// Hidden options are never written.
if (!varp) {
continue;
}
// Global values are only written when not at the default value.
- if ((opt_flags & OPT_GLOBAL) && optval_default(p, varp)) {
+ if ((opt_flags & OPT_GLOBAL) && optval_default(opt, varp)) {
continue;
}
if ((opt_flags & OPT_SKIPRTP)
- && (p->var == &p_rtp || p->var == &p_pp)) {
+ && (opt->var == &p_rtp || opt->var == &p_pp)) {
continue;
}
int round = 2;
void *varp_local = NULL; // fresh value
- if (p->indir != PV_NONE) {
- if (p->var == VAR_WIN) {
+ if (opt->indir != PV_NONE) {
+ if (opt->var == VAR_WIN) {
// skip window-local option when only doing globals
if (!(opt_flags & OPT_LOCAL)) {
continue;
@@ -4152,8 +4142,8 @@ int makeset(FILE *fd, int opt_flags, int local_only)
// When fresh value of window-local option is not at the
// default, need to write it too.
if (!(opt_flags & OPT_GLOBAL) && !local_only) {
- void *varp_fresh = get_varp_scope(p, OPT_GLOBAL); // local value
- if (!optval_default(p, varp_fresh)) {
+ void *varp_fresh = get_varp_scope(opt, OPT_GLOBAL); // local value
+ if (!optval_default(opt, varp_fresh)) {
round = 1;
varp_local = varp;
varp = varp_fresh;
@@ -4172,12 +4162,12 @@ int makeset(FILE *fd, int opt_flags, int local_only)
cmd = "setlocal";
}
- if (p->flags & P_BOOL) {
- if (put_setbool(fd, cmd, p->fullname, *(int *)varp) == FAIL) {
+ if (opt->flags & P_BOOL) {
+ if (put_setbool(fd, cmd, opt->fullname, *(int *)varp) == FAIL) {
return FAIL;
}
- } else if (p->flags & P_NUM) {
- if (put_setnum(fd, cmd, p->fullname, (OptInt *)varp) == FAIL) {
+ } else if (opt->flags & P_NUM) {
+ if (put_setnum(fd, cmd, opt->fullname, (OptInt *)varp) == FAIL) {
return FAIL;
}
} else { // P_STRING
@@ -4185,15 +4175,15 @@ int makeset(FILE *fd, int opt_flags, int local_only)
// Don't set 'syntax' and 'filetype' again if the value is
// already right, avoids reloading the syntax file.
- if (p->indir == PV_SYN || p->indir == PV_FT) {
- if (fprintf(fd, "if &%s != '%s'", p->fullname,
+ if (opt->indir == PV_SYN || opt->indir == PV_FT) {
+ if (fprintf(fd, "if &%s != '%s'", opt->fullname,
*(char **)(varp)) < 0
|| put_eol(fd) < 0) {
return FAIL;
}
do_endif = true;
}
- if (put_setstring(fd, cmd, p->fullname, (char **)varp, p->flags) == FAIL) {
+ if (put_setstring(fd, cmd, opt->fullname, (char **)varp, opt->flags) == FAIL) {
return FAIL;
}
if (do_endif) {
@@ -4404,7 +4394,7 @@ void *get_varp_scope(vimoption_T *p, int scope)
/// Get pointer to option variable at 'opt_idx', depending on local or global
/// scope.
-void *get_option_varp_scope_from(int opt_idx, int scope, buf_T *buf, win_T *win)
+void *get_option_varp_scope_from(OptIndex opt_idx, int scope, buf_T *buf, win_T *win)
{
return get_varp_scope_from(&(options[opt_idx]), scope, buf, win);
}
@@ -4871,19 +4861,19 @@ void didset_window_options(win_T *wp, bool valid_cursor)
}
/// Index into the options table for a buffer-local option enum.
-static int buf_opt_idx[BV_COUNT];
+static OptIndex buf_opt_idx[BV_COUNT];
#define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].last_set
/// Initialize buf_opt_idx[] if not done already.
static void init_buf_opt_idx(void)
{
- static int did_init_buf_opt_idx = false;
+ static bool did_init_buf_opt_idx = false;
if (did_init_buf_opt_idx) {
return;
}
did_init_buf_opt_idx = true;
- for (int i = 0; options[i].fullname != NULL; i++) {
+ for (OptIndex i = 0; i < kOptIndexCount; i++) {
if (options[i].indir & PV_BUF) {
buf_opt_idx[options[i].indir & PV_MASK] = i;
}
@@ -5172,14 +5162,9 @@ void buf_copy_options(buf_T *buf, int flags)
/// Reset the 'modifiable' option and its default value.
void reset_modifiable(void)
{
- int opt_idx;
-
curbuf->b_p_ma = false;
p_ma = false;
- opt_idx = findoption("ma");
- if (opt_idx >= 0) {
- options[opt_idx].def_val = false;
- }
+ options[kOptModifiable].def_val = false;
}
/// Set the global value for 'iminsert' to the local value.
@@ -5194,7 +5179,7 @@ void set_imsearch_global(buf_T *buf)
p_imsearch = buf->b_p_imsearch;
}
-static int expand_option_idx = -1;
+static int expand_option_idx = kOptInvalid;
static int expand_option_start_col = 0;
static char expand_option_name[5] = { 't', '_', NUL, NUL, NUL };
static int expand_option_flags = 0;
@@ -5244,7 +5229,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
char nextchar;
uint32_t flags = 0;
- int opt_idx = 0;
+ OptIndex opt_idx = 0;
int is_term_option = false;
if (*arg == '<') {
@@ -5285,7 +5270,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
}
nextchar = *p;
opt_idx = findoption_len(arg, (size_t)(p - arg));
- if (opt_idx == -1 || options[opt_idx].var == NULL) {
+ if (opt_idx == kOptInvalid || options[opt_idx].var == NULL) {
xp->xp_context = EXPAND_NOTHING;
return;
}
@@ -5318,7 +5303,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// Below are for handling expanding a specific option's value after the '=' or ':'
if (is_term_option) {
- expand_option_idx = -1;
+ expand_option_idx = kOptInvalid;
} else {
expand_option_idx = opt_idx;
}
@@ -5342,8 +5327,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
if (expand_option_subtract) {
xp->xp_context = EXPAND_SETTING_SUBTRACT;
return;
- } else if (expand_option_idx >= 0
- && options[expand_option_idx].opt_expand_cb != NULL) {
+ } else if (expand_option_idx != kOptInvalid && options[expand_option_idx].opt_expand_cb != NULL) {
xp->xp_context = EXPAND_STRING_SETTING;
} else if (*xp->xp_pattern == NUL) {
xp->xp_context = EXPAND_OLD_SETTING;
@@ -5504,8 +5488,8 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM
}
}
char *str;
- for (size_t opt_idx = 0; (str = options[opt_idx].fullname) != NULL;
- opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ str = options[opt_idx].fullname;
if (options[opt_idx].var == NULL) {
continue;
}
@@ -5569,7 +5553,7 @@ static char *escape_option_str_cmdline(char *var)
// The reverse is found at stropt_copy_value().
for (var = buf; *var != NUL; MB_PTR_ADV(var)) {
if (var[0] == '\\' && var[1] == '\\'
- && expand_option_idx >= 0
+ && expand_option_idx != kOptInvalid
&& (options[expand_option_idx].flags & P_EXPAND)
&& vim_isfilec((uint8_t)var[2])
&& (var[2] != '\\' || (var == buf && var[4] != '\\'))) {
@@ -5588,12 +5572,12 @@ int ExpandOldSetting(int *numMatches, char ***matches)
*numMatches = 0;
*matches = xmalloc(sizeof(char *));
- // For a terminal key code expand_option_idx is < 0.
- if (expand_option_idx < 0) {
+ // For a terminal key code expand_option_idx is kOptInvalid.
+ if (expand_option_idx == kOptInvalid) {
expand_option_idx = findoption(expand_option_name);
}
- if (expand_option_idx >= 0) {
+ if (expand_option_idx != kOptInvalid) {
// Put string of option value in NameBuff.
option_value2string(&options[expand_option_idx], expand_option_flags);
var = NameBuff;
@@ -5611,8 +5595,7 @@ int ExpandOldSetting(int *numMatches, char ***matches)
/// Expansion handler for :set=/:set+= when the option has a custom expansion handler.
int ExpandStringSetting(expand_T *xp, regmatch_T *regmatch, int *numMatches, char ***matches)
{
- if (expand_option_idx < 0
- || options[expand_option_idx].opt_expand_cb == NULL) {
+ if (expand_option_idx == kOptInvalid || options[expand_option_idx].opt_expand_cb == NULL) {
// Not supposed to reach this. This function is only for options with
// custom expansion callbacks.
return FAIL;
@@ -5644,7 +5627,7 @@ int ExpandStringSetting(expand_T *xp, regmatch_T *regmatch, int *numMatches, cha
/// Expansion handler for :set-=
int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, char ***matches)
{
- if (expand_option_idx < 0) {
+ if (expand_option_idx == kOptInvalid) {
// term option
return ExpandOldSetting(numMatches, matches);
}
@@ -5824,35 +5807,24 @@ void vimrc_found(char *fname, char *envname)
}
}
-/// Check whether global option has been set
+/// Check whether global option has been set.
///
/// @param[in] name Option name.
///
-/// @return True if it was set.
-bool option_was_set(const char *name)
+/// @return True if option was set.
+bool option_was_set(OptIndex opt_idx)
{
- int idx;
-
- idx = findoption(name);
- if (idx < 0) { // Unknown option.
- return false;
- } else if (options[idx].flags & P_WAS_SET) {
- return true;
- }
- return false;
+ assert(opt_idx != kOptInvalid);
+ return options[opt_idx].flags & P_WAS_SET;
}
/// Reset the flag indicating option "name" was set.
///
/// @param[in] name Option name.
-void reset_option_was_set(const char *name)
+void reset_option_was_set(OptIndex opt_idx)
{
- const int idx = findoption(name);
- if (idx < 0) {
- return;
- }
-
- options[idx].flags &= ~P_WAS_SET;
+ assert(opt_idx != kOptInvalid);
+ options[opt_idx].flags &= ~P_WAS_SET;
}
/// fill_culopt_flags() -- called when 'culopt' changes value
@@ -5951,17 +5923,14 @@ int option_set_callback_func(char *optval, Callback *optcb)
return OK;
}
-static void didset_options_sctx(int opt_flags, char **buf)
+static void didset_options_sctx(int opt_flags, int *buf)
{
for (int i = 0;; i++) {
- if (buf[i] == NULL) {
+ if (buf[i] == kOptInvalid) {
break;
}
- int idx = findoption(buf[i]);
- if (idx >= 0) {
- set_option_sctx_idx(idx, opt_flags, current_sctx);
- }
+ set_option_sctx(buf[i], opt_flags, current_sctx);
}
}
@@ -6101,7 +6070,7 @@ void set_fileformat(int eol_style, int opt_flags)
// p is NULL if "eol_style" is EOL_UNKNOWN.
if (p != NULL) {
- set_string_option_direct("ff", -1, p, OPT_FREE | opt_flags, 0);
+ set_string_option_direct(kOptFileformat, p, OPT_FREE | opt_flags, 0);
}
// This may cause the buffer to become (un)modified.
@@ -6172,27 +6141,13 @@ bool fish_like_shell(void)
return strstr(path_tail(p_sh), "fish") != NULL;
}
-/// Return the number of requested sign columns, based on current
-/// buffer signs and on user configuration.
-int win_signcol_count(win_T *wp)
-{
- if (wp->w_minscwidth <= SCL_NO) {
- return 0;
- }
-
- int needed_signcols = buf_signcols(wp->w_buffer, wp->w_maxscwidth);
- int ret = MAX(wp->w_minscwidth, MIN(wp->w_maxscwidth, needed_signcols));
- assert(ret <= SIGN_SHOW_MAX);
- return ret;
-}
-
/// Get window or buffer local options
dict_T *get_winbuf_options(const int bufopt)
FUNC_ATTR_WARN_UNUSED_RESULT
{
dict_T *const d = tv_dict_alloc();
- for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
struct vimoption *opt = &options[opt_idx];
if ((bufopt && (opt->indir & PV_BUF))
@@ -6236,8 +6191,8 @@ int get_sidescrolloff_value(win_T *wp)
Dictionary get_vimoption(String name, int scope, buf_T *buf, win_T *win, Error *err)
{
- int opt_idx = findoption_len(name.data, name.size);
- VALIDATE_S(opt_idx >= 0, "option (not found)", name.data, {
+ OptIndex opt_idx = findoption_len(name.data, name.size);
+ VALIDATE_S(opt_idx != kOptInvalid, "option (not found)", name.data, {
return (Dictionary)ARRAY_DICT_INIT;
});
@@ -6247,9 +6202,9 @@ Dictionary get_vimoption(String name, int scope, buf_T *buf, win_T *win, Error *
Dictionary get_all_vimoptions(void)
{
Dictionary retval = ARRAY_DICT_INIT;
- for (size_t i = 0; options[i].fullname != NULL; i++) {
- Dictionary opt_dict = vimoption2dict(&options[i], OPT_GLOBAL, curbuf, curwin);
- PUT(retval, options[i].fullname, DICTIONARY_OBJ(opt_dict));
+ for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ Dictionary opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin);
+ PUT(retval, options[opt_idx].fullname, DICTIONARY_OBJ(opt_dict));
}
return retval;
}
diff --git a/src/nvim/option.h b/src/nvim/option.h
index ebf8e0417d..db438342ab 100644
--- a/src/nvim/option.h
+++ b/src/nvim/option.h
@@ -87,14 +87,11 @@ typedef enum {
OPT_SKIPRTP = 0x100, ///< "skiprtp" in 'sessionoptions'
} OptionFlags;
-/// Return value from get_option_value_strict
+/// Return value from get_option_attrs().
enum {
- SOPT_BOOL = 0x01, ///< Boolean option
- SOPT_NUM = 0x02, ///< Number option
- SOPT_STRING = 0x04, ///< String option
- SOPT_GLOBAL = 0x08, ///< Option has global value
- SOPT_WIN = 0x10, ///< Option has window-local value
- SOPT_BUF = 0x20, ///< Option has buffer-local value
+ SOPT_GLOBAL = 0x01, ///< Option has global value
+ SOPT_WIN = 0x02, ///< Option has window-local value
+ SOPT_BUF = 0x04, ///< Option has buffer-local value
};
// OptVal helper macros.
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 6d0401f319..28718c6269 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -122,3 +122,8 @@ typedef enum {
kOptReqWin = 1, ///< Request window-local option value
kOptReqBuf = 2, ///< Request buffer-local option value
} OptReqScope;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+// Initialize the OptIndex enum.
+# include "options_enum.generated.h"
+#endif
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index daaf73d241..8f0be0eb1b 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -94,56 +94,6 @@ return {
type = 'number',
},
{
- abbreviation = 'arab',
- cb = 'did_set_arabic',
- defaults = { if_true = false },
- desc = [=[
- This option can be set to start editing Arabic text.
- Setting this option will:
- - Set the 'rightleft' option, unless 'termbidi' is set.
- - Set the 'arabicshape' option, unless 'termbidi' is set.
- - Set the 'keymap' option to "arabic"; in Insert mode CTRL-^ toggles
- between typing English and Arabic key mapping.
- - Set the 'delcombine' option
-
- Resetting this option will:
- - Reset the 'rightleft' option.
- - Disable the use of 'keymap' (without changing its value).
- Note that 'arabicshape' and 'delcombine' are not reset (it is a global
- option).
- Also see |arabic.txt|.
- ]=],
- full_name = 'arabic',
- redraw = { 'curswant' },
- scope = { 'window' },
- short_desc = N_('Arabic as a default second language'),
- type = 'bool',
- },
- {
- abbreviation = 'arshape',
- defaults = { if_true = true },
- desc = [=[
- When on and 'termbidi' is off, the required visual character
- corrections that need to take place for displaying the Arabic language
- take effect. Shaping, in essence, gets enabled; the term is a broad
- one which encompasses:
- a) the changing/morphing of characters based on their location
- within a word (initial, medial, final and stand-alone).
- b) the enabling of the ability to compose characters
- c) the enabling of the required combining of some characters
- When disabled the display shows each character's true stand-alone
- form.
- Arabic is a complex language which requires other settings, for
- further details see |arabic.txt|.
- ]=],
- full_name = 'arabicshape',
- redraw = { 'all_windows', 'ui_option' },
- scope = { 'global' },
- short_desc = N_('do shaping for Arabic characters'),
- type = 'bool',
- varname = 'p_arshape',
- },
- {
abbreviation = 'ari',
defaults = { if_true = false },
desc = [=[
@@ -203,6 +153,56 @@ return {
varname = 'p_ambw',
},
{
+ abbreviation = 'arab',
+ cb = 'did_set_arabic',
+ defaults = { if_true = false },
+ desc = [=[
+ This option can be set to start editing Arabic text.
+ Setting this option will:
+ - Set the 'rightleft' option, unless 'termbidi' is set.
+ - Set the 'arabicshape' option, unless 'termbidi' is set.
+ - Set the 'keymap' option to "arabic"; in Insert mode CTRL-^ toggles
+ between typing English and Arabic key mapping.
+ - Set the 'delcombine' option
+
+ Resetting this option will:
+ - Reset the 'rightleft' option.
+ - Disable the use of 'keymap' (without changing its value).
+ Note that 'arabicshape' and 'delcombine' are not reset (it is a global
+ option).
+ Also see |arabic.txt|.
+ ]=],
+ full_name = 'arabic',
+ redraw = { 'curswant' },
+ scope = { 'window' },
+ short_desc = N_('Arabic as a default second language'),
+ type = 'bool',
+ },
+ {
+ abbreviation = 'arshape',
+ defaults = { if_true = true },
+ desc = [=[
+ When on and 'termbidi' is off, the required visual character
+ corrections that need to take place for displaying the Arabic language
+ take effect. Shaping, in essence, gets enabled; the term is a broad
+ one which encompasses:
+ a) the changing/morphing of characters based on their location
+ within a word (initial, medial, final and stand-alone).
+ b) the enabling of the ability to compose characters
+ c) the enabling of the required combining of some characters
+ When disabled the display shows each character's true stand-alone
+ form.
+ Arabic is a complex language which requires other settings, for
+ further details see |arabic.txt|.
+ ]=],
+ full_name = 'arabicshape',
+ redraw = { 'all_windows', 'ui_option' },
+ scope = { 'global' },
+ short_desc = N_('do shaping for Arabic characters'),
+ type = 'bool',
+ varname = 'p_arshape',
+ },
+ {
abbreviation = 'acd',
cb = 'did_set_autochdir',
defaults = { if_true = false },
@@ -1129,6 +1129,25 @@ return {
varname = 'p_cino',
},
{
+ abbreviation = 'cinsd',
+ alloced = true,
+ defaults = { if_true = 'public,protected,private' },
+ deny_duplicates = true,
+ desc = [=[
+ Keywords that are interpreted as a C++ scope declaration by |cino-g|.
+ Useful e.g. for working with the Qt framework that defines additional
+ scope declarations "signals", "public slots" and "private slots": >
+ set cinscopedecls+=signals,public\ slots,private\ slots
+ <
+ ]=],
+ full_name = 'cinscopedecls',
+ list = 'onecomma',
+ scope = { 'buffer' },
+ short_desc = N_("words that are recognized by 'cino-g'"),
+ type = 'string',
+ varname = 'p_cinsd',
+ },
+ {
abbreviation = 'cinw',
alloced = true,
defaults = { if_true = 'if,else,while,do,for,switch' },
@@ -1149,25 +1168,6 @@ return {
varname = 'p_cinw',
},
{
- abbreviation = 'cinsd',
- alloced = true,
- defaults = { if_true = 'public,protected,private' },
- deny_duplicates = true,
- desc = [=[
- Keywords that are interpreted as a C++ scope declaration by |cino-g|.
- Useful e.g. for working with the Qt framework that defines additional
- scope declarations "signals", "public slots" and "private slots": >
- set cinscopedecls+=signals,public\ slots,private\ slots
- <
- ]=],
- full_name = 'cinscopedecls',
- list = 'onecomma',
- scope = { 'buffer' },
- short_desc = N_("words that are recognized by 'cino-g'"),
- type = 'string',
- varname = 'p_cinsd',
- },
- {
abbreviation = 'cb',
cb = 'did_set_clipboard',
defaults = { if_true = '' },
@@ -1394,65 +1394,6 @@ return {
varname = 'p_cpt',
},
{
- abbreviation = 'cocu',
- alloced = true,
- cb = 'did_set_concealcursor',
- defaults = { if_true = '' },
- desc = [=[
- Sets the modes in which text in the cursor line can also be concealed.
- When the current mode is listed then concealing happens just like in
- other lines.
- n Normal mode
- v Visual mode
- i Insert mode
- c Command line editing, for 'incsearch'
-
- 'v' applies to all lines in the Visual area, not only the cursor.
- A useful value is "nc". This is used in help files. So long as you
- are moving around text is concealed, but when starting to insert text
- or selecting a Visual area the concealed text is displayed, so that
- you can see what you are doing.
- Keep in mind that the cursor position is not always where it's
- displayed. E.g., when moving vertically it may change column.
- ]=],
- expand_cb = 'expand_set_concealcursor',
- full_name = 'concealcursor',
- list = 'flags',
- redraw = { 'current_window' },
- scope = { 'window' },
- short_desc = N_('whether concealable text is hidden in cursor line'),
- type = 'string',
- },
- {
- abbreviation = 'cole',
- defaults = { if_true = 0 },
- desc = [=[
- Determine how text with the "conceal" syntax attribute |:syn-conceal|
- is shown:
-
- Value Effect ~
- 0 Text is shown normally
- 1 Each block of concealed text is replaced with one
- character. If the syntax item does not have a custom
- replacement character defined (see |:syn-cchar|) the
- character defined in 'listchars' is used.
- It is highlighted with the "Conceal" highlight group.
- 2 Concealed text is completely hidden unless it has a
- custom replacement character defined (see
- |:syn-cchar|).
- 3 Concealed text is completely hidden.
-
- Note: in the cursor line concealed text is not hidden, so that you can
- edit and copy the text. This can be changed with the 'concealcursor'
- option.
- ]=],
- full_name = 'conceallevel',
- redraw = { 'current_window' },
- scope = { 'window' },
- short_desc = N_('whether concealable text is shown or hidden'),
- type = 'number',
- },
- {
abbreviation = 'cfu',
alloced = true,
cb = 'did_set_completefunc',
@@ -1543,6 +1484,65 @@ return {
varname = 'p_csl',
},
{
+ abbreviation = 'cocu',
+ alloced = true,
+ cb = 'did_set_concealcursor',
+ defaults = { if_true = '' },
+ desc = [=[
+ Sets the modes in which text in the cursor line can also be concealed.
+ When the current mode is listed then concealing happens just like in
+ other lines.
+ n Normal mode
+ v Visual mode
+ i Insert mode
+ c Command line editing, for 'incsearch'
+
+ 'v' applies to all lines in the Visual area, not only the cursor.
+ A useful value is "nc". This is used in help files. So long as you
+ are moving around text is concealed, but when starting to insert text
+ or selecting a Visual area the concealed text is displayed, so that
+ you can see what you are doing.
+ Keep in mind that the cursor position is not always where it's
+ displayed. E.g., when moving vertically it may change column.
+ ]=],
+ expand_cb = 'expand_set_concealcursor',
+ full_name = 'concealcursor',
+ list = 'flags',
+ redraw = { 'current_window' },
+ scope = { 'window' },
+ short_desc = N_('whether concealable text is hidden in cursor line'),
+ type = 'string',
+ },
+ {
+ abbreviation = 'cole',
+ defaults = { if_true = 0 },
+ desc = [=[
+ Determine how text with the "conceal" syntax attribute |:syn-conceal|
+ is shown:
+
+ Value Effect ~
+ 0 Text is shown normally
+ 1 Each block of concealed text is replaced with one
+ character. If the syntax item does not have a custom
+ replacement character defined (see |:syn-cchar|) the
+ character defined in 'listchars' is used.
+ It is highlighted with the "Conceal" highlight group.
+ 2 Concealed text is completely hidden unless it has a
+ custom replacement character defined (see
+ |:syn-cchar|).
+ 3 Concealed text is completely hidden.
+
+ Note: in the cursor line concealed text is not hidden, so that you can
+ edit and copy the text. This can be changed with the 'concealcursor'
+ option.
+ ]=],
+ full_name = 'conceallevel',
+ redraw = { 'current_window' },
+ scope = { 'window' },
+ short_desc = N_('whether concealable text is shown or hidden'),
+ type = 'number',
+ },
+ {
abbreviation = 'cf',
defaults = { if_true = false },
desc = [=[
@@ -3241,27 +3241,6 @@ return {
varname = 'p_fex',
},
{
- abbreviation = 'fo',
- alloced = true,
- cb = 'did_set_formatoptions',
- defaults = { if_true = macros('DFLT_FO_VIM') },
- desc = [=[
- This is a sequence of letters which describes how automatic
- formatting is to be done.
- See |fo-table| for possible values and |gq| for how to format text.
- Commas can be inserted for readability.
- To avoid problems with flags that are added in the future, use the
- "+=" and "-=" feature of ":set" |add-option-flags|.
- ]=],
- expand_cb = 'expand_set_formatoptions',
- full_name = 'formatoptions',
- list = 'flags',
- scope = { 'buffer' },
- short_desc = N_('how automatic formatting is to be done'),
- type = 'string',
- varname = 'p_fo',
- },
- {
abbreviation = 'flp',
alloced = true,
defaults = { if_true = '^\\s*\\d\\+[\\]:.)}\\t ]\\s*' },
@@ -3283,6 +3262,27 @@ return {
varname = 'p_flp',
},
{
+ abbreviation = 'fo',
+ alloced = true,
+ cb = 'did_set_formatoptions',
+ defaults = { if_true = macros('DFLT_FO_VIM') },
+ desc = [=[
+ This is a sequence of letters which describes how automatic
+ formatting is to be done.
+ See |fo-table| for possible values and |gq| for how to format text.
+ Commas can be inserted for readability.
+ To avoid problems with flags that are added in the future, use the
+ "+=" and "-=" feature of ":set" |add-option-flags|.
+ ]=],
+ expand_cb = 'expand_set_formatoptions',
+ full_name = 'formatoptions',
+ list = 'flags',
+ scope = { 'buffer' },
+ short_desc = N_('how automatic formatting is to be done'),
+ type = 'string',
+ varname = 'p_fo',
+ },
+ {
abbreviation = 'fp',
defaults = { if_true = '' },
desc = [=[
@@ -6557,27 +6557,6 @@ return {
type = 'number',
},
{
- abbreviation = 'sms',
- cb = 'did_set_smoothscroll',
- defaults = { if_true = false },
- desc = [=[
- Scrolling works with screen lines. When 'wrap' is set and the first
- line in the window wraps part of it may not be visible, as if it is
- above the window. "<<<" is displayed at the start of the first line,
- highlighted with |hl-NonText|.
- You may also want to add "lastline" to the 'display' option to show as
- much of the last line as possible.
- NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y
- and scrolling with the mouse.
- ]=],
- full_name = 'smoothscroll',
- pv_name = 'p_sms',
- redraw = { 'current_window' },
- scope = { 'window' },
- short_desc = N_("scroll by screen lines when 'wrap' is set"),
- type = 'bool',
- },
- {
abbreviation = 'scbk',
cb = 'did_set_scrollback',
defaults = {
@@ -7230,6 +7209,23 @@ return {
varname = 'p_stmp',
},
{
+ abbreviation = 'sxe',
+ defaults = { if_true = '' },
+ desc = [=[
+ When 'shellxquote' is set to "(" then the characters listed in this
+ option will be escaped with a '^' character. This makes it possible
+ to execute most external commands with cmd.exe.
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
+ ]=],
+ full_name = 'shellxescape',
+ scope = { 'global' },
+ secure = true,
+ short_desc = N_("characters to escape when 'shellxquote' is ("),
+ type = 'string',
+ varname = 'p_sxe',
+ },
+ {
abbreviation = 'sxq',
defaults = {
condition = 'MSWIN',
@@ -7256,23 +7252,6 @@ return {
varname = 'p_sxq',
},
{
- abbreviation = 'sxe',
- defaults = { if_true = '' },
- desc = [=[
- When 'shellxquote' is set to "(" then the characters listed in this
- option will be escaped with a '^' character. This makes it possible
- to execute most external commands with cmd.exe.
- This option cannot be set from a |modeline| or in the |sandbox|, for
- security reasons.
- ]=],
- full_name = 'shellxescape',
- scope = { 'global' },
- secure = true,
- short_desc = N_("characters to escape when 'shellxquote' is ("),
- type = 'string',
- varname = 'p_sxe',
- },
- {
abbreviation = 'sr',
defaults = { if_true = false },
desc = [=[
@@ -7668,6 +7647,27 @@ return {
varname = 'p_sta',
},
{
+ abbreviation = 'sms',
+ cb = 'did_set_smoothscroll',
+ defaults = { if_true = false },
+ desc = [=[
+ Scrolling works with screen lines. When 'wrap' is set and the first
+ line in the window wraps part of it may not be visible, as if it is
+ above the window. "<<<" is displayed at the start of the first line,
+ highlighted with |hl-NonText|.
+ You may also want to add "lastline" to the 'display' option to show as
+ much of the last line as possible.
+ NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y
+ and scrolling with the mouse.
+ ]=],
+ full_name = 'smoothscroll',
+ pv_name = 'p_sms',
+ redraw = { 'current_window' },
+ scope = { 'window' },
+ short_desc = N_("scroll by screen lines when 'wrap' is set"),
+ type = 'bool',
+ },
+ {
abbreviation = 'sts',
defaults = { if_true = 0 },
desc = [=[
@@ -7821,6 +7821,31 @@ return {
varname = 'p_spl',
},
{
+ abbreviation = 'spo',
+ cb = 'did_set_spelloptions',
+ defaults = { if_true = '' },
+ deny_duplicates = true,
+ desc = [=[
+ A comma-separated list of options for spell checking:
+ camel When a word is CamelCased, assume "Cased" is a
+ separate word: every upper-case character in a word
+ that comes after a lower case character indicates the
+ start of a new word.
+ noplainbuffer Only spellcheck a buffer when 'syntax' is enabled,
+ or when extmarks are set within the buffer. Only
+ designated regions of the buffer are spellchecked in
+ this case.
+ ]=],
+ expand_cb = 'expand_set_spelloptions',
+ full_name = 'spelloptions',
+ list = 'onecomma',
+ redraw = { 'current_buffer' },
+ scope = { 'buffer' },
+ secure = true,
+ type = 'string',
+ varname = 'p_spo',
+ },
+ {
abbreviation = 'sps',
cb = 'did_set_spellsuggest',
defaults = { if_true = 'best' },
@@ -7901,31 +7926,6 @@ return {
varname = 'p_sps',
},
{
- abbreviation = 'spo',
- cb = 'did_set_spelloptions',
- defaults = { if_true = '' },
- deny_duplicates = true,
- desc = [=[
- A comma-separated list of options for spell checking:
- camel When a word is CamelCased, assume "Cased" is a
- separate word: every upper-case character in a word
- that comes after a lower case character indicates the
- start of a new word.
- noplainbuffer Only spellcheck a buffer when 'syntax' is enabled,
- or when extmarks are set within the buffer. Only
- designated regions of the buffer are spellchecked in
- this case.
- ]=],
- expand_cb = 'expand_set_spelloptions',
- full_name = 'spelloptions',
- list = 'onecomma',
- redraw = { 'current_buffer' },
- scope = { 'buffer' },
- secure = true,
- type = 'string',
- varname = 'p_spo',
- },
- {
abbreviation = 'sb',
defaults = { if_true = false },
desc = [=[
@@ -8456,28 +8456,6 @@ return {
varname = 'p_syn',
},
{
- abbreviation = 'tfu',
- cb = 'did_set_tagfunc',
- defaults = { if_true = '' },
- desc = [=[
- This option specifies a function to be used to perform tag searches.
- The function gets the tag pattern and should return a List of matching
- tags. See |tag-function| for an explanation of how to write the
- function and an example. The value can be the name of a function, a
- |lambda| or a |Funcref|. See |option-value-function| for more
- information.
- This option cannot be set from a |modeline| or in the |sandbox|, for
- security reasons.
- ]=],
- full_name = 'tagfunc',
- func = true,
- scope = { 'buffer' },
- secure = true,
- short_desc = N_('function used to perform tag searches'),
- type = 'string',
- varname = 'p_tfu',
- },
- {
abbreviation = 'tal',
cb = 'did_set_tabline',
defaults = { if_true = '' },
@@ -8656,6 +8634,28 @@ return {
varname = 'p_tc',
},
{
+ abbreviation = 'tfu',
+ cb = 'did_set_tagfunc',
+ defaults = { if_true = '' },
+ desc = [=[
+ This option specifies a function to be used to perform tag searches.
+ The function gets the tag pattern and should return a List of matching
+ tags. See |tag-function| for an explanation of how to write the
+ function and an example. The value can be the name of a function, a
+ |lambda| or a |Funcref|. See |option-value-function| for more
+ information.
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
+ ]=],
+ full_name = 'tagfunc',
+ func = true,
+ scope = { 'buffer' },
+ secure = true,
+ short_desc = N_('function used to perform tag searches'),
+ type = 'string',
+ varname = 'p_tfu',
+ },
+ {
abbreviation = 'tl',
defaults = { if_true = 0 },
desc = [=[
@@ -8764,6 +8764,10 @@ return {
Enables 24-bit RGB color in the |TUI|. Uses "gui" |:highlight|
attributes instead of "cterm" attributes. |guifg|
Requires an ISO-8613-3 compatible terminal.
+
+ Nvim will automatically attempt to determine if the host terminal
+ supports 24-bit color and will enable this option if it does
+ (unless explicitly disabled by the user).
]=],
full_name = 'termguicolors',
redraw = { 'ui_option' },
@@ -9789,39 +9793,6 @@ return {
type = 'number',
},
{
- abbreviation = 'winhl',
- alloced = true,
- cb = 'did_set_winhighlight',
- defaults = { if_true = '' },
- deny_duplicates = true,
- desc = [=[
- Window-local highlights. Comma-delimited list of highlight
- |group-name| pairs "{hl-from}:{hl-to},..." where each {hl-from} is
- a |highlight-groups| item to be overridden by {hl-to} group in
- the window.
-
- Note: highlight namespaces take precedence over 'winhighlight'.
- See |nvim_win_set_hl_ns()| and |nvim_set_hl()|.
-
- Highlights of vertical separators are determined by the window to the
- left of the separator. The 'tabline' highlight of a tabpage is
- decided by the last-focused window of the tabpage. Highlights of
- the popupmenu are determined by the current window. Highlights in the
- message area cannot be overridden.
-
- Example: show a different color for non-current windows: >
- set winhighlight=Normal:MyNormal,NormalNC:MyNormalNC
- <
- ]=],
- expand_cb = 'expand_set_winhighlight',
- full_name = 'winhighlight',
- list = 'onecommacolon',
- redraw = { 'current_window' },
- scope = { 'window' },
- short_desc = N_('Setup window-local highlights'),
- type = 'string',
- },
- {
abbreviation = 'wi',
cb = 'did_set_window',
defaults = {
@@ -9846,6 +9817,35 @@ return {
varname = 'p_window',
},
{
+ abbreviation = 'wfh',
+ defaults = { if_true = false },
+ desc = [=[
+ Keep the window height when windows are opened or closed and
+ 'equalalways' is set. Also for |CTRL-W_=|. Set by default for the
+ |preview-window| and |quickfix-window|.
+ The height may be changed anyway when running out of room.
+ ]=],
+ full_name = 'winfixheight',
+ redraw = { 'statuslines' },
+ scope = { 'window' },
+ short_desc = N_('keep window height when opening/closing windows'),
+ type = 'bool',
+ },
+ {
+ abbreviation = 'wfw',
+ defaults = { if_true = false },
+ desc = [=[
+ Keep the window width when windows are opened or closed and
+ 'equalalways' is set. Also for |CTRL-W_=|.
+ The width may be changed anyway when running out of room.
+ ]=],
+ full_name = 'winfixwidth',
+ redraw = { 'statuslines' },
+ scope = { 'window' },
+ short_desc = N_('keep window width when opening/closing windows'),
+ type = 'bool',
+ },
+ {
abbreviation = 'wh',
cb = 'did_set_winheight',
defaults = { if_true = 1 },
@@ -9875,33 +9875,37 @@ return {
varname = 'p_wh',
},
{
- abbreviation = 'wfh',
- defaults = { if_true = false },
- desc = [=[
- Keep the window height when windows are opened or closed and
- 'equalalways' is set. Also for |CTRL-W_=|. Set by default for the
- |preview-window| and |quickfix-window|.
- The height may be changed anyway when running out of room.
- ]=],
- full_name = 'winfixheight',
- redraw = { 'statuslines' },
- scope = { 'window' },
- short_desc = N_('keep window height when opening/closing windows'),
- type = 'bool',
- },
- {
- abbreviation = 'wfw',
- defaults = { if_true = false },
+ abbreviation = 'winhl',
+ alloced = true,
+ cb = 'did_set_winhighlight',
+ defaults = { if_true = '' },
+ deny_duplicates = true,
desc = [=[
- Keep the window width when windows are opened or closed and
- 'equalalways' is set. Also for |CTRL-W_=|.
- The width may be changed anyway when running out of room.
+ Window-local highlights. Comma-delimited list of highlight
+ |group-name| pairs "{hl-from}:{hl-to},..." where each {hl-from} is
+ a |highlight-groups| item to be overridden by {hl-to} group in
+ the window.
+
+ Note: highlight namespaces take precedence over 'winhighlight'.
+ See |nvim_win_set_hl_ns()| and |nvim_set_hl()|.
+
+ Highlights of vertical separators are determined by the window to the
+ left of the separator. The 'tabline' highlight of a tabpage is
+ decided by the last-focused window of the tabpage. Highlights of
+ the popupmenu are determined by the current window. Highlights in the
+ message area cannot be overridden.
+
+ Example: show a different color for non-current windows: >
+ set winhighlight=Normal:MyNormal,NormalNC:MyNormalNC
+ <
]=],
- full_name = 'winfixwidth',
- redraw = { 'statuslines' },
+ expand_cb = 'expand_set_winhighlight',
+ full_name = 'winhighlight',
+ list = 'onecommacolon',
+ redraw = { 'current_window' },
scope = { 'window' },
- short_desc = N_('keep window width when opening/closing windows'),
- type = 'bool',
+ short_desc = N_('Setup window-local highlights'),
+ type = 'string',
},
{
abbreviation = 'wmh',
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 544524dd42..002cc68a3b 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -283,7 +283,7 @@ static void set_string_option_global(vimoption_T *opt, char **varp)
/// Set a string option to a new value (without checking the effect).
/// The string is copied into allocated memory.
-/// if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
+/// if ("opt_idx" == kOptInvalid) "name" is used, otherwise "opt_idx" is used.
/// When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When
/// "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to
/// "set_sid".
@@ -291,22 +291,9 @@ static void set_string_option_global(vimoption_T *opt, char **varp)
/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL.
///
/// TODO(famiu): Remove this and its win/buf variants.
-void set_string_option_direct(const char *name, int opt_idx, const char *val, int opt_flags,
- int set_sid)
+void set_string_option_direct(OptIndex opt_idx, const char *val, int opt_flags, int set_sid)
{
- int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
- int idx = opt_idx;
-
- if (idx == -1) { // Use name.
- idx = findoption(name);
- if (idx < 0) { // Not found (should not happen).
- internal_error("set_string_option_direct()");
- siemsg(_("For option %s"), name);
- return;
- }
- }
-
- vimoption_T *opt = get_option(idx);
+ vimoption_T *opt = get_option(opt_idx);
if (opt->var == NULL) { // can't set hidden option
return;
@@ -314,53 +301,53 @@ void set_string_option_direct(const char *name, int opt_idx, const char *val, in
assert(opt->var != &p_shada);
+ int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
char *s = xstrdup(val);
- {
- char **varp = (char **)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags);
- if ((opt_flags & OPT_FREE) && (opt->flags & P_ALLOCED)) {
- free_string_option(*varp);
- }
- *varp = s;
+ char **varp = (char **)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags);
- // For buffer/window local option may also set the global value.
- if (both) {
- set_string_option_global(opt, varp);
- }
+ if ((opt_flags & OPT_FREE) && (opt->flags & P_ALLOCED)) {
+ free_string_option(*varp);
+ }
+ *varp = s;
- opt->flags |= P_ALLOCED;
+ // For buffer/window local option may also set the global value.
+ if (both) {
+ set_string_option_global(opt, varp);
+ }
- // When setting both values of a global option with a local value,
- // make the local value empty, so that the global value is used.
- if ((opt->indir & PV_BOTH) && both) {
- free_string_option(*varp);
- *varp = empty_string_option;
- }
- if (set_sid != SID_NONE) {
- sctx_T script_ctx;
+ opt->flags |= P_ALLOCED;
- if (set_sid == 0) {
- script_ctx = current_sctx;
- } else {
- script_ctx.sc_sid = set_sid;
- script_ctx.sc_seq = 0;
- script_ctx.sc_lnum = 0;
- }
- set_option_sctx_idx(idx, opt_flags, script_ctx);
+ // When setting both values of a global option with a local value,
+ // make the local value empty, so that the global value is used.
+ if ((opt->indir & PV_BOTH) && both) {
+ free_string_option(*varp);
+ *varp = empty_string_option;
+ }
+ if (set_sid != SID_NONE) {
+ sctx_T script_ctx;
+
+ if (set_sid == 0) {
+ script_ctx = current_sctx;
+ } else {
+ script_ctx.sc_sid = set_sid;
+ script_ctx.sc_seq = 0;
+ script_ctx.sc_lnum = 0;
}
+ set_option_sctx(opt_idx, opt_flags, script_ctx);
}
}
/// Like set_string_option_direct(), but for a window-local option in "wp".
/// Blocks autocommands to avoid the old curwin becoming invalid.
-void set_string_option_direct_in_win(win_T *wp, const char *name, int opt_idx, const char *val,
- int opt_flags, int set_sid)
+void set_string_option_direct_in_win(win_T *wp, OptIndex opt_idx, const char *val, int opt_flags,
+ int set_sid)
{
win_T *save_curwin = curwin;
block_autocmds();
curwin = wp;
curbuf = curwin->w_buffer;
- set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
+ set_string_option_direct(opt_idx, val, opt_flags, set_sid);
curwin = save_curwin;
curbuf = curwin->w_buffer;
unblock_autocmds();
@@ -368,14 +355,14 @@ void set_string_option_direct_in_win(win_T *wp, const char *name, int opt_idx, c
/// Like set_string_option_direct(), but for a buffer-local option in "buf".
/// Blocks autocommands to avoid the old curwin becoming invalid.
-void set_string_option_direct_in_buf(buf_T *buf, const char *name, int opt_idx, const char *val,
- int opt_flags, int set_sid)
+void set_string_option_direct_in_buf(buf_T *buf, OptIndex opt_idx, const char *val, int opt_flags,
+ int set_sid)
{
buf_T *save_curbuf = curbuf;
block_autocmds();
curbuf = buf;
- set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
+ set_string_option_direct(opt_idx, val, opt_flags, set_sid);
curbuf = save_curbuf;
unblock_autocmds();
}
@@ -2095,6 +2082,8 @@ const char *did_set_signcolumn(optset_T *args)
if (check_signcolumn(win) != OK) {
return e_invarg;
}
+ int scwidth = win->w_minscwidth <= 0 ? 0 : MIN(win->w_maxscwidth, win->w_scwidth);
+ win->w_scwidth = MAX(win->w_minscwidth, scwidth);
// When changing the 'signcolumn' to or from 'number', recompute the
// width of the number column if 'number' or 'relativenumber' is set.
if ((*oldval == 'n' && *(oldval + 1) == 'u') || win->w_minscwidth == SCL_NUM) {
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 28de003212..0fc461ae0f 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1666,7 +1666,7 @@ static char *eval_includeexpr(const char *const ptr, const size_t len)
current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx;
char *res = eval_to_string_safe(curbuf->b_p_inex,
- was_set_insecurely(curwin, "includeexpr", OPT_LOCAL));
+ was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL));
set_vim_var_string(VV_FNAME, NULL, 0);
current_sctx = save_sctx;
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index fbddb1ab4a..cbfaa4ace3 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -14,6 +14,7 @@
#include "nvim/indent.h"
#include "nvim/macros_defs.h"
#include "nvim/mark.h"
+#include "nvim/marktree.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/move.h"
diff --git a/src/nvim/plines.h b/src/nvim/plines.h
index 6aede88c8b..7227db4524 100644
--- a/src/nvim/plines.h
+++ b/src/nvim/plines.h
@@ -1,10 +1,10 @@
#pragma once
#include <stdbool.h>
-#include <stdint.h>
+#include <stdint.h> // IWYU pragma: keep
#include "nvim/buffer_defs.h"
-#include "nvim/marktree.h"
+#include "nvim/marktree_defs.h"
#include "nvim/pos_defs.h" // IWYU pragma: keep
/// Argument for lbr_chartabsize().
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index f009722357..56fc16a82e 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -767,11 +767,11 @@ static bool pum_set_selected(int n, int repeat)
if (res == OK) {
// Edit a new, empty buffer. Set options for a "wipeout"
// buffer.
- set_option_value_give_err("swf", BOOLEAN_OPTVAL(false), OPT_LOCAL);
- set_option_value_give_err("bl", BOOLEAN_OPTVAL(false), OPT_LOCAL);
- set_option_value_give_err("bt", STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
- set_option_value_give_err("bh", STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL);
- set_option_value_give_err("diff", BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ set_option_value_give_err(kOptSwapfile, BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ set_option_value_give_err(kOptBuflisted, BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ set_option_value_give_err(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
+ set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL);
+ set_option_value_give_err(kOptDiff, BOOLEAN_OPTVAL(false), OPT_LOCAL);
}
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 112f9aa35a..976b7e837d 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3645,12 +3645,12 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz, bool vertsp
static void qf_set_cwindow_options(void)
{
// switch off 'swapfile'
- set_option_value_give_err("swf", BOOLEAN_OPTVAL(false), OPT_LOCAL);
- set_option_value_give_err("bt", STATIC_CSTR_AS_OPTVAL("quickfix"), OPT_LOCAL);
- set_option_value_give_err("bh", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
+ set_option_value_give_err(kOptSwapfile, BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ set_option_value_give_err(kOptBuftype, STATIC_CSTR_AS_OPTVAL("quickfix"), OPT_LOCAL);
+ set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
RESET_BINDING(curwin);
curwin->w_p_diff = false;
- set_option_value_give_err("fdm", STATIC_CSTR_AS_OPTVAL("manual"), OPT_LOCAL);
+ set_option_value_give_err(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("manual"), OPT_LOCAL);
}
// Open a new quickfix or location list window, load the quickfix buffer and
@@ -4212,7 +4212,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
// resembles reading a file into a buffer, it's more logical when using
// autocommands.
curbuf->b_ro_locked++;
- set_option_value_give_err("ft", STATIC_CSTR_AS_OPTVAL("qf"), OPT_LOCAL);
+ set_option_value_give_err(kOptFiletype, STATIC_CSTR_AS_OPTVAL("qf"), OPT_LOCAL);
curbuf->b_p_ma = false;
keep_filetype = true; // don't detect 'filetype'
@@ -5090,7 +5090,7 @@ void ex_cfile(exarg_T *eap)
}
}
if (*eap->arg != NUL) {
- set_string_option_direct("ef", -1, eap->arg, OPT_FREE, 0);
+ set_string_option_direct(kOptErrorfile, eap->arg, OPT_FREE, 0);
}
char *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
@@ -7220,7 +7220,7 @@ void ex_helpgrep(exarg_T *eap)
bool updated = false;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *const save_cpo = p_cpo;
- const bool save_cpo_allocated = is_option_allocated("cpo");
+ const bool save_cpo_allocated = (get_option(kOptCpoptions)->flags & P_ALLOCED);
p_cpo = empty_string_option;
bool new_qi = false;
@@ -7258,7 +7258,7 @@ void ex_helpgrep(exarg_T *eap)
// Darn, some plugin changed the value. If it's still empty it was
// changed and restored, need to restore in the complicated way.
if (*p_cpo == NUL) {
- set_option_value_give_err("cpo", CSTR_AS_OPTVAL(save_cpo), 0);
+ set_option_value_give_err(kOptCpoptions, CSTR_AS_OPTVAL(save_cpo), 0);
}
if (save_cpo_allocated) {
free_string_option(save_cpo);
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 087c26a46f..d0305a1082 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -1061,7 +1061,7 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
xstrlcat(new_rtp, afterdir, new_rtp_capacity);
}
- set_option_value_give_err("rtp", CSTR_AS_OPTVAL(new_rtp), 0);
+ set_option_value_give_err(kOptRuntimepath, CSTR_AS_OPTVAL(new_rtp), 0);
xfree(new_rtp);
retval = OK;
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 819fbcf885..02e7c3cc68 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -2604,7 +2604,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
case VAR_LIST: {
list_T *l = vartv.vval.v_list;
int copyID = get_copyID();
- if (!set_ref_in_list(l, copyID, NULL)
+ if (!set_ref_in_list_items(l, copyID, NULL)
&& copyID == l->lv_copyID) {
tv_clear(&vartv);
continue;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 5065bee347..d20d113d9c 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -3218,14 +3218,14 @@ void ex_spelldump(exarg_T *eap)
if (no_spell_checking(curwin)) {
return;
}
- OptVal spl = get_option_value("spl", NULL, OPT_LOCAL, NULL);
+ OptVal spl = get_option_value(kOptSpelllang, OPT_LOCAL);
// Create a new empty buffer in a new window.
do_cmdline_cmd("new");
// enable spelling locally in the new window
- set_option_value_give_err("spell", BOOLEAN_OPTVAL(true), OPT_LOCAL);
- set_option_value_give_err("spl", spl, OPT_LOCAL);
+ set_option_value_give_err(kOptSpell, BOOLEAN_OPTVAL(true), OPT_LOCAL);
+ set_option_value_give_err(kOptSpelllang, spl, OPT_LOCAL);
optval_free(spl);
if (!buf_is_empty(curbuf)) {
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 4aa0508329..027013c5f0 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -5600,7 +5600,7 @@ static void init_spellfile(void)
&& strstr(path_tail(fname), ".ascii.") != NULL)
? "ascii"
: spell_enc()));
- set_option_value_give_err("spellfile", CSTR_AS_OPTVAL(buf), OPT_LOCAL);
+ set_option_value_give_err(kOptSpellfile, CSTR_AS_OPTVAL(buf), OPT_LOCAL);
break;
}
aspath = false;
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index 4dac1b1451..c7d9a65b86 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -296,7 +296,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
char buf[MAXPATHL];
char transbuf[MAXPATHL];
char *stl;
- char *opt_name;
+ OptIndex opt_idx = kOptInvalid;
int opt_scope = 0;
stl_hlrec_t *hltab;
StlClickRecord *tabtab;
@@ -320,9 +320,9 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
fillchar = ' ';
attr = HL_ATTR(HLF_TPF);
maxwidth = Columns;
- opt_name = "tabline";
+ opt_idx = kOptTabline;
} else if (draw_winbar) {
- opt_name = "winbar";
+ opt_idx = kOptWinbar;
stl = ((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr);
opt_scope = ((*wp->w_p_wbr != NUL) ? OPT_LOCAL : 0);
row = -1; // row zero is first row of text
@@ -351,7 +351,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
if (draw_ruler) {
stl = p_ruf;
- opt_name = "rulerformat";
+ opt_idx = kOptRulerformat;
// advance past any leading group spec - implicit in ru_col
if (*stl == '%') {
if (*++stl == '-') {
@@ -379,7 +379,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
attr = HL_ATTR(HLF_MSG);
}
} else {
- opt_name = "statusline";
+ opt_idx = kOptStatusline;
stl = ((*wp->w_p_stl != NUL) ? wp->w_p_stl : p_stl);
opt_scope = ((*wp->w_p_stl != NUL) ? OPT_LOCAL : 0);
}
@@ -402,7 +402,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
// Make a copy, because the statusline may include a function call that
// might change the option value and free the memory.
stl = xstrdup(stl);
- build_stl_str_hl(ewp, buf, sizeof(buf), stl, opt_name, opt_scope,
+ build_stl_str_hl(ewp, buf, sizeof(buf), stl, opt_idx, opt_scope,
fillchar, maxwidth, &hltab, &tabtab, NULL);
xfree(stl);
@@ -881,7 +881,7 @@ int build_statuscol_str(win_T *wp, linenr_T lnum, linenr_T relnum, statuscol_T *
StlClickRecord *clickrec;
char *stc = xstrdup(wp->w_p_stc);
- int width = build_stl_str_hl(wp, stcp->text, MAXPATHL, stc, "statuscolumn", OPT_LOCAL, ' ',
+ int width = build_stl_str_hl(wp, stcp->text, MAXPATHL, stc, kOptStatuscolumn, OPT_LOCAL, ' ',
stcp->width, &stcp->hlrec, fillclick ? &clickrec : NULL, stcp);
xfree(stc);
@@ -913,8 +913,8 @@ int build_statuscol_str(win_T *wp, linenr_T lnum, linenr_T relnum, statuscol_T *
/// Note: This should not be NameBuff
/// @param outlen The length of the output buffer
/// @param fmt The statusline format string
-/// @param opt_name The option name corresponding to "fmt"
-/// @param opt_scope The scope corresponding to "opt_name"
+/// @param opt_idx Index of the option corresponding to "fmt"
+/// @param opt_scope The scope corresponding to "opt_idx"
/// @param fillchar Character to use when filling empty space in the statusline
/// @param maxwidth The maximum width to make the statusline
/// @param hltab HL attributes (can be NULL)
@@ -922,9 +922,9 @@ int build_statuscol_str(win_T *wp, linenr_T lnum, linenr_T relnum, statuscol_T *
/// @param stcp Status column attributes (can be NULL)
///
/// @return The final width of the statusline
-int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_name, int opt_scope,
- int fillchar, int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab,
- statuscol_T *stcp)
+int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex opt_idx,
+ int opt_scope, int fillchar, int maxwidth, stl_hlrec_t **hltab,
+ StlClickRecord **tabtab, statuscol_T *stcp)
{
static size_t stl_items_len = 20; // Initial value, grows as needed.
static stl_item_t *stl_items = NULL;
@@ -957,10 +957,10 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
stl_separator_locations = xmalloc(sizeof(int) * stl_items_len);
}
- // if "fmt" was set insecurely it needs to be evaluated in the sandbox
- // "opt_name" will be NULL when caller is nvim_eval_statusline()
- const int use_sandbox = opt_name ? was_set_insecurely(wp, opt_name, opt_scope)
- : false;
+ // If "fmt" was set insecurely it needs to be evaluated in the sandbox.
+ // "opt_idx" will be kOptInvalid when caller is nvim_eval_statusline().
+ const int use_sandbox = (opt_idx != kOptInvalid) ? was_set_insecurely(wp, opt_idx, opt_scope)
+ : false;
// When the format starts with "%!" then evaluate it as an expression and
// use the result as the actual format string.
@@ -1545,7 +1545,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
break;
case STL_SHOWCMD:
- if (p_sc && (opt_name == NULL || strcmp(opt_name, p_sloc) == 0)) {
+ if (p_sc && (opt_idx == kOptInvalid || findoption(p_sloc) == opt_idx)) {
str = showcmd_buf;
}
break;
@@ -2177,8 +2177,8 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
// TODO(Bram): find out why using called_emsg_before makes tests fail, does it
// matter?
// if (called_emsg > called_emsg_before)
- if (opt_name && did_emsg > did_emsg_before) {
- set_string_option_direct(opt_name, -1, "", OPT_FREE | opt_scope, SID_ERROR);
+ if (opt_idx != kOptInvalid && did_emsg > did_emsg_before) {
+ set_string_option_direct(opt_idx, "", OPT_FREE | opt_scope, SID_ERROR);
}
// A user function may reset KeyTyped, restore it.
diff --git a/src/nvim/statusline.h b/src/nvim/statusline.h
index eab7c1aa47..59a900d566 100644
--- a/src/nvim/statusline.h
+++ b/src/nvim/statusline.h
@@ -4,6 +4,7 @@
#include "nvim/buffer_defs.h" // IWYU pragma: keep
#include "nvim/macros_defs.h"
+#include "nvim/option_defs.h"
#include "nvim/statusline_defs.h" // IWYU pragma: export
/// Array defining what should be done when tabline is clicked
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index fda6aa41e8..af9693c4b0 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -233,7 +233,7 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
aucmd_prepbuf(&aco, buf);
refresh_screen(rv, buf);
- set_option_value("buftype", STATIC_CSTR_AS_OPTVAL("terminal"), OPT_LOCAL);
+ set_option_value(kOptBuftype, STATIC_CSTR_AS_OPTVAL("terminal"), OPT_LOCAL);
// Default settings for terminal buffers
buf->b_p_ma = false; // 'nomodifiable'
@@ -241,8 +241,8 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
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("wrap", BOOLEAN_OPTVAL(false), OPT_LOCAL);
- set_option_value("list", BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ 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));
}
diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c
index 7219e04add..3484d104fd 100644
--- a/src/nvim/textformat.c
+++ b/src/nvim/textformat.c
@@ -678,7 +678,7 @@ void auto_format(bool trailblank, bool prev_line)
// Do the formatting and restore the cursor position. "saved_cursor" will
// be adjusted for the text formatting.
saved_cursor = pos;
- format_lines((linenr_T) - 1, false);
+ format_lines(-1, false);
curwin->w_cursor = saved_cursor;
saved_cursor.lnum = 0;
@@ -761,7 +761,7 @@ int comp_textwidth(bool ff)
textwidth -= 1;
}
textwidth -= win_fdccol_count(curwin);
- textwidth -= win_signcol_count(curwin);
+ textwidth -= curwin->w_scwidth;
if (curwin->w_p_nu || curwin->w_p_rnu) {
textwidth -= 8;
@@ -870,7 +870,7 @@ void op_formatexpr(oparg_T *oap)
/// @param c character to be inserted
int fex_format(linenr_T lnum, long count, int c)
{
- int use_sandbox = was_set_insecurely(curwin, "formatexpr", OPT_LOCAL);
+ int use_sandbox = was_set_insecurely(curwin, kOptFormatexpr, OPT_LOCAL);
const sctx_T save_sctx = current_sctx;
// Set v:lnum to the first line number and v:count to the number of lines.
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index c533b288c1..6c47d1b5c7 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -156,14 +156,15 @@ void tinput_init(TermInput *input, Loop *loop)
rstream_init_fd(loop, &input->read_stream, input->in_fd, READ_STREAM_SIZE);
// initialize a timer handle for handling ESC with libtermkey
- time_watcher_init(loop, &input->timer_handle, input);
+ uv_timer_init(&loop->uv, &input->timer_handle);
+ input->timer_handle.data = input;
}
void tinput_destroy(TermInput *input)
{
map_destroy(int, &kitty_key_map);
rbuffer_free(input->key_buffer);
- time_watcher_close(&input->timer_handle, NULL);
+ uv_close((uv_handle_t *)&input->timer_handle, NULL);
stream_close(&input->read_stream, NULL, NULL);
termkey_destroy(input->tk);
}
@@ -176,7 +177,7 @@ void tinput_start(TermInput *input)
void tinput_stop(TermInput *input)
{
rstream_stop(&input->read_stream);
- time_watcher_stop(&input->timer_handle);
+ uv_timer_stop(&input->timer_handle);
}
static void tinput_done_event(void **argv)
@@ -466,17 +467,16 @@ static void tk_getkeys(TermInput *input, bool force)
if (input->ttimeout && input->ttimeoutlen >= 0) {
// Stop the current timer if already running
- time_watcher_stop(&input->timer_handle);
- time_watcher_start(&input->timer_handle, tinput_timer_cb,
- (uint64_t)input->ttimeoutlen, 0);
+ uv_timer_stop(&input->timer_handle);
+ uv_timer_start(&input->timer_handle, tinput_timer_cb, (uint64_t)input->ttimeoutlen, 0);
} else {
tk_getkeys(input, true);
}
}
-static void tinput_timer_cb(TimeWatcher *watcher, void *data)
+static void tinput_timer_cb(uv_timer_t *handle)
{
- TermInput *input = (TermInput *)data;
+ 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)) {
@@ -489,8 +489,8 @@ static void tinput_timer_cb(TimeWatcher *watcher, void *data)
/// Handle focus events.
///
/// If the upcoming sequence of bytes in the input stream matches the termcode
-/// for "focus gained" or "focus lost", consume that sequence and schedule an
-/// event on the main loop.
+/// for "focus gained" or "focus lost", consume that sequence and send an event
+/// to Nvim server.
///
/// @param input the input stream
/// @return true iff handle_focus_event consumed some input
@@ -757,8 +757,8 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *da
int64_t ms = input->ttimeout
? (input->ttimeoutlen >= 0 ? input->ttimeoutlen : 0) : 0;
// Stop the current timer if already running
- time_watcher_stop(&input->timer_handle);
- time_watcher_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0);
+ uv_timer_stop(&input->timer_handle);
+ uv_timer_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0);
return;
}
diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h
index 9d276277de..bc490754be 100644
--- a/src/nvim/tui/input.h
+++ b/src/nvim/tui/input.h
@@ -6,7 +6,6 @@
#include "nvim/event/loop.h"
#include "nvim/event/stream.h"
-#include "nvim/event/time.h"
#include "nvim/rbuffer_defs.h"
#include "nvim/tui/input_defs.h" // IWYU pragma: export
#include "nvim/tui/tui.h"
@@ -33,7 +32,7 @@ typedef struct {
OptInt ttimeoutlen;
TermKey *tk;
TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook
- TimeWatcher timer_handle;
+ uv_timer_t timer_handle;
Loop *loop;
Stream read_stream;
RBuffer *key_buffer;
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index c71eb633e9..70df1464ed 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -42,9 +42,6 @@
# include "nvim/os/tty.h"
#endif
-// Space reserved in two output buffers to make the cursor normal or invisible
-// when flushing. No existing terminal will require 32 bytes to do that.
-#define CNORM_COMMAND_MAX_SIZE 32
#define OUTBUF_SIZE 0xffff
#define TOO_MANY_EVENTS 1000000
@@ -77,7 +74,7 @@ struct TUIData {
TermInput input;
uv_loop_t write_loop;
unibi_term *ut;
- char *term; // value of $TERM
+ char *term; ///< value of $TERM
union {
uv_tty_t tty;
uv_pipe_t pipe;
@@ -148,7 +145,8 @@ static bool cursor_style_enabled = false;
# include "tui/tui.c.generated.h"
#endif
-void tui_start(TUIData **tui_p, int *width, int *height, char **term)
+void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb)
+ FUNC_ATTR_NONNULL_ALL
{
TUIData *tui = xcalloc(1, sizeof(TUIData));
tui->is_starting = true;
@@ -169,14 +167,14 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term)
uv_timer_init(&tui->loop->uv, &tui->startup_delay_timer);
tui->startup_delay_timer.data = tui;
- uv_timer_start(&tui->startup_delay_timer, after_startup_cb,
- 100, 0);
+ uv_timer_start(&tui->startup_delay_timer, after_startup_cb, 100, 0);
*tui_p = tui;
loop_poll_events(&main_loop, 1);
*width = tui->width;
*height = tui->height;
*term = tui->term;
+ *rgb = tui->rgb;
}
void tui_set_key_encoding(TUIData *tui)
@@ -334,6 +332,9 @@ static void terminfo_start(TUIData *tui)
int konsolev = konsolev_env ? (int)strtol(konsolev_env, NULL, 10)
: (konsole ? 1 : 0);
+ // truecolor support must be checked before patching/augmenting terminfo
+ tui->rgb = term_has_truecolor(tui, colorterm);
+
patch_terminfo_bugs(tui, term, colorterm, vtev, konsolev, iterm_env, nsterm);
augment_terminfo(tui, term, vtev, konsolev, iterm_env, nsterm);
tui->can_change_scroll_region =
@@ -1307,39 +1308,6 @@ void tui_default_colors_set(TUIData *tui, Integer rgb_fg, Integer rgb_bg, Intege
invalidate(tui, 0, tui->grid.height, 0, tui->grid.width);
}
-/// Begin flushing the TUI. If 'termsync' is set and the terminal supports synchronized updates,
-/// begin a synchronized update. Otherwise, hide the cursor to avoid cursor jumping.
-static void tui_flush_start(TUIData *tui)
- FUNC_ATTR_NONNULL_ALL
-{
- if (tui->sync_output && tui->unibi_ext.sync != -1) {
- UNIBI_SET_NUM_VAR(tui->params[0], 1);
- unibi_out_ext(tui, tui->unibi_ext.sync);
- } else if (!tui->is_invisible) {
- unibi_out(tui, unibi_cursor_invisible);
- tui->is_invisible = true;
- }
-}
-
-/// Finish flushing the TUI. If 'termsync' is set and the terminal supports synchronized updates,
-/// end a synchronized update. Otherwise, make the cursor visible again.
-static void tui_flush_end(TUIData *tui)
- FUNC_ATTR_NONNULL_ALL
-{
- if (tui->sync_output && tui->unibi_ext.sync != -1) {
- UNIBI_SET_NUM_VAR(tui->params[0], 0);
- unibi_out_ext(tui, tui->unibi_ext.sync);
- }
- bool should_invisible = tui->busy || tui->want_invisible;
- if (tui->is_invisible && !should_invisible) {
- unibi_out(tui, unibi_cursor_normal);
- tui->is_invisible = false;
- } else if (!tui->is_invisible && should_invisible) {
- unibi_out(tui, unibi_cursor_invisible);
- tui->is_invisible = true;
- }
-}
-
void tui_flush(TUIData *tui)
{
UGrid *grid = &tui->grid;
@@ -1356,8 +1324,6 @@ void tui_flush(TUIData *tui)
tui_busy_stop(tui); // avoid hidden cursor
}
- tui_flush_start(tui);
-
while (kv_size(tui->invalid_regions)) {
Rect r = kv_pop(tui->invalid_regions);
assert(r.bot <= grid->height && r.right <= grid->width);
@@ -1385,8 +1351,6 @@ void tui_flush(TUIData *tui)
cursor_goto(tui, tui->row, tui->col);
- tui_flush_end(tui);
-
flush_buf(tui);
}
@@ -1439,7 +1403,7 @@ void tui_suspend(TUIData *tui)
tui_mouse_on(tui);
}
stream_set_blocking(tui->input.in_fd, false); // libuv expects this
- ui_client_attach(tui->width, tui->height, tui->term);
+ ui_client_attach(tui->width, tui->height, tui->term, tui->rgb);
#endif
}
@@ -1752,6 +1716,44 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name)
return -1;
}
+/// 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
+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
+ 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"))) {
+ return true;
+ }
+ }
+
+ // Check for setrgbf and setrgbb
+ bool setrgbf = false;
+ bool setrgbb = false;
+ for (size_t i = 0; i < unibi_count_ext_str(tui->ut) && (!setrgbf || !setrgbb); i++) {
+ const char *n = unibi_get_ext_str_name(tui->ut, i);
+ if (n) {
+ if (!setrgbf && !strcmp(n, "setrgbf")) {
+ setrgbf = true;
+ } else if (!setrgbb && !strcmp(n, "setrgbb")) {
+ setrgbb = true;
+ }
+ }
+ }
+
+ return setrgbf && setrgbb;
+}
+
/// Patches the terminfo records after loading from system or built-in db.
/// Several entries in terminfo are known to be deficient or outright wrong;
/// and several terminal emulators falsely announce incorrect terminal types.
@@ -2253,23 +2255,97 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in
}
}
+static bool should_invisible(TUIData *tui)
+{
+ return tui->busy || tui->want_invisible;
+}
+
+/// Write the sequence to begin flushing output to `buf`.
+/// If 'termsync' is set and the terminal supports synchronized output, begin synchronized update.
+/// Otherwise, hide the cursor to avoid cursor jumping.
+///
+/// @param buf the buffer to write the sequence to
+/// @param len the length of `buf`
+static size_t flush_buf_start(TUIData *tui, char *buf, size_t len)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char *str = NULL;
+
+ if (tui->sync_output && tui->unibi_ext.sync != -1) {
+ UNIBI_SET_NUM_VAR(tui->params[0], 1);
+ str = unibi_get_ext_str(tui->ut, (size_t)tui->unibi_ext.sync);
+ } else if (!tui->is_invisible) {
+ str = unibi_get_str(tui->ut, unibi_cursor_invisible);
+ tui->is_invisible = true;
+ }
+
+ if (str == NULL) {
+ return 0;
+ }
+
+ return unibi_run(str, tui->params, buf, len);
+}
+
+/// Write the sequence to end flushing output to `buf`.
+/// If 'termsync' is set and the terminal supports synchronized output, end synchronized update.
+/// Otherwise, make the cursor visible again.
+///
+/// @param buf the buffer to write the sequence to
+/// @param len the length of `buf`
+static size_t flush_buf_end(TUIData *tui, char *buf, size_t len)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t offset = 0;
+ if (tui->sync_output && tui->unibi_ext.sync != -1) {
+ UNIBI_SET_NUM_VAR(tui->params[0], 0);
+ const char *str = unibi_get_ext_str(tui->ut, (size_t)tui->unibi_ext.sync);
+ offset = unibi_run(str, tui->params, buf, len);
+ }
+
+ const char *str = NULL;
+ if (tui->is_invisible && !should_invisible(tui)) {
+ str = unibi_get_str(tui->ut, unibi_cursor_normal);
+ tui->is_invisible = false;
+ } else if (!tui->is_invisible && should_invisible(tui)) {
+ str = unibi_get_str(tui->ut, unibi_cursor_invisible);
+ tui->is_invisible = true;
+ }
+
+ if (str != NULL) {
+ assert(len >= offset);
+ offset += unibi_run(str, tui->params, buf + offset, len - offset);
+ }
+
+ return offset;
+}
+
static void flush_buf(TUIData *tui)
{
uv_write_t req;
- uv_buf_t buf;
+ uv_buf_t bufs[3];
+ char pre[32];
+ char post[32];
- if (tui->bufpos <= 0) {
+ if (tui->bufpos <= 0 && tui->is_invisible == should_invisible(tui)) {
return;
}
- buf.base = tui->buf;
- buf.len = UV_BUF_LEN(tui->bufpos);
+ bufs[0].base = pre;
+ bufs[0].len = UV_BUF_LEN(flush_buf_start(tui, pre, sizeof(pre)));
+
+ bufs[1].base = tui->buf;
+ bufs[1].len = UV_BUF_LEN(tui->bufpos);
+
+ bufs[2].base = post;
+ bufs[2].len = UV_BUF_LEN(flush_buf_end(tui, post, sizeof(post)));
if (tui->screenshot) {
- fwrite(buf.base, buf.len, 1, tui->screenshot);
+ for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) {
+ fwrite(bufs[i].base, bufs[i].len, 1, tui->screenshot);
+ }
} else {
int ret
- = uv_write(&req, (uv_stream_t *)&tui->output_handle, &buf, 1, NULL);
+ = uv_write(&req, (uv_stream_t *)&tui->output_handle, bufs, ARRAY_SIZE(bufs), NULL);
if (ret) {
ELOG("uv_write failed: %s", uv_strerror(ret));
}
diff --git a/src/nvim/types_defs.h b/src/nvim/types_defs.h
index c06737abb5..27227685fa 100644
--- a/src/nvim/types_defs.h
+++ b/src/nvim/types_defs.h
@@ -48,3 +48,10 @@ typedef enum {
#define TRISTATE_FROM_INT(val) ((val) == 0 ? kFalse : ((val) >= 1 ? kTrue : kNone))
typedef int64_t OptInt;
+
+// Range entry for the "b_signcols.invalid" map in which the keys are the range start.
+typedef struct {
+ int end; // End of the invalid range.
+ int add; // Number of signs added in the invalid range, negative for deleted signs.
+} SignRange;
+#define SIGNRANGE_INIT { 0, 0 }
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index cb4ebb5c3b..0fc0c5bf86 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -63,6 +63,7 @@ bool ui_cb_ext[kUIExtCount]; ///< Internalized UI capabilities.
static bool has_mouse = false;
static int pending_has_mouse = -1;
+static bool pending_default_colors = false;
static Array call_buf = ARRAY_DICT_INIT;
@@ -234,7 +235,7 @@ void ui_refresh(void)
p_lz = save_p_lz;
if (ext_widgets[kUIMessages]) {
- set_option_value("cmdheight", NUMBER_OPTVAL(0), 0);
+ set_option_value(kOptCmdheight, NUMBER_OPTVAL(0), 0);
command_height();
}
ui_mode_info_set();
@@ -283,8 +284,21 @@ void ui_schedule_refresh(void)
void ui_default_colors_set(void)
{
- ui_call_default_colors_set(normal_fg, normal_bg, normal_sp,
- cterm_normal_fg_color, cterm_normal_bg_color);
+ // Throttle setting of default colors at startup, so it only happens once
+ // if the user sets the colorscheme in startup.
+ pending_default_colors = true;
+ if (starting == 0) {
+ ui_may_set_default_colors();
+ }
+}
+
+static void ui_may_set_default_colors(void)
+{
+ if (pending_default_colors) {
+ pending_default_colors = false;
+ ui_call_default_colors_set(normal_fg, normal_bg, normal_sp,
+ cterm_normal_fg_color, cterm_normal_bg_color);
+ }
}
void ui_busy_start(void)
@@ -442,6 +456,9 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
flags |= kLineFlagInvalid;
}
+ // set default colors now so that that text won't have to be repainted later
+ ui_may_set_default_colors();
+
size_t off = grid->line_offset[row] + (size_t)startcol;
ui_call_raw_line(grid->handle, row, startcol, endcol, clearcol, clearattr,
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index eb32c16881..d744560a86 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -70,14 +70,14 @@ uint64_t ui_client_start_server(int argc, char **argv)
return channel->id;
}
-void ui_client_attach(int width, int height, char *term)
+void ui_client_attach(int width, int height, char *term, bool rgb)
{
MAXSIZE_TEMP_ARRAY(args, 3);
ADD_C(args, INTEGER_OBJ(width));
ADD_C(args, INTEGER_OBJ(height));
MAXSIZE_TEMP_DICT(opts, 9);
- PUT_C(opts, "rgb", BOOLEAN_OBJ(true));
+ PUT_C(opts, "rgb", BOOLEAN_OBJ(rgb));
PUT_C(opts, "ext_linegrid", BOOLEAN_OBJ(true));
PUT_C(opts, "ext_termcolors", BOOLEAN_OBJ(true));
if (term) {
@@ -111,9 +111,10 @@ void ui_client_run(bool remote_ui)
ui_client_is_remote = remote_ui;
int width, height;
char *term;
- tui_start(&tui, &width, &height, &term);
+ bool rgb;
+ tui_start(&tui, &width, &height, &term, &rgb);
- ui_client_attach(width, height, term);
+ ui_client_attach(width, height, term, rgb);
// os_exit() will be invoked when the client channel detaches
while (true) {
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 928dd2967c..fd3bb41de0 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -3031,9 +3031,9 @@ void u_undoline(void)
char *oldp = u_save_line(curbuf->b_u_line_lnum);
ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, true);
- changed_bytes(curbuf->b_u_line_lnum, 0);
extmark_splice_cols(curbuf, (int)curbuf->b_u_line_lnum - 1, 0, (colnr_T)strlen(oldp),
(colnr_T)strlen(curbuf->b_u_line_ptr), kExtmarkUndo);
+ changed_bytes(curbuf->b_u_line_lnum, 0);
xfree(curbuf->b_u_line_ptr);
curbuf->b_u_line_ptr = oldp;
diff --git a/src/nvim/version.c b/src/nvim/version.c
index fc93a01b32..2caf2c0cb8 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -896,7 +896,7 @@ static const int included_patches[] = {
// 1586,
1585,
// 1584,
- // 1583,
+ 1583,
1582,
1581,
// 1580,
diff --git a/src/nvim/window.c b/src/nvim/window.c
index ef1ef89d95..98c62d6f44 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5183,7 +5183,7 @@ void win_new_screensize(void)
if (old_Rows != Rows) {
// If 'window' uses the whole screen, keep it using that.
// Don't change it when set with "-w size" on the command line.
- if (p_window == old_Rows - 1 || (old_Rows == 0 && !option_was_set("window"))) {
+ if (p_window == old_Rows - 1 || (old_Rows == 0 && !option_was_set(kOptWindow))) {
p_window = Rows - 1;
}
old_Rows = Rows;