aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-02-02 19:02:58 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-02-02 19:02:58 +0000
commitb255fa570d8b041e4c81e3454d51e06100c2fa4f (patch)
treed3b246b467500ca48067ed4a45d2fa53966cd9f1 /src
parenteeccad2ff1ae8892fe9e06d733a7b07a166eecb0 (diff)
parent0bd07bea095a8000cffa4f379c1fa53e009c1143 (diff)
downloadrneovim-20230125_mix.tar.gz
rneovim-20230125_mix.tar.bz2
rneovim-20230125_mix.zip
Merge branch 'aucmd_textputpost' into 20230125_mix20230125_mix
Diffstat (limited to 'src')
-rwxr-xr-xsrc/nvim/CMakeLists.txt59
-rw-r--r--src/nvim/api/autocmd.c2
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/buffer_defs.h1
-rw-r--r--src/nvim/cmdexpand.c19
-rw-r--r--src/nvim/drawline.c13
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/eval.lua68
-rw-r--r--src/nvim/eval/funcs.c55
-rw-r--r--src/nvim/eval/typval.c80
-rw-r--r--src/nvim/eval/userfunc.c9
-rw-r--r--src/nvim/eval/vars.c2
-rw-r--r--src/nvim/file_search.c2
-rw-r--r--src/nvim/fileio.c178
-rw-r--r--src/nvim/getchar.c12
-rw-r--r--src/nvim/highlight.c10
-rw-r--r--src/nvim/highlight_defs.h4
-rw-r--r--src/nvim/highlight_group.c9
-rw-r--r--src/nvim/lua/executor.c70
-rw-r--r--src/nvim/main.c21
-rw-r--r--src/nvim/marktree.c2
-rw-r--r--src/nvim/memline.c5
-rw-r--r--src/nvim/message.c2
-rw-r--r--src/nvim/normal.c4
-rw-r--r--src/nvim/ops.c52
-rw-r--r--src/nvim/option.c972
-rw-r--r--src/nvim/optionstr.c308
-rw-r--r--src/nvim/os/fs.c6
-rw-r--r--src/nvim/path.c2
-rw-r--r--src/nvim/regexp_bt.c2
-rw-r--r--src/nvim/regexp_nfa.c2
-rw-r--r--src/nvim/runtime.c244
-rw-r--r--src/nvim/screen.c11
-rw-r--r--src/nvim/search.c7
-rw-r--r--src/nvim/sign.c2
-rw-r--r--src/nvim/sign_defs.h6
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/spellfile.c2
-rw-r--r--src/nvim/spellsuggest.c2
-rw-r--r--src/nvim/syntax.c2
-rw-r--r--src/nvim/tag.c228
-rwxr-xr-xsrc/nvim/testdir/runnvim.sh3
-rw-r--r--src/nvim/testdir/test_edit.vim15
-rw-r--r--src/nvim/testdir/test_filetype.vim9
-rw-r--r--src/nvim/testdir/test_fold.vim58
-rw-r--r--src/nvim/testdir/test_gf.vim25
-rw-r--r--src/nvim/testdir/test_normal.vim46
-rw-r--r--src/nvim/testdir/test_packadd.vim84
-rw-r--r--src/nvim/testdir/test_search_stat.vim23
-rw-r--r--src/nvim/testdir/test_taglist.vim4
-rw-r--r--src/nvim/testdir/test_virtualedit.vim13
-rw-r--r--src/nvim/testdir/test_visual.vim11
-rw-r--r--src/nvim/testing.c49
-rw-r--r--src/nvim/textformat.c32
-rw-r--r--src/nvim/tui/input.c16
-rw-r--r--src/nvim/tui/input.h8
-rw-r--r--src/nvim/tui/tui.c5
-rw-r--r--src/nvim/ui_client.c29
-rw-r--r--src/nvim/undo.c8
-rw-r--r--src/nvim/usercmd.c1
-rw-r--r--src/nvim/version.c46
-rw-r--r--src/nvim/vim.h1
-rw-r--r--src/nvim/window.c30
63 files changed, 1738 insertions, 1258 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 2361210e59..7b56af59da 100755
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -22,17 +22,15 @@ find_package(TreeSitter REQUIRED)
target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${TreeSitter_INCLUDE_DIRS})
target_link_libraries(main_lib INTERFACE ${TreeSitter_LIBRARIES})
-find_package(UNIBILIUM 2.0 REQUIRED)
-target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${UNIBILIUM_INCLUDE_DIRS})
-target_link_libraries(main_lib INTERFACE ${UNIBILIUM_LIBRARIES})
+find_package(unibilium 2.0 REQUIRED)
+target_link_libraries(main_lib INTERFACE unibilium)
find_package(LibTermkey 0.22 REQUIRED)
target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBTERMKEY_INCLUDE_DIRS})
target_link_libraries(main_lib INTERFACE ${LIBTERMKEY_LIBRARIES})
-find_package(LIBVTERM 0.3 REQUIRED)
-target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBVTERM_INCLUDE_DIRS})
-target_link_libraries(main_lib INTERFACE ${LIBVTERM_LIBRARIES})
+find_package(libvterm 0.3 REQUIRED)
+target_link_libraries(main_lib INTERFACE libvterm)
find_package(Iconv REQUIRED)
target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${Iconv_INCLUDE_DIRS})
@@ -54,7 +52,7 @@ if(PREFER_LUA)
find_package(Lua 5.1 EXACT REQUIRED)
target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUA_INCLUDE_DIR})
target_link_libraries(main_lib INTERFACE ${LUA_LIBRARIES})
- # Passive (not REQUIRED): if LUAJIT_FOUND is not set, nvim-test is skipped.
+ # Passive (not REQUIRED): if LUAJIT_FOUND is not set, fixtures for unittests is skipped.
find_package(LuaJit)
else()
find_package(LuaJit REQUIRED)
@@ -175,24 +173,6 @@ if(CI_BUILD)
endif()
endif()
-list(APPEND CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}")
-list(APPEND CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}")
-check_c_source_compiles("
-#include <unibilium.h>
-
-int
-main(void)
-{
- unibi_str_from_var(unibi_var_from_str(\"\"));
- return unibi_num_from_var(unibi_var_from_num(0));
-}
-" UNIBI_HAS_VAR_FROM)
-list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}")
-list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}")
-if(UNIBI_HAS_VAR_FROM)
- target_compile_definitions(main_lib INTERFACE NVIM_UNIBI_HAS_VAR_FROM)
-endif()
-
list(APPEND CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}")
check_c_source_compiles("
#include <msgpack.h>
@@ -699,6 +679,14 @@ if(UNIX)
endif()
endif()
+if(NOT LUAJIT_FOUND)
+ message(STATUS "luajit not found, skipping unit tests")
+elseif(CMAKE_BUILD_TYPE MATCHES Debug)
+ glob_wrapper(UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c)
+ list(APPEND NVIM_SOURCES ${UNIT_TEST_FIXTURES})
+ target_compile_definitions(main_lib INTERFACE UNIT_TESTING)
+endif()
+
target_sources(nvim PRIVATE ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS}
${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS})
@@ -857,27 +845,6 @@ set_target_properties(
target_compile_definitions(libnvim PRIVATE MAKE_LIB)
target_link_libraries(libnvim PRIVATE main_lib PUBLIC libuv_lib)
-if(NOT LUAJIT_FOUND)
- message(STATUS "luajit not found, skipping nvim-test (unit tests) target")
-else()
- glob_wrapper(UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c)
- add_library(
- nvim-test
- MODULE
- EXCLUDE_FROM_ALL
- ${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
- ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
- ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}
- ${UNIT_TEST_FIXTURES}
- )
- target_link_libraries(nvim-test PRIVATE ${LUAJIT_LIBRARIES} main_lib PUBLIC libuv_lib)
- if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
- target_link_libraries(nvim-test PRIVATE "-framework CoreServices")
- endif()
- target_include_directories(nvim-test PRIVATE ${LUAJIT_INCLUDE_DIRS})
- target_compile_definitions(nvim-test PRIVATE UNIT_TESTING)
-endif()
-
if(CLANG_ASAN_UBSAN)
message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.")
if(CI_BUILD)
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 931363e199..a2cb297b15 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -404,7 +404,7 @@ cleanup:
/// - match: (string) expanded value of |<amatch>|
/// - buf: (number) expanded value of |<abuf>|
/// - file: (string) expanded value of |<afile>|
-/// - data: (any) arbitrary data passed to |nvim_exec_autocmds()|
+/// - data: (any) arbitrary data passed from |nvim_exec_autocmds()|
/// - command (string) optional: Vim command to execute on event. Cannot be used with
/// {callback}
/// - once (boolean) optional: defaults to false. Run the autocommand
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index a75ee3bbd5..fb0062e524 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -110,6 +110,7 @@ return {
'TextChangedP', -- text was modified in Insert mode(popup)
'TextChangedT', -- text was modified in Terminal mode
'TextYankPost', -- after a yank or delete was done (y, d, c)
+ 'TextPutPost', -- after a put was done (p, P)
'UIEnter', -- after UI attaches
'UILeave', -- after UI detaches
'User', -- user defined autocommand
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 5c1e3af015..28c3374c0c 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -1410,6 +1410,7 @@ struct window_S {
int w_prev_fraction_row;
linenr_T w_nrwidth_line_count; // line count when ml_nrwidth_width was computed.
+ linenr_T w_statuscol_line_count; // line count when 'statuscolumn' width was computed.
int w_nrwidth_width; // nr of chars to print line count.
qf_info_T *w_llist; // Location list for this window
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index be815151ef..5e4b49db24 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -109,6 +109,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp)
&& xp->xp_context != EXPAND_OLD_SETTING
&& xp->xp_context != EXPAND_OWNSYNTAX
&& xp->xp_context != EXPAND_PACKADD
+ && xp->xp_context != EXPAND_RUNTIME
&& xp->xp_context != EXPAND_SHELLCMD
&& xp->xp_context != EXPAND_TAGS
&& xp->xp_context != EXPAND_TAGS_LISTFILES
@@ -1215,6 +1216,7 @@ char *addstar(char *fname, size_t len, int context)
|| context == EXPAND_OWNSYNTAX
|| context == EXPAND_FILETYPE
|| context == EXPAND_PACKADD
+ || context == EXPAND_RUNTIME
|| ((context == EXPAND_TAGS_LISTFILES || context == EXPAND_TAGS)
&& fname[0] == '/')) {
retval = xstrnsave(fname, len);
@@ -2092,6 +2094,10 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa
xp->xp_pattern = (char *)arg;
break;
+ case CMD_runtime:
+ set_context_in_runtime_cmd(xp, arg);
+ break;
+
#ifdef HAVE_WORKING_LIBINTL
case CMD_language:
return set_context_in_lang_cmd(xp, arg);
@@ -2733,6 +2739,9 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
if (xp->xp_context == EXPAND_PACKADD) {
return ExpandPackAddDir(pat, numMatches, matches);
}
+ if (xp->xp_context == EXPAND_RUNTIME) {
+ return expand_runtime_cmd(pat, numMatches, matches);
+ }
// When expanding a function name starting with s:, match the <SNR>nr_
// prefix.
@@ -3201,11 +3210,12 @@ static int ExpandUserLua(expand_T *xp, int *num_file, char ***file)
/// Expand `file` for all comma-separated directories in `path`.
/// Adds matches to `ga`.
-void globpath(char *path, char *file, garray_T *ga, int expand_options)
+/// If "dirs" is true only expand directory names.
+void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dirs)
{
expand_T xpc;
ExpandInit(&xpc);
- xpc.xp_context = EXPAND_FILES;
+ xpc.xp_context = dirs ? EXPAND_DIRECTORIES : EXPAND_FILES;
char *buf = xmalloc(MAXPATHL);
@@ -3524,11 +3534,14 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
set_context_in_menu_cmd(&xpc, "menu", xpc.xp_pattern, false);
xpc.xp_pattern_len = strlen(xpc.xp_pattern);
}
-
if (xpc.xp_context == EXPAND_SIGN) {
set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
xpc.xp_pattern_len = strlen(xpc.xp_pattern);
}
+ if (xpc.xp_context == EXPAND_RUNTIME) {
+ set_context_in_runtime_cmd(&xpc, xpc.xp_pattern);
+ xpc.xp_pattern_len = strlen(xpc.xp_pattern);
+ }
theend:
if (cmdline_fuzzy_completion_supported(&xpc)) {
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 031ad39f75..83aa68194c 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -412,7 +412,6 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, i
bool use_cul = use_cursor_line_sign(wp, lnum);
int virtnum = row - startrow - filler_lines;
- set_vim_var_nr(VV_VIRTNUM, virtnum);
// When called the first time for line "lnum" set num_attr
if (stcp->num_attr == 0) {
stcp->num_attr = sign_num_attr ? sign_num_attr
@@ -437,6 +436,18 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, i
}
stcp->sign_text[i] = NULL;
+ // When a buffer's line count has changed, make a best estimate for the full
+ // width of the status column by building with "w_nrwidth_line_count". Add
+ // potentially truncated width and rebuild before drawing anything.
+ if (wp->w_statuscol_line_count != wp->w_nrwidth_line_count) {
+ wp->w_statuscol_line_count = wp->w_nrwidth_line_count;
+ set_vim_var_nr(VV_VIRTNUM, 0);
+ build_statuscol_str(wp, wp->w_nrwidth_line_count, 0, stcp->width,
+ ' ', stcp->text, &stcp->hlrec, stcp);
+ stcp->width += stcp->truncate;
+ }
+ set_vim_var_nr(VV_VIRTNUM, virtnum);
+
int width = build_statuscol_str(wp, lnum, relnum, stcp->width,
' ', stcp->text, &stcp->hlrec, stcp);
// Force a redraw in case of error or when truncated
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 095d73f53f..96df6a3044 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1483,7 +1483,7 @@ static void init_prompt(int cmdchar_todo)
}
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
coladvance(MAXCOL);
- changed_bytes(curbuf->b_ml.ml_line_count, 0);
+ inserted_bytes(curbuf->b_ml.ml_line_count, 0, 0, (colnr_T)strlen(prompt));
}
// Insert always starts after the prompt, allow editing text after it.
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index c17a44b990..9a5ab51c71 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -26,7 +26,7 @@ return {
acos={args=1, base=1, float_func="acos"}, -- WJMc
add={args=2, base=1},
['and']={args=2, base=1},
- api_info={},
+ api_info={fast=true},
append={args=2, base=2},
appendbufline={args=3, base=3},
argc={args={0, 1}},
@@ -64,14 +64,14 @@ return {
bufwinid={args=1, base=1},
bufwinnr={args=1, base=1},
byte2line={args=1, base=1},
- byteidx={args=2, base=1},
- byteidxcomp={args=2, base=1},
+ byteidx={args=2, base=1, fast=true},
+ byteidxcomp={args=2, base=1, fast=true},
call={args={2, 3}, base=1},
ceil={args=1, base=1, float_func="ceil"},
changenr={},
chanclose={args={1, 2}},
chansend={args=2},
- char2nr={args={1, 2}, base=1},
+ char2nr={args={1, 2}, base=1, fast=true},
charclass={args=1, base=1},
charcol={args={1, 2}, base=1},
charidx={args={2, 3}, base=1},
@@ -100,7 +100,7 @@ return {
deletebufline={args={2,3}, base=1},
dictwatcheradd={args=3},
dictwatcherdel={args=3},
- did_filetype={},
+ did_filetype={fast=true},
diff_filler={args=1, base=1},
diff_hlID={args=2, base=1},
digraph_get={args=1, base=1},
@@ -108,11 +108,11 @@ return {
digraph_set={args=2, base=1},
digraph_setlist={args=1, base=1},
empty={args=1, base=1},
- environ={},
- escape={args=2, base=1},
+ environ={fast=true},
+ escape={args=2, base=1, fast=true},
eval={args=1, base=1},
eventhandler={},
- executable={args=1, base=1},
+ executable={args=1, base=1, fast=true},
execute={args={1, 2}, base=1},
exepath={args=1, base=1},
exists={args=1, base=1},
@@ -122,8 +122,8 @@ return {
extend={args={2, 3}, base=1},
feedkeys={args={1, 2}, base=1},
file_readable={args=1, base=1, func='f_filereadable'}, -- obsolete
- filereadable={args=1, base=1},
- filewritable={args=1, base=1},
+ filereadable={args=1, base=1, fast=true},
+ filewritable={args=1, base=1, fast=true},
filter={args=2, base=1},
finddir={args={1, 3}, base=1},
findfile={args={1, 3}, base=1},
@@ -131,8 +131,8 @@ return {
float2nr={args=1, base=1},
floor={args=1, base=1, float_func="floor"},
fmod={args=2, base=1},
- fnameescape={args=1, base=1},
- fnamemodify={args=2, base=1},
+ fnameescape={args=1, base=1, fast=true},
+ fnamemodify={args=2, base=1, fast=true},
foldclosed={args=1, base=1},
foldclosedend={args=1, base=1},
foldlevel={args=1, base=1},
@@ -167,17 +167,17 @@ return {
getcwd={args={0, 2}, base=1},
getenv={args=1, base=1},
getfontname={args={0, 1}},
- getfperm={args=1, base=1},
- getfsize={args=1, base=1},
- getftime={args=1, base=1},
- getftype={args=1, base=1},
+ getfperm={args=1, base=1, fast=true},
+ getfsize={args=1, base=1, fast=true},
+ getftime={args=1, base=1, fast=true},
+ getftype={args=1, base=1, fast=true},
getjumplist={args={0, 2}, base=1},
getline={args={1, 2}, base=1},
getloclist={args={1, 2}},
getmarklist={args={0, 1}, base=1},
getmatches={args={0, 1}},
getmousepos={},
- getpid={},
+ getpid={fast=true},
getpos={args=1, base=1},
getqflist={args={0, 1}},
getreg={args={0, 3}, base=1},
@@ -208,7 +208,7 @@ return {
histnr={args=1, base=1},
hlID={args=1, base=1},
hlexists={args=1, base=1},
- hostname={},
+ hostname={fast=true},
iconv={args=3, base=1, fast=true},
indent={args=1, base=1},
index={args={2, 4}, base=1},
@@ -221,7 +221,7 @@ return {
insert={args={2, 3}, base=1},
interrupt={args=0},
invert={args=1, base=1},
- isdirectory={args=1, base=1},
+ isdirectory={args=1, base=1, fast=true},
isinf={args=1, base=1},
islocked={args=1, base=1},
isnan={args=1, base=1},
@@ -300,13 +300,13 @@ return {
reg_executing={},
reg_recording={},
reg_recorded={},
- reltime={args={0, 2}, base=1},
- reltimefloat={args=1, base=1},
- reltimestr={args=1, base=1},
+ reltime={args={0, 2}, base=1, fast=true},
+ reltimefloat={args=1, base=1, fast=true},
+ reltimestr={args=1, base=1, fast=true},
remove={args={2, 3}, base=1},
rename={args=2, base=1},
- ['repeat']={args=2, base=1},
- resolve={args=1, base=1},
+ ['repeat']={args=2, base=1, fast=true},
+ resolve={args=1, base=1, fast=true},
reverse={args=1, base=1},
round={args=1, base=1, float_func="round"},
rpcnotify={args=varargs(2)},
@@ -374,24 +374,24 @@ return {
split={args={1, 3}, base=1},
sqrt={args=1, base=1, float_func="sqrt"},
srand={args={0, 1}, base=1},
- stdpath={args=1},
+ stdpath={args=1, fast=true},
str2float={args=1, base=1},
str2list={args={1, 2}, base=1},
str2nr={args={1, 3}, base=1},
strcharlen={args=1, base=1},
- strcharpart={args={2, 3}, base=1},
+ strcharpart={args={2, 3}, base=1, fast=true},
strchars={args={1, 2}, base=1},
strdisplaywidth={args={1, 2}, base=1},
strftime={args={1, 2}, base=1},
strgetchar={args=2, base=1},
- stridx={args={2, 3}, base=1},
+ stridx={args={2, 3}, base=1, fast=true},
string={args=1, base=1},
strlen={args=1, base=1},
- strpart={args={2, 4}, base=1},
+ strpart={args={2, 4}, base=1, fast=true},
strptime={args=2, base=1},
strridx={args={2, 3}, base=1},
- strtrans={args=1, base=1},
- strwidth={args=1, base=1},
+ strtrans={args=1, base=1, fast=true},
+ strwidth={args=1, base=1, fast=true},
submatch={args={1, 2}, base=1},
substitute={args=4, base=1},
swapinfo={args=1, base=1},
@@ -419,12 +419,12 @@ return {
timer_start={args={2, 3}, base=1},
timer_stop={args=1, base=1},
timer_stopall={args=0},
- tolower={args=1, base=1},
- toupper={args=1, base=1},
+ tolower={args=1, base=1, fast=true},
+ toupper={args=1, base=1, fast=true},
tr={args=3, base=1},
trim={args={1, 3}, base=1},
trunc={args=1, base=1, float_func="trunc"},
- type={args=1, base=1},
+ type={args=1, base=1, fast=true},
undofile={args=1, base=1},
undotree={},
uniq={args={1, 3}, base=1},
@@ -447,7 +447,7 @@ return {
win_splitmove={args={2, 3}, base=1},
winbufnr={args=1, base=1},
wincol={},
- windowsversion={},
+ windowsversion={fast=true},
winheight={args=1, base=1},
winlayout={args={0, 1}, base=1},
winline={},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 33f8af451f..569c1462d1 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -2983,7 +2983,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (file != NULL && !error) {
garray_T ga;
ga_init(&ga, (int)sizeof(char *), 10);
- globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags);
+ globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags, false);
if (rettv->v_type == VAR_STRING) {
rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n");
@@ -3064,9 +3064,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"conceal",
"cursorbind",
"cursorshape",
-#ifdef DEBUG
- "debug",
-#endif
"dialog_con",
"diff",
"digraphs",
@@ -7826,34 +7823,35 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// MSVC returns NULL for an invalid value of seconds.
if (curtime_ptr == NULL) {
rettv->vval.v_string = xstrdup(_("(Invalid)"));
- } else {
- vimconv_T conv;
+ return;
+ }
- conv.vc_type = CONV_NONE;
- char *enc = enc_locale();
- convert_setup(&conv, p_enc, enc);
- if (conv.vc_type != CONV_NONE) {
- p = string_convert(&conv, p, NULL);
- }
- char result_buf[256];
- if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) {
- result_buf[0] = NUL;
- }
+ vimconv_T conv;
- if (conv.vc_type != CONV_NONE) {
- xfree(p);
- }
- convert_setup(&conv, enc, p_enc);
- if (conv.vc_type != CONV_NONE) {
- rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
- } else {
- rettv->vval.v_string = xstrdup(result_buf);
- }
+ conv.vc_type = CONV_NONE;
+ char *enc = enc_locale();
+ convert_setup(&conv, p_enc, enc);
+ if (conv.vc_type != CONV_NONE) {
+ p = string_convert(&conv, p, NULL);
+ }
+ char result_buf[256];
+ if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) {
+ result_buf[0] = NUL;
+ }
- // Release conversion descriptors.
- convert_setup(&conv, NULL, NULL);
- xfree(enc);
+ if (conv.vc_type != CONV_NONE) {
+ xfree(p);
}
+ convert_setup(&conv, enc, p_enc);
+ if (conv.vc_type != CONV_NONE) {
+ rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
+ } else {
+ rettv->vval.v_string = xstrdup(result_buf);
+ }
+
+ // Release conversion descriptors.
+ convert_setup(&conv, NULL, NULL);
+ xfree(enc);
}
/// "strgetchar()" function
@@ -8657,6 +8655,7 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, EvalFuncData fptr
emsg(_(e_number_exp));
return;
}
+
int paused = (bool)tv_get_number(&argvars[1]);
timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0]));
if (timer != NULL) {
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 05b4737206..c298064d86 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -3208,17 +3208,19 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic
/// @param[in,out] tv Value to free.
void tv_clear(typval_T *const tv)
{
- if (tv != NULL && tv->v_type != VAR_UNKNOWN) {
- // WARNING: do not translate the string here, gettext is slow and function
- // is used *very* often. At the current state encode_vim_to_nothing() does
- // not error out and does not use the argument anywhere.
- //
- // If situation changes and this argument will be used, translate it in the
- // place where it is used.
- const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument");
- (void)evn_ret;
- assert(evn_ret == OK);
+ if (tv == NULL || tv->v_type == VAR_UNKNOWN) {
+ return;
}
+
+ // WARNING: do not translate the string here, gettext is slow and function
+ // is used *very* often. At the current state encode_vim_to_nothing() does
+ // not error out and does not use the argument anywhere.
+ //
+ // If situation changes and this argument will be used, translate it in the
+ // place where it is used.
+ const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument");
+ (void)evn_ret;
+ assert(evn_ret == OK);
}
//{{{3 Free
@@ -3228,35 +3230,37 @@ void tv_clear(typval_T *const tv)
/// @param tv Object to free.
void tv_free(typval_T *tv)
{
- if (tv != NULL) {
- switch (tv->v_type) {
- case VAR_PARTIAL:
- partial_unref(tv->vval.v_partial);
- break;
- case VAR_FUNC:
- func_unref(tv->vval.v_string);
- FALLTHROUGH;
- case VAR_STRING:
- xfree(tv->vval.v_string);
- break;
- case VAR_BLOB:
- tv_blob_unref(tv->vval.v_blob);
- break;
- case VAR_LIST:
- tv_list_unref(tv->vval.v_list);
- break;
- case VAR_DICT:
- tv_dict_unref(tv->vval.v_dict);
- break;
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_UNKNOWN:
- break;
- }
- xfree(tv);
+ if (tv == NULL) {
+ return;
+ }
+
+ switch (tv->v_type) {
+ case VAR_PARTIAL:
+ partial_unref(tv->vval.v_partial);
+ break;
+ case VAR_FUNC:
+ func_unref(tv->vval.v_string);
+ FALLTHROUGH;
+ case VAR_STRING:
+ xfree(tv->vval.v_string);
+ break;
+ case VAR_BLOB:
+ tv_blob_unref(tv->vval.v_blob);
+ break;
+ case VAR_LIST:
+ tv_list_unref(tv->vval.v_list);
+ break;
+ case VAR_DICT:
+ tv_dict_unref(tv->vval.v_dict);
+ break;
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN:
+ break;
}
+ xfree(tv);
}
//{{{3 Copy
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 3fe5a0d7c7..ab81c190b0 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -760,13 +760,12 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force)
static bool func_remove(ufunc_T *fp)
{
hashitem_T *hi = hash_find(&func_hashtab, (char *)UF2HIKEY(fp));
-
- if (!HASHITEM_EMPTY(hi)) {
- hash_remove(&func_hashtab, hi);
- return true;
+ if (HASHITEM_EMPTY(hi)) {
+ return false;
}
- return false;
+ hash_remove(&func_hashtab, hi);
+ return true;
}
static void func_clear_items(ufunc_T *fp)
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 58fb2211fc..f38dc90e9d 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -1352,7 +1352,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
// Make sure dict is valid
assert(dict != NULL);
- v = xmalloc(sizeof(dictitem_T) + strlen(varname));
+ v = xmalloc(offsetof(dictitem_T, di_key) + strlen(varname) + 1);
STRCPY(v->di_key, varname);
if (hash_add(ht, (char *)v->di_key) == FAIL) {
xfree(v);
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index e236f23895..a0435afd65 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1092,7 +1092,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_p
}
// New file/dir. Add it to the list of visited files/dirs.
- vp = xmalloc(sizeof(ff_visited_T) + strlen(ff_expand_buffer));
+ vp = xmalloc(offsetof(ff_visited_T, ffv_fname) + strlen(ff_expand_buffer) + 1);
if (!url) {
vp->file_id_valid = true;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 9da9d6199e..fbb5c4f1fa 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -968,13 +968,11 @@ retry:
if (read_buf_lnum > from) {
size = 0;
} else {
- int n, ni;
- long tlen;
-
- tlen = 0;
+ int ni;
+ long tlen = 0;
for (;;) {
p = (char_u *)ml_get(read_buf_lnum) + read_buf_col;
- n = (int)strlen((char *)p);
+ int n = (int)strlen((char *)p);
if ((int)tlen + n + 1 > size) {
// Filled up to "size", append partial line.
// Change NL to NUL to reverse the effect done
@@ -2126,7 +2124,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
bool errmsg_allocated = false;
char *buffer;
char smallbuf[SMBUFSIZE];
- char *backup_ext;
int bufsize;
long perm; // file permissions
int retval = OK;
@@ -2555,8 +2552,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
if ((bkc & BKC_YES) || append) { // "yes"
backup_copy = true;
} else if ((bkc & BKC_AUTO)) { // "auto"
- int i;
-
// Don't rename the file when:
// - it's a hard link
// - it's a symbolic link
@@ -2571,7 +2566,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
// First find a file name that doesn't exist yet (use some
// arbitrary numbers).
STRCPY(IObuff, fname);
- for (i = 4913;; i += 123) {
+ for (int i = 4913;; i += 123) {
char *tail = path_tail(IObuff);
size_t size = (size_t)(tail - IObuff);
snprintf(tail, IOSIZE - size, "%d", i);
@@ -2624,18 +2619,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
}
// make sure we have a valid backup extension to use
- if (*p_bex == NUL) {
- backup_ext = ".bak";
- } else {
- backup_ext = p_bex;
- }
+ char *backup_ext = *p_bex == NUL ? ".bak" : p_bex;
if (backup_copy) {
- char *wp;
int some_error = false;
- char *dirp;
- char *rootname;
- char *p;
// Try to make the backup in each directory in the 'bdir' option.
//
@@ -2647,11 +2634,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
//
// For these reasons, the existing writable file must be truncated
// and reused. Creation of a backup COPY will be attempted.
- dirp = p_bdir;
+ char *dirp = p_bdir;
while (*dirp) {
// Isolate one directory name, using an entry in 'bdir'.
size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ",");
- p = IObuff + dir_len;
+ char *p = IObuff + dir_len;
bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2];
if (trailing_pathseps) {
IObuff[dir_len - 2] = NUL;
@@ -2674,7 +2661,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
}
}
- rootname = get_file_in_dir(fname, IObuff);
+ char *rootname = get_file_in_dir(fname, IObuff);
if (rootname == NULL) {
some_error = true; // out of memory
goto nobackup;
@@ -2710,7 +2697,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
// delete an existing one, and try to use another name instead.
// Change one character, just before the extension.
//
- wp = backup + strlen(backup) - 1 - strlen(backup_ext);
+ char *wp = backup + strlen(backup) - 1 - strlen(backup_ext);
if (wp < backup) { // empty file name ???
wp = backup;
}
@@ -2781,10 +2768,6 @@ nobackup:
}
SET_ERRMSG(NULL);
} else {
- char *dirp;
- char *p;
- char *rootname;
-
// Make a backup by renaming the original file.
// If 'cpoptions' includes the "W" flag, we don't want to
@@ -2798,11 +2781,11 @@ nobackup:
// Form the backup file name - change path/fo.o.h to
// path/fo.o.h.bak Try all directories in 'backupdir', first one
// that works is used.
- dirp = p_bdir;
+ char *dirp = p_bdir;
while (*dirp) {
// Isolate one directory name and make the backup file name.
size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ",");
- p = IObuff + dir_len;
+ char *p = IObuff + dir_len;
bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2];
if (trailing_pathseps) {
IObuff[dir_len - 2] = NUL;
@@ -2826,7 +2809,7 @@ nobackup:
}
if (backup == NULL) {
- rootname = get_file_in_dir(fname, IObuff);
+ char *rootname = get_file_in_dir(fname, IObuff);
if (rootname == NULL) {
backup = NULL;
} else {
@@ -3690,9 +3673,7 @@ static bool msg_add_fileformat(int eol_type)
/// Append line and character count to IObuff.
void msg_add_lines(int insert_space, long lnum, off_T nchars)
{
- char *p;
-
- p = IObuff + strlen(IObuff);
+ char *p = IObuff + strlen(IObuff);
if (insert_space) {
*p++ = ' ';
@@ -3758,46 +3739,35 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F
/// @return FAIL for failure, OK otherwise.
static int buf_write_bytes(struct bw_info *ip)
{
- int wlen;
- char *buf = ip->bw_buf; // data to write
- int len = ip->bw_len; // length of data
+ char *buf = ip->bw_buf; // data to write
+ int len = ip->bw_len; // length of data
#ifdef HAS_BW_FLAGS
- int flags = ip->bw_flags; // extra flags
+ int flags = ip->bw_flags; // extra flags
#endif
// Skip conversion when writing the BOM.
if (!(flags & FIO_NOCONVERT)) {
- char *p;
- unsigned c;
- int n;
-
if (flags & FIO_UTF8) {
// Convert latin1 in the buffer to UTF-8 in the file.
- p = ip->bw_conv_buf; // translate to buffer
- for (wlen = 0; wlen < len; wlen++) {
+ char *p = ip->bw_conv_buf; // translate to buffer
+ for (int wlen = 0; wlen < len; wlen++) {
p += utf_char2bytes((uint8_t)buf[wlen], p);
}
buf = ip->bw_conv_buf;
len = (int)(p - ip->bw_conv_buf);
} else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) {
+ unsigned c;
+ int n = 0;
// Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
// Latin1 chars in the file.
- if (flags & FIO_LATIN1) {
- p = buf; // translate in-place (can only get shorter)
- } else {
- p = ip->bw_conv_buf; // translate to buffer
- }
- for (wlen = 0; wlen < len; wlen += n) {
+ // translate in-place (can only get shorter) or to buffer
+ char *p = flags & FIO_LATIN1 ? buf : ip->bw_conv_buf;
+ for (int wlen = 0; wlen < len; wlen += n) {
if (wlen == 0 && ip->bw_restlen != 0) {
- int l;
-
// Use remainder of previous call. Append the start of
// buf[] to get a full sequence. Might still be too
// short!
- l = CONV_RESTLEN - ip->bw_restlen;
- if (l > len) {
- l = len;
- }
+ int l = MIN(len, CONV_RESTLEN - ip->bw_restlen);
memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
n = utf_ptr2len_len((char *)ip->bw_rest, ip->bw_restlen + l);
if (n > ip->bw_restlen + len) {
@@ -3864,18 +3834,15 @@ static int buf_write_bytes(struct bw_info *ip)
if (ip->bw_iconv_fd != (iconv_t)-1) {
const char *from;
size_t fromlen;
- char *to;
size_t tolen;
// Convert with iconv().
if (ip->bw_restlen > 0) {
- char *fp;
-
// Need to concatenate the remainder of the previous call and
// the bytes of the current call. Use the end of the
// conversion buffer for this.
fromlen = (size_t)len + (size_t)ip->bw_restlen;
- fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
+ char *fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen);
memmove(fp + ip->bw_restlen, buf, (size_t)len);
from = fp;
@@ -3885,7 +3852,7 @@ static int buf_write_bytes(struct bw_info *ip)
fromlen = (size_t)len;
tolen = ip->bw_conv_buflen;
}
- to = ip->bw_conv_buf;
+ char *to = ip->bw_conv_buf;
if (ip->bw_first) {
size_t save_len = tolen;
@@ -3925,7 +3892,7 @@ static int buf_write_bytes(struct bw_info *ip)
// Only checking conversion, which is OK if we get here.
return OK;
}
- wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len);
+ int wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len);
return (wlen < len) ? FAIL : OK;
}
@@ -3940,7 +3907,6 @@ static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL
{
char_u *p = (char_u *)(*pp);
bool error = false;
- int cc;
if (flags & FIO_UCS4) {
if (flags & FIO_ENDIAN_L) {
@@ -3963,7 +3929,7 @@ static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL
if (c >= 0x100000) {
error = true;
}
- cc = (int)(((c >> 10) & 0x3ff) + 0xd800);
+ int cc = (int)(((c >> 10) & 0x3ff) + 0xd800);
if (flags & FIO_ENDIAN_L) {
*p++ = (uint8_t)cc;
*p++ = (uint8_t)(cc >> 8);
@@ -4006,7 +3972,6 @@ static bool need_conversion(const char *fenc)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int same_encoding;
- int enc_flags;
int fenc_flags;
if (*fenc == NUL || strcmp(p_enc, fenc) == 0) {
@@ -4015,7 +3980,7 @@ static bool need_conversion(const char *fenc)
} else {
// Ignore difference between "ansi" and "latin1", "ucs-4" and
// "ucs-4be", etc.
- enc_flags = get_fio_flags(p_enc);
+ int enc_flags = get_fio_flags(p_enc);
fenc_flags = get_fio_flags(fenc);
same_encoding = (enc_flags != 0 && fenc_flags == enc_flags);
}
@@ -4036,12 +4001,10 @@ static bool need_conversion(const char *fenc)
/// @param name string to check for encoding
static int get_fio_flags(const char *name)
{
- int prop;
-
if (*name == NUL) {
name = p_enc;
}
- prop = enc_canon_props(name);
+ int prop = enc_canon_props(name);
if (prop & ENC_UNICODE) {
if (prop & ENC_2BYTE) {
if (prop & ENC_ENDIAN_L) {
@@ -4121,10 +4084,7 @@ static char *check_for_bom(const char *p_in, long size, int *lenp, int flags)
/// @return the length of the BOM (zero when no BOM).
static int make_bom(char_u *buf, char *name)
{
- int flags;
- char *p;
-
- flags = get_fio_flags(name);
+ int flags = get_fio_flags(name);
// Can't put a BOM in a non-Unicode file.
if (flags == FIO_LATIN1 || flags == 0) {
@@ -4137,7 +4097,7 @@ static int make_bom(char_u *buf, char *name)
buf[2] = 0xbf;
return 3;
}
- p = (char *)buf;
+ char *p = (char *)buf;
(void)ucs2bytes(0xfeff, &p, flags);
return (int)((char_u *)p - buf);
}
@@ -4153,8 +4113,6 @@ static int make_bom(char_u *buf, char *name)
/// name.
void shorten_buf_fname(buf_T *buf, char *dirname, int force)
{
- char *p;
-
if (buf->b_fname != NULL
&& !bt_nofilename(buf)
&& !path_with_url(buf->b_fname)
@@ -4164,7 +4122,7 @@ void shorten_buf_fname(buf_T *buf, char *dirname, int force)
if (buf->b_sfname != buf->b_ffname) {
XFREE_CLEAR(buf->b_sfname);
}
- p = path_shorten_fname(buf->b_ffname, dirname);
+ char *p = path_shorten_fname(buf->b_ffname, dirname);
if (p != NULL) {
buf->b_sfname = xstrdup(p);
buf->b_fname = buf->b_sfname;
@@ -4461,10 +4419,7 @@ int vim_rename(const char *from, const char *to)
{
int fd_in;
int fd_out;
- int n;
char *errmsg = NULL;
- char *buffer;
- long perm;
#ifdef HAVE_ACL
vim_acl_T acl; // ACL from original file
#endif
@@ -4506,7 +4461,7 @@ int vim_rename(const char *from, const char *to)
return -1;
}
STRCPY(tempname, from);
- for (n = 123; n < 99999; n++) {
+ for (int n = 123; n < 99999; n++) {
char *tail = path_tail(tempname);
snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - tempname - 1)), "%d", n);
@@ -4540,7 +4495,7 @@ int vim_rename(const char *from, const char *to)
}
// Rename() failed, try copying the file.
- perm = os_getperm(from);
+ long perm = os_getperm(from);
#ifdef HAVE_ACL
// For systems that support ACL: get the ACL from the original file.
acl = os_get_acl(from);
@@ -4566,7 +4521,7 @@ int vim_rename(const char *from, const char *to)
// Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim
// is `preserve_exit()`ing.
- buffer = try_malloc(BUFSIZE);
+ char *buffer = try_malloc(BUFSIZE);
if (buffer == NULL) {
close(fd_out);
close(fd_in);
@@ -4576,6 +4531,7 @@ int vim_rename(const char *from, const char *to)
return -1;
}
+ int n;
while ((n = (int)read_eintr(fd_in, buffer, BUFSIZE)) > 0) {
if (write_eintr(fd_out, buffer, (size_t)n) != n) {
errmsg = _("E208: Error writing to \"%s\"");
@@ -4619,8 +4575,6 @@ static int already_warned = false;
/// @return true if some message was written (screen should be redrawn and cursor positioned).
int check_timestamps(int focus)
{
- int didit = 0;
-
// Don't check timestamps while system() or another low-level function may
// cause us to lose and gain focus.
if (no_check_timestamps > 0) {
@@ -4635,6 +4589,8 @@ int check_timestamps(int focus)
return false;
}
+ int didit = 0;
+
if (!stuff_empty() || global_busy || !typebuf_typed()
|| autocmd_busy || curbuf->b_ro_locked > 0
|| allbuf_lock > 0) {
@@ -4678,13 +4634,11 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
{
buf_T *tbuf = curbuf;
int retval = OK;
- linenr_T lnum;
- char *p;
// Copy the lines in "frombuf" to "tobuf".
curbuf = tobuf;
- for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) {
- p = xstrdup(ml_get_buf(frombuf, lnum, false));
+ for (linenr_T lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) {
+ char *p = xstrdup(ml_get_buf(frombuf, lnum, false));
if (ml_append(lnum - 1, p, 0, false) == FAIL) {
xfree(p);
retval = FAIL;
@@ -4696,7 +4650,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
// Delete all the lines in "frombuf".
if (retval != FAIL) {
curbuf = frombuf;
- for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) {
+ for (linenr_T lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) {
if (ml_delete(lnum, false) == FAIL) {
// Oops! We could try putting back the saved lines, but that
// might fail again...
@@ -4720,7 +4674,6 @@ int buf_check_timestamp(buf_T *buf)
FUNC_ATTR_NONNULL_ALL
{
int retval = 0;
- char *path;
char *mesg = NULL;
char *mesg2 = "";
bool helpmesg = false;
@@ -4735,8 +4688,6 @@ int buf_check_timestamp(buf_T *buf)
uint64_t orig_size = buf->b_orig_size;
int orig_mode = buf->b_orig_mode;
static bool busy = false;
- char *s;
- char *reason;
bufref_T bufref;
set_bufref(&bufref, buf);
@@ -4784,6 +4735,7 @@ int buf_check_timestamp(buf_T *buf)
// was set, the global option value otherwise.
reload = RELOAD_NORMAL;
} else {
+ char *reason;
if (!file_info_ok) {
reason = "deleted";
} else if (bufIsChanged(buf)) {
@@ -4810,7 +4762,7 @@ int buf_check_timestamp(buf_T *buf)
if (!bufref_valid(&bufref)) {
emsg(_("E246: FileChangedShell autocommand deleted buffer"));
}
- s = get_vim_var_str(VV_FCS_CHOICE);
+ char *s = get_vim_var_str(VV_FCS_CHOICE);
if (strcmp(s, "reload") == 0 && *reason != 'd') {
reload = RELOAD_NORMAL;
} else if (strcmp(s, "edit") == 0) {
@@ -4863,7 +4815,7 @@ int buf_check_timestamp(buf_T *buf)
}
if (mesg != NULL) {
- path = home_replace_save(buf, buf->b_fname);
+ char *path = home_replace_save(buf, buf->b_fname);
if (!helpmesg) {
mesg2 = "";
}
@@ -4946,8 +4898,6 @@ int buf_check_timestamp(buf_T *buf)
void buf_reload(buf_T *buf, int orig_mode, bool reload_options)
{
exarg_T ea;
- pos_T old_cursor;
- linenr_T old_topline;
int old_ro = buf->b_p_ro;
buf_T *savebuf;
bufref_T bufref;
@@ -4967,8 +4917,8 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options)
prep_exarg(&ea, buf);
}
- old_cursor = curwin->w_cursor;
- old_topline = curwin->w_topline;
+ pos_T old_cursor = curwin->w_cursor;
+ linenr_T old_topline = curwin->w_topline;
if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) {
// Save all the text, so that the reload can be undone.
@@ -5454,24 +5404,19 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname,
bool match_file_list(char *list, char *sfname, char *ffname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3)
{
- char buf[100];
- char *tail;
- char *regpat;
- char allow_dirs;
- bool match;
- char *p;
-
- tail = path_tail(sfname);
+ char *tail = path_tail(sfname);
// try all patterns in 'wildignore'
- p = list;
+ char *p = list;
while (*p) {
+ char buf[100];
copy_option_part(&p, buf, ARRAY_SIZE(buf), ",");
- regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false);
+ char allow_dirs;
+ char *regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false);
if (regpat == NULL) {
break;
}
- match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs);
+ bool match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs);
xfree(regpat);
if (match) {
return true;
@@ -5494,15 +5439,10 @@ bool match_file_list(char *list, char *sfname, char *ffname)
char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs, int no_bslash)
FUNC_ATTR_NONNULL_ARG(1)
{
- const char *endp;
- char *reg_pat;
- const char *p;
- int nested = 0;
- bool add_dollar = true;
-
if (allow_dirs != NULL) {
*allow_dirs = false;
}
+
if (pat_end == NULL) {
pat_end = pat + strlen(pat);
}
@@ -5513,7 +5453,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs
size_t size = 2; // '^' at start, '$' at end.
- for (p = pat; p < pat_end; p++) {
+ for (const char *p = pat; p < pat_end; p++) {
switch (*p) {
case '*':
case '.':
@@ -5534,7 +5474,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs
break;
}
}
- reg_pat = xmalloc(size + 1);
+ char *reg_pat = xmalloc(size + 1);
size_t i = 0;
@@ -5545,14 +5485,16 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs
} else {
reg_pat[i++] = '^';
}
- endp = pat_end - 1;
+ const char *endp = pat_end - 1;
+ bool add_dollar = true;
if (endp >= pat && *endp == '*') {
while (endp - pat > 0 && *endp == '*') {
endp--;
}
add_dollar = false;
}
- for (p = pat; *p && nested >= 0 && p <= endp; p++) {
+ int nested = 0;
+ for (const char *p = pat; *p && nested >= 0 && p <= endp; p++) {
switch (*p) {
case '*':
reg_pat[i++] = '.';
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 9c5364e1b1..8ed9381bca 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -252,7 +252,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle
} else {
len = (size_t)slen;
}
- buffblock_T *p = xmalloc(sizeof(buffblock_T) + len);
+ buffblock_T *p = xmalloc(offsetof(buffblock_T, b_str) + len + 1);
buf->bh_space = len - (size_t)slen;
xstrlcpy(p->b_str, s, (size_t)slen + 1);
@@ -2526,10 +2526,12 @@ static int vgetorpeek(bool advance)
// move cursor left, if possible
if (curwin->w_cursor.col != 0) {
if (curwin->w_wcol > 0) {
- if (did_ai) {
- // We are expecting to truncate the trailing
- // white-space, so find the last non-white
- // character -- webb
+ // After auto-indenting and no text is following,
+ // we are expecting to truncate the trailing
+ // white-space, so find the last non-white
+ // character -- webb
+ if (did_ai
+ && *skipwhite(get_cursor_line_ptr() + curwin->w_cursor.col) == NUL) {
curwin->w_wcol = 0;
ptr = (char_u *)get_cursor_line_ptr();
chartabsize_T cts;
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 9dab91cc2b..c20eac3c28 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -842,14 +842,14 @@ void hlattrs2dict(Dictionary *dict, HlAttrs ae, bool use_rgb)
PUT_C(hl, "underline", BOOLEAN_OBJ(true));
break;
- case HL_UNDERDOUBLE:
- PUT_C(hl, "underdouble", BOOLEAN_OBJ(true));
- break;
-
case HL_UNDERCURL:
PUT_C(hl, "undercurl", BOOLEAN_OBJ(true));
break;
+ case HL_UNDERDOUBLE:
+ PUT_C(hl, "underdouble", BOOLEAN_OBJ(true));
+ break;
+
case HL_UNDERDOTTED:
PUT_C(hl, "underdotted", BOOLEAN_OBJ(true));
break;
@@ -930,8 +930,8 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(dict, mask, bold, , HL_BOLD);
CHECK_FLAG(dict, mask, italic, , HL_ITALIC);
CHECK_FLAG(dict, mask, underline, , HL_UNDERLINE);
- CHECK_FLAG(dict, mask, underdouble, , HL_UNDERDOUBLE);
CHECK_FLAG(dict, mask, undercurl, , HL_UNDERCURL);
+ CHECK_FLAG(dict, mask, underdouble, , HL_UNDERDOUBLE);
CHECK_FLAG(dict, mask, underdotted, , HL_UNDERDOTTED);
CHECK_FLAG(dict, mask, underdashed, , HL_UNDERDASHED);
CHECK_FLAG(dict, mask, standout, , HL_STANDOUT);
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index a4dcf6eb60..95c81ac9db 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -18,8 +18,8 @@ typedef enum {
// The next three bits are all underline styles
HL_UNDERLINE_MASK = 0x38,
HL_UNDERLINE = 0x08,
- HL_UNDERDOUBLE = 0x10,
- HL_UNDERCURL = 0x18,
+ HL_UNDERCURL = 0x10,
+ HL_UNDERDOUBLE = 0x18,
HL_UNDERDOTTED = 0x20,
HL_UNDERDASHED = 0x28,
// 0x30 and 0x38 spare for underline styles
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 5b1ea9967d..3d91335f55 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -1553,12 +1553,17 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg
} else { // type == LIST_ATTR
buf[0] = NUL;
for (int i = 0; hl_attr_table[i] != 0; i++) {
- if (iarg & hl_attr_table[i]) {
+ if (((hl_attr_table[i] & HL_UNDERLINE_MASK)
+ && ((iarg & HL_UNDERLINE_MASK) == hl_attr_table[i]))
+ || (!(hl_attr_table[i] & HL_UNDERLINE_MASK)
+ && (iarg & hl_attr_table[i]))) {
if (buf[0] != NUL) {
xstrlcat(buf, ",", 100);
}
xstrlcat(buf, hl_name_table[i], 100);
- iarg &= ~hl_attr_table[i]; // don't want "inverse"
+ if (!(hl_attr_table[i] & HL_UNDERLINE_MASK)) {
+ iarg &= ~hl_attr_table[i]; // don't want "inverse"
+ }
}
}
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 5ffd90fddd..1415ceeaed 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -64,6 +64,7 @@
#include "nvim/window.h"
static int in_fast_callback = 0;
+static bool in_script = false;
// Initialized in nlua_init().
static lua_State *global_lstate = NULL;
@@ -133,8 +134,13 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
str = lua_tolstring(lstate, -1, &len);
}
- msg_ext_set_kind("lua_error");
- semsg_multiline(msg, (int)len, str);
+ if (in_script) {
+ os_errmsg(str);
+ os_errmsg("\n");
+ } else {
+ msg_ext_set_kind("lua_error");
+ semsg_multiline(msg, (int)len, str);
+ }
lua_pop(lstate, 1);
}
@@ -534,7 +540,7 @@ int nlua_get_global_ref_count(void)
return nlua_global_refs->ref_count;
}
-static void nlua_common_vim_init(lua_State *lstate, bool is_thread)
+static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_standalone)
FUNC_ATTR_NONNULL_ARG(1)
{
nlua_ref_state_t *ref_state = nlua_new_ref_state(lstate, is_thread);
@@ -567,7 +573,9 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread)
lua_setfield(lstate, -2, "_empty_dict_mt");
// vim.loop
- if (is_thread) {
+ if (is_standalone) {
+ // do nothing, use libluv like in a standalone interpreter
+ } else if (is_thread) {
luv_set_callback(lstate, nlua_luv_thread_cb_cfpcall);
luv_set_thread(lstate, nlua_luv_thread_cfpcall);
luv_set_cthread(lstate, nlua_luv_thread_cfcpcall);
@@ -606,7 +614,7 @@ static int nlua_module_preloader(lua_State *lstate)
return 1;
}
-static bool nlua_init_packages(lua_State *lstate)
+static bool nlua_init_packages(lua_State *lstate, bool is_standalone)
FUNC_ATTR_NONNULL_ALL
{
// put builtin packages in preload
@@ -618,7 +626,7 @@ static bool nlua_init_packages(lua_State *lstate)
lua_pushcclosure(lstate, nlua_module_preloader, 1); // [package, preload, cclosure]
lua_setfield(lstate, -2, def.name); // [package, preload]
- if (nlua_disable_preload && strequal(def.name, "vim.inspect")) {
+ if ((nlua_disable_preload && !is_standalone) && strequal(def.name, "vim.inspect")) {
break;
}
}
@@ -769,7 +777,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, &nlua_ui_detach);
lua_setfield(lstate, -2, "ui_detach");
- nlua_common_vim_init(lstate, false);
+ nlua_common_vim_init(lstate, false, false);
// patch require() (only for --startuptime)
if (time_fd != NULL) {
@@ -788,7 +796,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setglobal(lstate, "vim");
- if (!nlua_init_packages(lstate)) {
+ if (!nlua_init_packages(lstate, false)) {
return false;
}
@@ -813,6 +821,9 @@ void nlua_init(char **argv, int argc, int lua_arg0)
luaL_openlibs(lstate);
if (!nlua_state_init(lstate)) {
os_errmsg(_("E970: Failed to initialize builtin lua modules\n"));
+#ifdef EXITFREE
+ nlua_common_free_all_mem(lstate);
+#endif
os_exit(1);
}
@@ -824,9 +835,28 @@ void nlua_init(char **argv, int argc, int lua_arg0)
static lua_State *nlua_thread_acquire_vm(void)
{
+ return nlua_init_state(true);
+}
+
+void nlua_run_script(char **argv, int argc, int lua_arg0)
+ FUNC_ATTR_NORETURN
+{
+ in_script = true;
+ global_lstate = nlua_init_state(false);
+ luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem);
+ nlua_init_argv(global_lstate, argv, argc, lua_arg0);
+ bool lua_ok = nlua_exec_file(argv[lua_arg0 - 1]);
+#ifdef EXITFREE
+ nlua_free_all_mem();
+#endif
+ exit(lua_ok ? 0 : 1);
+}
+
+lua_State *nlua_init_state(bool thread)
+{
// If it is called from the main thread, it will attempt to rebuild the cache.
const uv_thread_t self = uv_thread_self();
- if (uv_thread_equal(&main_thread, &self)) {
+ if (!in_script && uv_thread_equal(&main_thread, &self)) {
runtime_search_path_validate();
}
@@ -835,9 +865,11 @@ static lua_State *nlua_thread_acquire_vm(void)
// Add in the lua standard libraries
luaL_openlibs(lstate);
- // print
- lua_pushcfunction(lstate, &nlua_print);
- lua_setglobal(lstate, "print");
+ if (!in_script) {
+ // print
+ lua_pushcfunction(lstate, &nlua_print);
+ lua_setglobal(lstate, "print");
+ }
lua_pushinteger(lstate, 0);
lua_setfield(lstate, LUA_REGISTRYINDEX, "nlua.refcount");
@@ -845,18 +877,20 @@ static lua_State *nlua_thread_acquire_vm(void)
// vim
lua_newtable(lstate);
- nlua_common_vim_init(lstate, true);
+ nlua_common_vim_init(lstate, thread, in_script);
nlua_state_add_stdlib(lstate, true);
- lua_createtable(lstate, 0, 0);
- lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime);
- lua_setfield(lstate, -2, "nvim__get_runtime");
- lua_setfield(lstate, -2, "api");
+ if (!in_script) {
+ lua_createtable(lstate, 0, 0);
+ lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime);
+ lua_setfield(lstate, -2, "nvim__get_runtime");
+ lua_setfield(lstate, -2, "api");
+ }
lua_setglobal(lstate, "vim");
- nlua_init_packages(lstate);
+ nlua_init_packages(lstate, in_script);
lua_getglobal(lstate, "package");
lua_getfield(lstate, -1, "loaded");
diff --git a/src/nvim/main.c b/src/nvim/main.c
index bbe877356d..e26922bf8e 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -239,6 +239,14 @@ int main(int argc, char **argv)
argv0 = argv[0];
+ if (argc > 1 && STRICMP(argv[1], "-ll") == 0) {
+ if (argc == 2) {
+ print_mainerr(err_arg_missing, argv[1]);
+ exit(1);
+ }
+ nlua_run_script(argv, argc, 3);
+ }
+
char *fname = NULL; // file name from command line
mparm_T params; // various parameters passed between
// main() and other functions.
@@ -803,6 +811,11 @@ void preserve_exit(void)
really_exiting = true;
// Ignore SIGHUP while we are already exiting. #9274
signal_reject_deadly();
+
+ if (ui_client_channel_id) {
+ os_exit(1);
+ }
+
os_errmsg(IObuff);
os_errmsg("\n");
ui_flush();
@@ -2111,6 +2124,12 @@ static int execute_env(char *env)
static void mainerr(const char *errstr, const char *str)
FUNC_ATTR_NORETURN
{
+ print_mainerr(errstr, str);
+ os_exit(1);
+}
+
+static void print_mainerr(const char *errstr, const char *str)
+{
char *prgname = path_tail(argv0);
signal_stop(); // kill us with CTRL-C here, if you like
@@ -2126,8 +2145,6 @@ static void mainerr(const char *errstr, const char *str)
os_errmsg(_("\nMore info with \""));
os_errmsg(prgname);
os_errmsg(" -h\"\n");
-
- os_exit(1);
}
/// Prints version information for "nvim -v" or "nvim --version".
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index 2036ddd21d..77ba6e6fa4 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -1182,7 +1182,7 @@ static size_t check_node(MarkTree *b, mtnode_t *x, mtpos_t *last, bool *last_rig
assert(x->ptr[i] != x->ptr[j]);
}
}
- } else {
+ } else if (x->n > 0) {
*last = x->key[x->n - 1].pos;
}
return n_keys;
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 10a8195e7a..b3fc64a68c 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -149,7 +149,7 @@ struct data_block {
#define DB_INDEX_MASK (~DB_MARKED)
#define INDEX_SIZE (sizeof(unsigned)) // size of one db_index entry
-#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) // size of data block header
+#define HEADER_SIZE (offsetof(DATA_BL, db_index)) // size of data block header
enum {
B0_FNAME_SIZE_ORG = 900, // what it was in older versions
@@ -2720,7 +2720,8 @@ static bhdr_T *ml_new_ptr(memfile_T *mfp)
PTR_BL *pp = hp->bh_data;
pp->pb_id = PTR_ID;
pp->pb_count = 0;
- pp->pb_count_max = (uint16_t)((mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1);
+ pp->pb_count_max
+ = (uint16_t)((mfp->mf_page_size - offsetof(PTR_BL, pb_pointer)) / sizeof(PTR_EN));
return hp;
}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 7f29b19031..3b3dfcd5b6 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -2514,7 +2514,7 @@ static void store_sb_text(char **sb_str, char *s, int attr, int *sb_col, int fin
}
if (s > *sb_str) {
- mp = xmalloc((sizeof(msgchunk_T) + (size_t)(s - *sb_str)));
+ mp = xmalloc(offsetof(msgchunk_T, sb_text) + (size_t)(s - *sb_str) + 1);
mp->sb_eol = (char)finish;
mp->sb_msg_col = *sb_col;
mp->sb_attr = attr;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 58a18ca5a8..b88cfb8926 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -5072,9 +5072,13 @@ static void nv_visual(cmdarg_T *cap)
curwin->w_curswant = MAXCOL;
coladvance(MAXCOL);
} else if (VIsual_mode == Ctrl_V) {
+ // Update curswant on the original line, that is where "col" is valid.
+ linenr_T lnum = curwin->w_cursor.lnum;
+ curwin->w_cursor.lnum = VIsual.lnum;
update_curswant_force();
assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX);
curwin->w_curswant += resel_VIsual_vcol * (int)cap->count0 - 1;
+ curwin->w_cursor.lnum = lnum;
coladvance(curwin->w_curswant);
} else {
curwin->w_set_curswant = true;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 93449f2337..86e317b7f6 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -3203,6 +3203,56 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
recursive = false;
}
+/// Execute autocommands for TextPutPost.
+///
+/// @param oap Operator arguments.
+/// @param reg The yank register used.
+static void do_autocmd_textputpost(int regname, yankreg_T *reg)
+ FUNC_ATTR_NONNULL_ALL
+{
+ static bool recursive = false;
+ int len;
+
+ if (recursive || !has_event(EVENT_TEXTPUTPOST)) {
+ // No autocommand was defined, or we yanked from this autocommand.
+ return;
+ }
+
+ recursive = true;
+
+ save_v_event_T save_v_event;
+ // Set the v:event dictionary with information about the yank.
+ dict_T *dict = get_v_event(&save_v_event);
+
+ // The yanked text contents.
+ list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
+ for (size_t i = 0; i < reg->y_size; i++) {
+ tv_list_append_string(list, (const char *)reg->y_array[i], -1);
+ }
+ tv_list_set_lock(list, VAR_FIXED);
+ (void)tv_dict_add_list(dict, S_LEN("regcontents"), list);
+
+ // Register type.
+ char buf[NUMBUFLEN + 6];
+ format_reg_type(reg->y_type, reg->y_width, buf, ARRAY_SIZE(buf));
+ (void)tv_dict_add_str(dict, S_LEN("regtype"), buf);
+
+ // Name of requested register, or empty string for unnamed operation.
+ len = (*utf_char2len)(regname);
+ buf[len] = 0;
+ utf_char2bytes(regname, buf);
+ recursive = true;
+ (void)tv_dict_add_str(dict, S_LEN("regname"), buf);
+
+ tv_dict_set_keys_readonly(dict);
+ textlock++;
+ apply_autocmds(EVENT_TEXTPUTPOST, NULL, NULL, false, curbuf);
+ textlock--;
+ restore_v_event(dict, &save_v_event);
+
+ recursive = false;
+}
+
/// Put contents of register "regname" into the text.
/// Caller must check "regname" to be valid!
///
@@ -3990,6 +4040,8 @@ error:
curwin->w_set_curswant = true;
end:
+ do_autocmd_textputpost(regname, reg);
+
if (cmdmod.cmod_flags & CMOD_LOCKMARKS) {
curbuf->b_op_start = orig_start;
curbuf->b_op_end = orig_end;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index e63665f7c4..86840faa43 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -726,11 +726,173 @@ void ex_set(exarg_T *eap)
(void)do_set(eap->arg, flags);
}
+static void do_set_bool(int opt_idx, int opt_flags, int prefix, int nextchar, const char *varp,
+ char **errmsg)
+{
+ varnumber_T value;
+
+ // ":set opt!": invert
+ // ":set opt&": reset to default value
+ // ":set opt<": reset to global value
+ if (nextchar == '!') {
+ value = *(int *)(varp) ^ 1;
+ } else if (nextchar == '&') {
+ value = (int)(intptr_t)options[opt_idx].def_val;
+ } else if (nextchar == '<') {
+ // For 'autoread' -1 means to use global value.
+ if ((int *)varp == &curbuf->b_p_ar && opt_flags == OPT_LOCAL) {
+ value = -1;
+ } else {
+ value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+ }
+ } else {
+ if (prefix == 2) {
+ value = *(int *)varp ^ 1; // ":set invopt": invert
+ } else {
+ value = prefix; // ":set opt" or ":set noopt": set or reset
+ }
+ }
+
+ *errmsg = set_bool_option(opt_idx, (char_u *)varp, (int)value, opt_flags);
+}
+
+static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, const set_op_T op,
+ const char *varp, char *errbuf, size_t errbuflen, char **errmsg)
+{
+ varnumber_T value;
+ char *arg = *argp;
+
+ // Different ways to set a number option:
+ // & set to default value
+ // < set to global value
+ // <xx> accept special key codes for 'wildchar'
+ // c accept any non-digit for 'wildchar'
+ // [-]0-9 set number
+ // other error
+ arg++;
+ if (nextchar == '&') {
+ value = (long)(intptr_t)options[opt_idx].def_val;
+ } else if (nextchar == '<') {
+ // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
+ // use the global value.
+ if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) {
+ value = NO_LOCAL_UNDOLEVEL;
+ } else {
+ value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+ }
+ } else if (((long *)varp == &p_wc
+ || (long *)varp == &p_wcm)
+ && (*arg == '<'
+ || *arg == '^'
+ || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1]))
+ && !ascii_isdigit(*arg)))) {
+ value = string_to_key(arg);
+ if (value == 0 && (long *)varp != &p_wcm) {
+ *errmsg = e_invarg;
+ return;
+ }
+ } else if (*arg == '-' || ascii_isdigit(*arg)) {
+ int i;
+ // Allow negative, octal and hex numbers.
+ vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true);
+ if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) {
+ *errmsg = e_number_required_after_equal;
+ return;
+ }
+ } else {
+ *errmsg = e_number_required_after_equal;
+ return;
+ }
+
+ if (op == OP_ADDING) {
+ value = *(long *)varp + value;
+ }
+ if (op == OP_PREPENDING) {
+ value = *(long *)varp * value;
+ }
+ if (op == OP_REMOVING) {
+ value = *(long *)varp - value;
+ }
+ *errmsg = set_num_option(opt_idx, (char_u *)varp, (long)value,
+ errbuf, errbuflen, opt_flags);
+}
+
+// Handle some special cases with string option values
+static void munge_string_opt_val(char **varp, char **oldval, char **const origval,
+ char_u **const origval_l, char_u **const origval_g,
+ char **const argp, char *const whichwrap, size_t whichwraplen,
+ char **const save_argp)
+{
+ // Set 'keywordprg' to ":help" if an empty
+ // value was passed to :set by the user.
+ if (varp == &p_kp && (**argp == NUL || **argp == ' ')) {
+ *save_argp = *argp;
+ *argp = ":help";
+ } else if (varp == &p_bs && ascii_isdigit(**(char_u **)varp)) {
+ // Convert 'backspace' number to string, for
+ // adding, prepending and removing string.
+ const int i = getdigits_int(varp, true, 0);
+ switch (i) {
+ case 0:
+ *varp = empty_option;
+ break;
+ case 1:
+ *varp = xstrdup("indent,eol");
+ break;
+ case 2:
+ *varp = xstrdup("indent,eol,start");
+ break;
+ case 3:
+ *varp = xstrdup("indent,eol,nostop");
+ break;
+ }
+ xfree(*oldval);
+ if (*origval == *oldval) {
+ *origval = *varp;
+ }
+ if (*origval_l == (char_u *)(*oldval)) {
+ *origval_l = *(char_u **)varp;
+ }
+ if (*origval_g == (char_u *)(*oldval)) {
+ *origval_g = *(char_u **)varp;
+ }
+ *oldval = *varp;
+ } else if (varp == &p_ww && ascii_isdigit(**argp)) {
+ // Convert 'whichwrap' number to string, for backwards compatibility
+ // with Vim 3.0.
+ *whichwrap = NUL;
+ int i = getdigits_int(argp, true, 0);
+ if (i & 1) {
+ xstrlcat(whichwrap, "b,", whichwraplen);
+ }
+ if (i & 2) {
+ xstrlcat(whichwrap, "s,", whichwraplen);
+ }
+ if (i & 4) {
+ xstrlcat(whichwrap, "h,l,", whichwraplen);
+ }
+ if (i & 8) {
+ xstrlcat(whichwrap, "<,>,", whichwraplen);
+ }
+ if (i & 16) {
+ xstrlcat(whichwrap, "[,],", whichwraplen);
+ }
+ if (*whichwrap != NUL) { // remove trailing ,
+ whichwrap[strlen(whichwrap) - 1] = NUL;
+ }
+ *save_argp = *argp;
+ *argp = whichwrap;
+ } else if (**argp == '>' && (varp == &p_dir || varp == &p_bdir)) {
+ // Remove '>' before 'dir' and 'bdir', for backwards compatibility with
+ // version 3.0
+ (*argp)++;
+ }
+}
+
/// Part of do_set() for string options.
-/// @return FAIL on failure, do not process further options.
-static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, set_op_T op_arg,
- uint32_t flags, char *varp_arg, char *errbuf, size_t errbuflen,
- int *value_checked, char **errmsg)
+static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, set_op_T op_arg,
+ uint32_t flags, char *varp_arg, char *errbuf, size_t errbuflen,
+ int *value_checked, char **errmsg)
{
char *arg = *argp;
set_op_T op = op_arg;
@@ -794,70 +956,8 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar,
} else {
arg++; // jump to after the '=' or ':'
- // Set 'keywordprg' to ":help" if an empty
- // value was passed to :set by the user.
- if (varp == (char *)&p_kp && (*arg == NUL || *arg == ' ')) {
- save_arg = arg;
- arg = ":help";
- } else if (varp == (char *)&p_bs && ascii_isdigit(**(char_u **)varp)) {
- // Convert 'backspace' number to string, for
- // adding, prepending and removing string.
- int i = getdigits_int((char **)varp, true, 0);
- switch (i) {
- case 0:
- *(char **)varp = empty_option;
- break;
- case 1:
- *(char_u **)varp = (char_u *)xstrdup("indent,eol");
- break;
- case 2:
- *(char_u **)varp = (char_u *)xstrdup("indent,eol,start");
- break;
- case 3:
- *(char_u **)varp = (char_u *)xstrdup("indent,eol,nostop");
- break;
- }
- xfree(oldval);
- if (origval == oldval) {
- origval = *(char **)varp;
- }
- if (origval_l == (char_u *)oldval) {
- origval_l = *(char_u **)varp;
- }
- if (origval_g == (char_u *)oldval) {
- origval_g = *(char_u **)varp;
- }
- oldval = *(char **)varp;
- } else if (varp == (char *)&p_ww && ascii_isdigit(*arg)) {
- // Convert 'whichwrap' number to string, for backwards compatibility
- // with Vim 3.0.
- *whichwrap = NUL;
- int i = getdigits_int(&arg, true, 0);
- if (i & 1) {
- xstrlcat(whichwrap, "b,", sizeof(whichwrap));
- }
- if (i & 2) {
- xstrlcat(whichwrap, "s,", sizeof(whichwrap));
- }
- if (i & 4) {
- xstrlcat(whichwrap, "h,l,", sizeof(whichwrap));
- }
- if (i & 8) {
- xstrlcat(whichwrap, "<,>,", sizeof(whichwrap));
- }
- if (i & 16) {
- xstrlcat(whichwrap, "[,],", sizeof(whichwrap));
- }
- if (*whichwrap != NUL) { // remove trailing ,
- whichwrap[strlen(whichwrap) - 1] = NUL;
- }
- save_arg = arg;
- arg = whichwrap;
- } else if (*arg == '>' && (varp == (char *)&p_dir || varp == (char *)&p_bdir)) {
- // Remove '>' before 'dir' and 'bdir', for backwards compatibility with
- // version 3.0
- arg++;
- }
+ munge_string_opt_val((char **)varp, &oldval, &origval, &origval_l, &origval_g, &arg,
+ whichwrap, sizeof(whichwrap), &save_arg);
// Copy the new string into allocated memory.
// Can't use set_string_option_direct(), because we need to remove the
@@ -1059,416 +1159,391 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar,
xfree(saved_newval);
*argp = arg;
- return *errmsg == NULL ? OK : FAIL;
}
-/// Parse 'arg' for option settings.
-///
-/// 'arg' may be IObuff, but only when no errors can be present and option
-/// does not need to be expanded with option_expand().
-/// "opt_flags":
-/// 0 for ":set"
-/// OPT_GLOBAL for ":setglobal"
-/// OPT_LOCAL for ":setlocal" and a modeline
-/// OPT_MODELINE for a modeline
-/// OPT_WINONLY to only set window-local options
-/// OPT_NOWIN to skip setting window-local options
-///
-/// @param arg option string (may be written to!)
-///
+static set_op_T get_op(const char *arg)
+{
+ set_op_T op = OP_NONE;
+ if (*arg != NUL && *(arg + 1) == '=') {
+ if (*arg == '+') {
+ op = OP_ADDING; // "+="
+ } else if (*arg == '^') {
+ op = OP_PREPENDING; // "^="
+ } else if (*arg == '-') {
+ op = OP_REMOVING; // "-="
+ }
+ }
+ return op;
+}
+
+static int get_option_prefix(char **argp)
+{
+ if (strncmp(*argp, "no", 2) == 0) {
+ *argp += 2;
+ return 0;
+ } else if (strncmp(*argp, "inv", 3) == 0) {
+ *argp += 3;
+ return 2;
+ }
+
+ return 1;
+}
+
+/// @param[in] arg Pointer to start option name
+/// @param[out] opt_idxp Option index in options[] table.
+/// @param[out] keyp
+/// @param[out] len Length of option name
/// @return FAIL if an error is detected, OK otherwise
-int do_set(char *arg, int opt_flags)
+static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp)
{
- int did_show = false; // already showed one value
+ // find end of name
+ int key = 0;
+ int len;
+ int opt_idx;
- if (*arg == NUL) {
- showoptions(0, opt_flags);
- did_show = true;
- goto theend;
- }
-
- char errbuf[80];
-
- while (*arg != NUL) { // loop to process all options
- char *errmsg = NULL;
- char *startarg = arg; // remember for error message
-
- if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3])
- && !(opt_flags & OPT_MODELINE)) {
- // ":set all" show all options.
- // ":set all&" set all options to their default value.
- arg += 3;
- if (*arg == '&') {
- arg++;
- // Only for :set command set global value of local options.
- set_options_default(OPT_FREE | opt_flags);
- didset_options();
- didset_options2();
- ui_refresh_options();
- redraw_all_later(UPD_CLEAR);
- } else {
- showoptions(1, opt_flags);
- did_show = true;
- }
+ if (*arg == '<') {
+ opt_idx = -1;
+ // look out for <t_>;>
+ if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) {
+ len = 5;
} else {
- int prefix = 1; // 1: nothing, 0: "no", 2: "inv" in front of name
- if (strncmp(arg, "no", 2) == 0) {
- prefix = 0;
- arg += 2;
- } else if (strncmp(arg, "inv", 3) == 0) {
- prefix = 2;
- arg += 3;
+ len = 1;
+ while (arg[len] != NUL && arg[len] != '>') {
+ len++;
}
-
- // find end of name
- int key = 0;
- int len;
- int opt_idx;
- if (*arg == '<') {
- opt_idx = -1;
- // look out for <t_>;>
- if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) {
- len = 5;
- } else {
- len = 1;
- while (arg[len] != NUL && arg[len] != '>') {
- len++;
- }
- }
- if (arg[len] != '>') {
- errmsg = e_invarg;
- goto skip;
- }
- if (arg[1] == 't' && arg[2] == '_') { // could be term code
- opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1));
- }
+ }
+ if (arg[len] != '>') {
+ return FAIL;
+ }
+ if (arg[1] == 't' && arg[2] == '_') { // could be term code
+ opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1));
+ }
+ len++;
+ if (opt_idx == -1) {
+ key = find_key_option(arg + 1, true);
+ }
+ } else {
+ // The two characters after "t_" may not be alphanumeric.
+ if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) {
+ len = 4;
+ } else {
+ len = 0;
+ while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') {
len++;
- if (opt_idx == -1) {
- key = find_key_option(arg + 1, true);
- }
- } else {
- len = 0;
- // The two characters after "t_" may not be alphanumeric.
- if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) {
- len = 4;
- } else {
- while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') {
- len++;
- }
- }
- opt_idx = findoption_len((const char *)arg, (size_t)len);
- if (opt_idx == -1) {
- key = find_key_option(arg, false);
- }
}
+ }
+ opt_idx = findoption_len((const char *)arg, (size_t)len);
+ if (opt_idx == -1) {
+ key = find_key_option(arg, false);
+ }
+ }
- // remember character after option name
- int afterchar = (uint8_t)arg[len];
+ *keyp = key;
+ *lenp = len;
+ *opt_idxp = opt_idx;
- // skip white space, allow ":set ai ?"
- while (ascii_iswhite(arg[len])) {
- len++;
- }
+ return OK;
+}
- set_op_T op = OP_NONE;
- if (arg[len] != NUL && arg[len + 1] == '=') {
- if (arg[len] == '+') {
- op = OP_ADDING; // "+="
- len++;
- } else if (arg[len] == '^') {
- op = OP_PREPENDING; // "^="
- len++;
- } else if (arg[len] == '-') {
- op = OP_REMOVING; // "-="
- len++;
- }
- }
- char_u nextchar = (uint8_t)arg[len]; // next non-white char after option name
+static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t flags, int prefix,
+ char **errmsg)
+{
+ // Only bools can have a prefix of 'inv' or 'no'
+ if (!(flags & P_BOOL) && prefix != 1) {
+ *errmsg = e_invarg;
+ return FAIL;
+ }
- if (opt_idx == -1 && key == 0) { // found a mismatch: skip
- errmsg = e_unknown_option;
- goto skip;
- }
+ // 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)) {
+ return FAIL;
+ }
- uint32_t flags; // flags for current option
- char *varp = NULL; // pointer to variable for current option
-
- if (opt_idx >= 0) {
- 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.
- if (vim_strchr("=:!&<", (uint8_t)nextchar) == NULL
- && (!(options[opt_idx].flags & P_BOOL)
- || nextchar == '?')) {
- errmsg = e_unsupportedoption;
- }
- goto skip;
- }
+ // Skip all options that are window-local (used for :vimgrep).
+ if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
+ && options[opt_idx].var == VAR_WIN) {
+ return FAIL;
+ }
- flags = options[opt_idx].flags;
- varp = get_varp_scope(&(options[opt_idx]), opt_flags);
- } else {
- flags = P_STRING;
- }
+ // Disallow changing some options from modelines.
+ if (opt_flags & OPT_MODELINE) {
+ if (flags & (P_SECURE | P_NO_ML)) {
+ *errmsg = e_not_allowed_in_modeline;
+ return FAIL;
+ }
+ if ((flags & P_MLE) && !p_mle) {
+ *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
+ return FAIL;
+ }
+ // In diff mode some options are overruled. This avoids that
+ // 'foldmethod' becomes "marker" instead of "diff" and that
+ // "wrap" gets set.
+ if (win->w_p_diff
+ && opt_idx >= 0 // shut up coverity warning
+ && (options[opt_idx].indir == PV_FDM
+ || options[opt_idx].indir == PV_WRAP)) {
+ return FAIL;
+ }
+ }
- // 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)) {
- goto skip;
- }
+ // Disallow changing some options in the sandbox
+ if (sandbox != 0 && (flags & P_SECURE)) {
+ *errmsg = e_sandbox;
+ return FAIL;
+ }
- // Skip all options that are window-local (used for :vimgrep).
- if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
- && options[opt_idx].var == VAR_WIN) {
- goto skip;
- }
+ return OK;
+}
- // Disallow changing some options from modelines.
- if (opt_flags & OPT_MODELINE) {
- if (flags & (P_SECURE | P_NO_ML)) {
- errmsg = e_not_allowed_in_modeline;
- goto skip;
- }
- if ((flags & P_MLE) && !p_mle) {
- errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
- goto skip;
- }
- // In diff mode some options are overruled. This avoids that
- // 'foldmethod' becomes "marker" instead of "diff" and that
- // "wrap" gets set.
- if (curwin->w_p_diff
- && opt_idx >= 0 // shut up coverity warning
- && (options[opt_idx].indir == PV_FDM
- || options[opt_idx].indir == PV_WRAP)) {
- goto skip;
- }
- }
+static void do_set_option_value(int opt_idx, int opt_flags, char **argp, int prefix, int nextchar,
+ set_op_T op, uint32_t flags, char *varp, char *errbuf,
+ size_t errbuflen, char **errmsg)
+{
+ int value_checked = false;
+ if (flags & P_BOOL) { // boolean
+ do_set_bool(opt_idx, opt_flags, prefix, nextchar, varp, errmsg);
+ } else if (flags & P_NUM) { // numeric
+ do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg);
+ } else if (opt_idx >= 0) { // string.
+ do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf,
+ errbuflen, &value_checked, errmsg);
+ } else {
+ // key code option(FIXME(tarruda): Show a warning or something
+ // similar)
+ }
- // Disallow changing some options in the sandbox
- if (sandbox != 0 && (flags & P_SECURE)) {
- errmsg = e_sandbox;
- goto skip;
- }
+ if (*errmsg != NULL) {
+ return;
+ }
- if (vim_strchr("?=:!&<", (uint8_t)nextchar) != NULL) {
- arg += len;
- if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') {
- if (arg[3] == 'm') { // "opt&vim": set to Vim default
- arg += 3;
- } else { // "opt&vi": set to Vi default
- arg += 2;
- }
- }
- if (vim_strchr("?!&<", (uint8_t)nextchar) != NULL
- && arg[1] != NUL && !ascii_iswhite(arg[1])) {
- errmsg = e_trailing;
- goto skip;
- }
- }
+ if (opt_idx >= 0) {
+ did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked);
+ }
+}
- //
- // allow '=' and ':' as MS-DOS command.com allows only one
- // '=' character per "set" command line. grrr. (jw)
- //
- if (nextchar == '?'
- || (prefix == 1
- && vim_strchr("=:&<", (uint8_t)nextchar) == NULL
- && !(flags & P_BOOL))) {
- // print value
- if (did_show) {
- msg_putchar('\n'); // cursor below last one
- } else {
- gotocmdline(true); // cursor at status line
- did_show = true; // remember that we did a line
- }
- if (opt_idx >= 0) {
- showoneopt(&options[opt_idx], opt_flags);
- if (p_verbose > 0) {
- // Mention where the option was last set.
- if (varp == (char *)options[opt_idx].var) {
- option_last_set_msg(options[opt_idx].last_set);
- } else if ((int)options[opt_idx].indir & PV_WIN) {
- option_last_set_msg(curwin->w_p_script_ctx[
- (int)options[opt_idx].indir & PV_MASK]);
- } else if ((int)options[opt_idx].indir & PV_BUF) {
- option_last_set_msg(curbuf->b_p_script_ctx[
- (int)options[opt_idx].indir & PV_MASK]);
- }
- }
- } else {
- errmsg = e_key_code_not_set;
- goto skip;
- }
- if (nextchar != '?'
- && nextchar != NUL && !ascii_iswhite(afterchar)) {
- errmsg = e_trailing;
- }
- } else {
- int value_checked = false;
- varnumber_T value;
+static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf,
+ size_t errbuflen, char **errmsg)
+{
+ // 1: nothing, 0: "no", 2: "inv" in front of name
+ int prefix = get_option_prefix(argp);
- if (flags & P_BOOL) { // boolean
- if (nextchar == '=' || nextchar == ':') {
- errmsg = e_invarg;
- goto skip;
- }
+ char *arg = *argp;
- // ":set opt!": invert
- // ":set opt&": reset to default value
- // ":set opt<": reset to global value
- if (nextchar == '!') {
- value = *(int *)(varp) ^ 1;
- } else if (nextchar == '&') {
- value = (int)(intptr_t)options[opt_idx].def_val;
- } else if (nextchar == '<') {
- // For 'autoread' -1 means to use global value.
- if ((int *)varp == &curbuf->b_p_ar
- && opt_flags == OPT_LOCAL) {
- value = -1;
- } else {
- value = *(int *)get_varp_scope(&(options[opt_idx]),
- OPT_GLOBAL);
- }
- } else {
- // ":set invopt": invert
- // ":set opt" or ":set noopt": set or reset
- if (nextchar != NUL && !ascii_iswhite(afterchar)) {
- errmsg = e_trailing;
- goto skip;
- }
- if (prefix == 2) { // inv
- value = *(int *)(varp) ^ 1;
- } else {
- value = prefix;
- }
- }
+ // find end of name
+ int key = 0;
+ int len;
+ int opt_idx;
+ if (parse_option_name(arg, &key, &len, &opt_idx) == FAIL) {
+ *errmsg = e_invarg;
+ return;
+ }
- errmsg = set_bool_option(opt_idx, (char_u *)varp, (int)value, opt_flags);
- } else { // Numeric or string.
- if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL
- || prefix != 1) {
- errmsg = e_invarg;
- goto skip;
- }
+ // remember character after option name
+ int afterchar = (uint8_t)arg[len];
- if (flags & P_NUM) { // numeric
- // Different ways to set a number option:
- // & set to default value
- // < set to global value
- // <xx> accept special key codes for 'wildchar'
- // c accept any non-digit for 'wildchar'
- // [-]0-9 set number
- // other error
- arg++;
- if (nextchar == '&') {
- value = (long)(intptr_t)options[opt_idx].def_val;
- } else if (nextchar == '<') {
- // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
- // use the global value.
- if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) {
- value = NO_LOCAL_UNDOLEVEL;
- } else {
- value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
- }
- } else if (((long *)varp == &p_wc
- || (long *)varp == &p_wcm)
- && (*arg == '<'
- || *arg == '^'
- || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1]))
- && !ascii_isdigit(*arg)))) {
- value = string_to_key(arg);
- if (value == 0 && (long *)varp != &p_wcm) {
- errmsg = e_invarg;
- goto skip;
- }
- } else if (*arg == '-' || ascii_isdigit(*arg)) {
- int i;
- // Allow negative, octal and hex numbers.
- vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true);
- if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) {
- errmsg = e_number_required_after_equal;
- goto skip;
- }
- } else {
- errmsg = e_number_required_after_equal;
- goto skip;
- }
+ // skip white space, allow ":set ai ?"
+ while (ascii_iswhite(arg[len])) {
+ len++;
+ }
- if (op == OP_ADDING) {
- value = *(long *)varp + value;
- }
- if (op == OP_PREPENDING) {
- value = *(long *)varp * value;
- }
- if (op == OP_REMOVING) {
- value = *(long *)varp - value;
- }
- errmsg = set_num_option(opt_idx, (char_u *)varp, (long)value,
- errbuf, sizeof(errbuf),
- opt_flags);
- } else if (opt_idx >= 0) { // String.
- if (do_set_string(opt_idx, opt_flags, &arg, nextchar,
- op, flags, varp, errbuf, sizeof(errbuf),
- &value_checked, &errmsg) == FAIL) {
- if (errmsg != NULL) {
- goto skip;
- }
- break;
- }
- } else {
- // key code option(FIXME(tarruda): Show a warning or something
- // similar)
- }
- }
+ set_op_T op = get_op(arg + len);
+ if (op != OP_NONE) {
+ len++;
+ }
- if (opt_idx >= 0) {
- did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked);
- }
+ uint8_t nextchar = (uint8_t)arg[len]; // next non-white char after option name
+
+ if (opt_idx == -1 && key == 0) { // found a mismatch: skip
+ *errmsg = e_unknown_option;
+ return;
+ }
+
+ uint32_t flags; // flags for current option
+ char *varp = NULL; // pointer to variable for current option
+
+ if (opt_idx >= 0) {
+ 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.
+ if (vim_strchr("=:!&<", nextchar) == NULL
+ && (!(options[opt_idx].flags & P_BOOL)
+ || nextchar == '?')) {
+ *errmsg = e_unsupportedoption;
}
+ return;
+ }
-skip:
- // Advance to next argument.
- // - skip until a blank found, taking care of backslashes
- // - skip blanks
- // - skip one "=val" argument (for hidden options ":set gfn =xx")
- for (int i = 0; i < 2; i++) {
- while (*arg != NUL && !ascii_iswhite(*arg)) {
- if (*arg++ == '\\' && *arg != NUL) {
- arg++;
- }
- }
- arg = skipwhite(arg);
- if (*arg != '=') {
- break;
- }
+ flags = options[opt_idx].flags;
+ varp = get_varp_scope(&(options[opt_idx]), opt_flags);
+ } else {
+ flags = P_STRING;
+ }
+
+ if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, prefix, errmsg) == FAIL) {
+ return;
+ }
+
+ if (vim_strchr("?=:!&<", nextchar) != NULL) {
+ *argp += len;
+ if (nextchar == '&' && (*argp)[1] == 'v' && (*argp)[2] == 'i') {
+ if ((*argp)[3] == 'm') { // "opt&vim": set to Vim default
+ *argp += 3;
+ } else { // "opt&vi": set to Vi default
+ *argp += 2;
}
}
+ if (vim_strchr("?!&<", nextchar) != NULL
+ && (*argp)[1] != NUL && !ascii_iswhite((*argp)[1])) {
+ *errmsg = e_trailing;
+ return;
+ }
+ }
- if (errmsg != NULL) {
- xstrlcpy(IObuff, _(errmsg), IOSIZE);
- int i = (int)strlen(IObuff) + 2;
- if (i + (arg - startarg) < IOSIZE) {
- // append the argument with the error
- STRCAT(IObuff, ": ");
- assert(arg >= startarg);
- memmove(IObuff + i, startarg, (size_t)(arg - startarg));
- IObuff[i + (arg - startarg)] = NUL;
+ //
+ // allow '=' and ':' as MS-DOS command.com allows only one
+ // '=' character per "set" command line. grrr. (jw)
+ //
+ if (nextchar == '?'
+ || (prefix == 1
+ && vim_strchr("=:&<", nextchar) == NULL
+ && !(flags & P_BOOL))) {
+ // print value
+ if (*did_show) {
+ msg_putchar('\n'); // cursor below last one
+ } else {
+ gotocmdline(true); // cursor at status line
+ *did_show = true; // remember that we did a line
+ }
+ if (opt_idx >= 0) {
+ showoneopt(&options[opt_idx], opt_flags);
+ if (p_verbose > 0) {
+ // Mention where the option was last set.
+ if (varp == (char *)options[opt_idx].var) {
+ option_last_set_msg(options[opt_idx].last_set);
+ } else if ((int)options[opt_idx].indir & PV_WIN) {
+ option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]);
+ } else if ((int)options[opt_idx].indir & PV_BUF) {
+ option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]);
+ }
}
- // make sure all characters are printable
- trans_characters(IObuff, IOSIZE);
+ } else {
+ *errmsg = e_key_code_not_set;
+ return;
+ }
+ if (nextchar != '?' && nextchar != NUL && !ascii_iswhite(afterchar)) {
+ *errmsg = e_trailing;
+ }
+ return;
+ }
- no_wait_return++; // wait_return() done later
- emsg(IObuff); // show error highlighted
- no_wait_return--;
+ if (flags & P_BOOL) {
+ if (vim_strchr("=:", nextchar) != NULL) {
+ *errmsg = e_invarg;
+ return;
+ }
- return FAIL;
+ if (vim_strchr("!&<", nextchar) == NULL && nextchar != NUL && !ascii_iswhite(afterchar)) {
+ *errmsg = e_trailing;
+ return;
}
+ } else {
+ if (vim_strchr("=:&<", nextchar) == NULL) {
+ *errmsg = e_invarg;
+ return;
+ }
+ }
- arg = skipwhite(arg);
+ do_set_option_value(opt_idx, opt_flags, argp, prefix, nextchar, op, flags, varp,
+ errbuf, errbuflen, errmsg);
+}
+
+/// Parse 'arg' for option settings.
+///
+/// 'arg' may be IObuff, but only when no errors can be present and option
+/// does not need to be expanded with option_expand().
+/// "opt_flags":
+/// 0 for ":set"
+/// OPT_GLOBAL for ":setglobal"
+/// OPT_LOCAL for ":setlocal" and a modeline
+/// OPT_MODELINE for a modeline
+/// OPT_WINONLY to only set window-local options
+/// OPT_NOWIN to skip setting window-local options
+///
+/// @param arg option string (may be written to!)
+///
+/// @return FAIL if an error is detected, OK otherwise
+int do_set(char *arg, int opt_flags)
+{
+ bool did_show = false; // already showed one value
+
+ if (*arg == NUL) {
+ showoptions(false, opt_flags);
+ did_show = true;
+ } else {
+ while (*arg != NUL) { // loop to process all options
+ if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3])
+ && !(opt_flags & OPT_MODELINE)) {
+ // ":set all" show all options.
+ // ":set all&" set all options to their default value.
+ arg += 3;
+ if (*arg == '&') {
+ arg++;
+ // Only for :set command set global value of local options.
+ set_options_default(OPT_FREE | opt_flags);
+ didset_options();
+ didset_options2();
+ ui_refresh_options();
+ redraw_all_later(UPD_CLEAR);
+ } else {
+ showoptions(true, opt_flags);
+ did_show = true;
+ }
+ } else {
+ char *startarg = arg; // remember for error message
+ char *errmsg = NULL;
+ char errbuf[80];
+
+ do_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg);
+
+ // Advance to next argument.
+ // - skip until a blank found, taking care of backslashes
+ // - skip blanks
+ // - skip one "=val" argument (for hidden options ":set gfn =xx")
+ for (int i = 0; i < 2; i++) {
+ arg = skiptowhite_esc(arg);
+ arg = skipwhite(arg);
+ if (*arg != '=') {
+ break;
+ }
+ }
+
+ if (errmsg != NULL) {
+ xstrlcpy(IObuff, _(errmsg), IOSIZE);
+ int i = (int)strlen(IObuff) + 2;
+ if (i + (arg - startarg) < IOSIZE) {
+ // append the argument with the error
+ STRCAT(IObuff, ": ");
+ assert(arg >= startarg);
+ memmove(IObuff + i, startarg, (size_t)(arg - startarg));
+ IObuff[i + (arg - startarg)] = NUL;
+ }
+ // make sure all characters are printable
+ trans_characters(IObuff, IOSIZE);
+
+ no_wait_return++; // wait_return() done later
+ emsg(IObuff); // show error highlighted
+ no_wait_return--;
+
+ return FAIL;
+ }
+ }
+
+ arg = skipwhite(arg);
+ }
}
-theend:
if (silent_mode && did_show) {
// After displaying option values in silent mode.
silent_mode = false;
@@ -2245,8 +2320,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
errmsg = e_positive;
}
} else if (pp == &p_ch) {
- int minval = 0;
- if (value < minval) {
+ if (value < 0) {
errmsg = e_positive;
} else {
p_ch_was_zero = value == 0;
@@ -3111,11 +3185,11 @@ static int find_key_option(const char *arg, bool has_lt)
return find_key_option_len(arg, strlen(arg), has_lt);
}
-/// if 'all' == 0: show changed options
-/// if 'all' == 1: show all normal options
+/// if 'all' == false: show changed options
+/// if 'all' == true: show all normal options
///
/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
-static void showoptions(int all, int opt_flags)
+static void showoptions(bool all, int opt_flags)
{
#define INC 20
#define GAP 3
@@ -4832,12 +4906,12 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM
return OK;
}
-void ExpandOldSetting(int *num_file, char ***file)
+void ExpandOldSetting(int *numMatches, char ***matches)
{
char *var = NULL;
- *num_file = 0;
- *file = xmalloc(sizeof(char_u *));
+ *numMatches = 0;
+ *matches = xmalloc(sizeof(char *));
// For a terminal key code expand_option_idx is < 0.
if (expand_option_idx < 0) {
@@ -4870,8 +4944,8 @@ void ExpandOldSetting(int *num_file, char ***file)
}
#endif
- *file[0] = buf;
- *num_file = 1;
+ *matches[0] = buf;
+ *numMatches = 1;
}
/// Get the value for the numeric or string option///opp in a nice format into
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index a5a708600f..ca50c3ab00 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -615,7 +615,7 @@ char *check_stl_option(char *s)
continue;
}
if (vim_strchr(STL_ALL, (uint8_t)(*s)) == NULL) {
- return illegal_char(errbuf, sizeof(errbuf), *s);
+ return illegal_char(errbuf, sizeof(errbuf), (uint8_t)(*s));
}
if (*s == '{') {
bool reevaluate = (*++s == '%');
@@ -638,13 +638,11 @@ char *check_stl_option(char *s)
return NULL;
}
-static int shada_idx = -1;
-
+/// Check for a "normal" directory or file name in some options. Disallow a
+/// path separator (slash and/or backslash), wildcards and characters that are
+/// often illegal in a file name. Be more permissive if "secure" is off.
static bool check_illegal_path_names(char *val, uint32_t flags)
{
- // Disallow a path separator (slash and/or backslash), wildcards and
- // characters that are often illegal in a file name. Be more permissive
- // if "secure" is off.
return (((flags & P_NFNAME)
&& strpbrk(val, (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL)
|| ((flags & P_NDNAME)
@@ -701,8 +699,8 @@ static void did_set_breakindentopt(win_T *win, char **errmsg)
static void did_set_isopt(buf_T *buf, bool *did_chartab, char **errmsg)
{
// 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
- // If the new option is invalid, use old value. 'lisp' option: refill
- // g_chartab[] for '-' char
+ // If the new option is invalid, use old value.
+ // 'lisp' option: refill g_chartab[] for '-' char
if (buf_init_chartab(buf, true) == FAIL) {
*did_chartab = true; // need to restore it below
*errmsg = e_invarg; // error in value
@@ -957,7 +955,7 @@ static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, char *
while (*s && *s != ':') {
if (vim_strchr(COM_ALL, (uint8_t)(*s)) == NULL
&& !ascii_isdigit(*s) && *s != '-') {
- *errmsg = illegal_char(errbuf, errbuflen, *s);
+ *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
break;
}
s++;
@@ -1013,6 +1011,8 @@ static void did_set_verbosefile(char **errmsg)
}
}
+static int shada_idx = -1;
+
static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf,
size_t errbuflen, char **errmsg)
{
@@ -1029,7 +1029,7 @@ static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, ch
for (char *s = p_shada; *s;) {
// Check it's a valid character
if (vim_strchr("!\"%'/:<@cfhnrs", (uint8_t)(*s)) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, *s);
+ *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
break;
}
if (*s == 'n') { // name is always last one
@@ -1236,7 +1236,7 @@ static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, char *
break;
}
if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, *s);
+ *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
break;
}
if (*++s != NUL && *s != ',' && *s != ' ') {
@@ -1272,6 +1272,16 @@ static void did_set_completeopt(char **errmsg)
}
}
+#ifdef BACKSLASH_IN_FILENAME
+static void did_set_completeslash(buf_T *buf, char **errmsg)
+{
+ if (check_opt_strings(p_csl, p_csl_values, false) != OK
+ || check_opt_strings(buf->b_p_csl, p_csl_values, false) != OK) {
+ *errmsg = e_invarg;
+ }
+}
+#endif
+
static void did_set_signcolumn(win_T *win, char **varp, const char *oldval, char **errmsg)
{
if (check_signcolumn(*varp) != OK) {
@@ -1404,10 +1414,11 @@ static void did_set_virtualedit(win_T *win, int opt_flags, char *oldval, char **
} else {
if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) {
*errmsg = e_invarg;
- } else if (strcmp(p_ve, oldval) != 0) {
+ } else if (strcmp(ve, oldval) != 0) {
// Recompute cursor position in case the new 've' setting
// changes something.
validate_virtcol_win(win);
+ // XXX: this only works when win == curwin
coladvance(win->w_virtcol);
}
}
@@ -1497,12 +1508,12 @@ static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, char **errms
}
}
-static void did_set_optexpr(win_T *win, char **p_opt, char **varp, char **gvarp)
+static void did_set_optexpr(char **varp)
{
- char *name = get_scriptlocal_funcname(*p_opt);
+ char *name = get_scriptlocal_funcname(*varp);
if (name != NULL) {
- free_string_option(*p_opt);
- *p_opt = name;
+ free_string_option(*varp);
+ *varp = name;
}
}
@@ -1511,8 +1522,8 @@ static void did_set_option_listflag(char **varp, char *flags, char *errbuf, size
char **errmsg)
{
for (char *s = *varp; *s; s++) {
- if (vim_strchr(flags, *s) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, *s);
+ if (vim_strchr(flags, (uint8_t)(*s)) == NULL) {
+ *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
break;
}
}
@@ -1560,7 +1571,7 @@ static void do_filetype_autocmd(buf_T *buf, char **varp, int opt_flags, bool val
}
}
-static void did_set_spelllang_source(win_T *win)
+static void do_spelllang_source(win_T *win)
{
char fname[200];
char *q = win->w_s->b_p_spl;
@@ -1613,243 +1624,238 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char
char **gvarp = (char **)get_varp_scope(opt, OPT_GLOBAL);
// Disallow changing some options from secure mode
- if ((secure || sandbox != 0)
- && (opt->flags & P_SECURE)) {
+ if ((secure || sandbox != 0) && (opt->flags & P_SECURE)) {
errmsg = e_secure;
- } else if (check_illegal_path_names(*varp, opt->flags)) {
// Check for a "normal" directory or file name in some options.
+ } else if (check_illegal_path_names(*varp, opt->flags)) {
errmsg = e_invarg;
- } else if (gvarp == &p_bkc) { // 'backupcopy'
+ } else if (gvarp == &p_bkc) { // 'backupcopy'
did_set_backupcopy(buf, oldval, opt_flags, &errmsg);
- } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode'
+ } else if (varp == &p_bex // 'backupext'
+ || varp == &p_pm) { // 'patchmode'
did_set_backupext_or_patchmode(&errmsg);
- } else if (varp == &win->w_p_briopt) { // 'breakindentopt'
+ } else if (varp == &win->w_p_briopt) { // 'breakindentopt'
did_set_breakindentopt(win, &errmsg);
- } else if (varp == &p_isi
- || varp == &buf->b_p_isk
- || varp == &p_isp
- || varp == &p_isf) {
- // 'isident', 'iskeyword', 'isprint or 'isfname' option
+ } else if (varp == &p_isi // 'isident'
+ || varp == &buf->b_p_isk // 'iskeyword'
+ || varp == &p_isp // 'isprint'
+ || varp == &p_isf) { // 'isfname'
did_set_isopt(buf, &did_chartab, &errmsg);
- } else if (varp == &p_hf) { // 'helpfile'
+ } else if (varp == &p_hf) { // 'helpfile'
did_set_helpfile();
- } else if (varp == &p_rtp || varp == &p_pp) { // 'runtimepath' 'packpath'
+ } else if (varp == &p_rtp // 'runtimepath'
+ || varp == &p_pp) { // 'packpath'
runtime_search_path_invalidate();
- } else if (varp == &win->w_p_culopt
- || gvarp == &win->w_allbuf_opt.wo_culopt) { // 'cursorlineopt'
+ } else if (gvarp == &win->w_allbuf_opt.wo_culopt) { // 'cursorlineopt'
did_set_cursorlineopt(win, varp, &errmsg);
- } else if (varp == &win->w_p_cc) { // 'colorcolumn'
+ } else if (varp == &win->w_p_cc) { // 'colorcolumn'
errmsg = check_colorcolumn(win);
- } else if (varp == &p_hlg) { // 'helplang'
+ } else if (varp == &p_hlg) { // 'helplang'
did_set_helplang(&errmsg);
- } else if (varp == &p_hl) { // 'highlight'
+ } else if (varp == &p_hl) { // 'highlight'
did_set_highlight(varp, &errmsg);
- } else if (varp == &p_jop) { // 'jumpoptions'
+ } else if (varp == &p_jop) { // 'jumpoptions'
did_set_opt_flags(p_jop, p_jop_values, &jop_flags, true, &errmsg);
- } else if (gvarp == &p_nf) { // 'nrformats'
+ } else if (gvarp == &p_nf) { // 'nrformats'
did_set_opt_strings(*varp, p_nf_values, true, &errmsg);
- } else if (varp == &p_ssop) { // 'sessionoptions'
+ } else if (varp == &p_ssop) { // 'sessionoptions'
did_set_sessionoptions(oldval, &errmsg);
- } else if (varp == &p_vop) { // 'viewoptions'
+ } else if (varp == &p_vop) { // 'viewoptions'
did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true, &errmsg);
- } else if (varp == &p_rdb) { // 'redrawdebug'
+ } else if (varp == &p_rdb) { // 'redrawdebug'
did_set_opt_flags(p_rdb, p_rdb_values, &rdb_flags, true, &errmsg);
- } else if (varp == &p_sbo) { // 'scrollopt'
+ } else if (varp == &p_sbo) { // 'scrollopt'
did_set_opt_strings(p_sbo, p_scbopt_values, true, &errmsg);
- } else if (varp == &p_ambw || (int *)varp == &p_emoji) { // 'ambiwidth'
+ } else if (varp == &p_ambw // 'ambiwidth'
+ || (int *)varp == &p_emoji) { // 'emoji'
did_set_ambiwidth(&errmsg);
- } else if (varp == &p_bg) { // 'background'
+ } else if (varp == &p_bg) { // 'background'
did_set_background(&errmsg);
- } else if (varp == &p_wim) { // 'wildmode'
+ } else if (varp == &p_wim) { // 'wildmode'
did_set_wildmode(&errmsg);
- } else if (varp == &p_wop) { // 'wildoptions'
+ } else if (varp == &p_wop) { // 'wildoptions'
did_set_opt_flags(p_wop, p_wop_values, &wop_flags, true, &errmsg);
- } else if (varp == &p_wak) { // 'winaltkeys'
+ } else if (varp == &p_wak) { // 'winaltkeys'
did_set_winaltkeys(&errmsg);
- } else if (varp == &p_ei) { // 'eventignore'
+ } else if (varp == &p_ei) { // 'eventignore'
did_set_eventignore(&errmsg);
- } else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) {
- // 'encoding', 'fileencoding' and 'makeencoding'
+ } else if (varp == &p_enc // 'encoding'
+ || gvarp == &p_fenc // 'fileencoding'
+ || gvarp == &p_menc) { // 'makeencoding'
did_set_encoding(buf, varp, gvarp, opt_flags, &errmsg);
- } else if (varp == &buf->b_p_keymap) {
+ } else if (varp == &buf->b_p_keymap) { // 'keymap'
did_set_keymap(buf, varp, opt_flags, value_checked, &errmsg);
- } else if (gvarp == &p_ff) { // 'fileformat'
+ } else if (gvarp == &p_ff) { // 'fileformat'
did_set_fileformat(buf, varp, oldval, opt_flags, &errmsg);
- } else if (varp == &p_ffs) { // 'fileformats'
+ } else if (varp == &p_ffs) { // 'fileformats'
did_set_opt_strings(p_ffs, p_ff_values, true, &errmsg);
- } else if (gvarp == &p_mps) { // 'matchpairs'
+ } else if (gvarp == &p_mps) { // 'matchpairs'
did_set_matchpairs(varp, &errmsg);
- } else if (gvarp == &p_com) { // 'comments'
+ } else if (gvarp == &p_com) { // 'comments'
did_set_comments(varp, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_lcs || varp == &p_fcs) { // global 'listchars' or 'fillchars'
+ } else if (varp == &p_lcs // global 'listchars'
+ || varp == &p_fcs) { // global 'fillchars'
did_set_global_listfillchars(win, varp, opt_flags, &errmsg);
- } else if (varp == &win->w_p_lcs) { // local 'listchars'
+ } else if (varp == &win->w_p_lcs) { // local 'listchars'
errmsg = set_chars_option(win, varp, true);
- } else if (varp == &win->w_p_fcs) { // local 'fillchars'
+ } else if (varp == &win->w_p_fcs) { // local 'fillchars'
errmsg = set_chars_option(win, varp, true);
- } else if (varp == &p_cedit) { // 'cedit'
+ } else if (varp == &p_cedit) { // 'cedit'
errmsg = check_cedit();
- } else if (varp == &p_vfile) { // 'verbosefile'
+ } else if (varp == &p_vfile) { // 'verbosefile'
did_set_verbosefile(&errmsg);
- } else if (varp == &p_shada) { // 'shada'
+ } else if (varp == &p_shada) { // 'shada'
did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen, &errmsg);
- } else if (gvarp == &p_sbr) { // 'showbreak'
+ } else if (gvarp == &p_sbr) { // 'showbreak'
did_set_showbreak(varp, &errmsg);
- } else if (varp == &p_guicursor) { // 'guicursor'
+ } else if (varp == &p_guicursor) { // 'guicursor'
errmsg = parse_shape_opt(SHAPE_CURSOR);
- } else if (varp == &p_langmap) { // 'langmap'
+ } else if (varp == &p_langmap) { // 'langmap'
langmap_set();
- } else if (varp == &p_breakat) { // 'breakat'
+ } else if (varp == &p_breakat) { // 'breakat'
fill_breakat_flags();
- } else if (varp == &p_titlestring || varp == &p_iconstring) {
- // 'titlestring' and 'iconstring'
+ } else if (varp == &p_titlestring // 'titlestring'
+ || varp == &p_iconstring) { // 'iconstring'
did_set_titleiconstring(varp);
- } else if (varp == &p_sel) { // 'selection'
+ } else if (varp == &p_sel) { // 'selection'
did_set_selection(&errmsg);
- } else if (varp == &p_slm) { // 'selectmode'
+ } else if (varp == &p_slm) { // 'selectmode'
did_set_opt_strings(p_slm, p_slm_values, true, &errmsg);
- } else if (varp == &p_km) { // 'keymodel'
+ } else if (varp == &p_km) { // 'keymodel'
did_set_keymodel(&errmsg);
- } else if (varp == &p_mousem) { // 'mousemodel'
+ } else if (varp == &p_mousem) { // 'mousemodel'
did_set_opt_strings(p_mousem, p_mousem_values, false, &errmsg);
- } else if (varp == &p_mousescroll) { // 'mousescroll'
+ } else if (varp == &p_mousescroll) { // 'mousescroll'
errmsg = check_mousescroll(p_mousescroll);
- } else if (varp == &p_swb) { // 'switchbuf'
+ } else if (varp == &p_swb) { // 'switchbuf'
did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true, &errmsg);
- } else if (varp == &p_spk) { // 'splitkeep'
+ } else if (varp == &p_spk) { // 'splitkeep'
did_set_opt_strings(p_spk, p_spk_values, false, &errmsg);
- } else if (varp == &p_debug) { // 'debug'
+ } else if (varp == &p_debug) { // 'debug'
did_set_opt_strings(p_debug, p_debug_values, true, &errmsg);
- } else if (varp == &p_dy) { // 'display'
+ } else if (varp == &p_dy) { // 'display'
did_set_display(&errmsg);
- } else if (varp == &p_ead) { // 'eadirection'
+ } else if (varp == &p_ead) { // 'eadirection'
did_set_opt_strings(p_ead, p_ead_values, false, &errmsg);
- } else if (varp == &p_cb) { // 'clipboard'
+ } else if (varp == &p_cb) { // 'clipboard'
did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true, &errmsg);
- } else if (varp == &win->w_s->b_p_spf) {
+ } else if (varp == &win->w_s->b_p_spf) { // 'spellfile'
did_set_spellfile(varp, &errmsg);
- } else if (varp == &win->w_s->b_p_spl) { // 'spell'
+ } else if (varp == &win->w_s->b_p_spl) { // 'spell'
did_set_spell(varp, &errmsg);
- } else if (varp == &win->w_s->b_p_spc) {
+ } else if (varp == &win->w_s->b_p_spc) { // 'spellcapcheck'
did_set_spellcapcheck(win, &errmsg);
- } else if (varp == &win->w_s->b_p_spo) { // 'spelloptions'
+ } else if (varp == &win->w_s->b_p_spo) { // 'spelloptions'
did_set_spelloptions(win, &errmsg);
- } else if (varp == &p_sps) { // 'spellsuggest'
+ } else if (varp == &p_sps) { // 'spellsuggest'
did_set_spellsuggest(&errmsg);
- } else if (varp == &p_msm) { // 'mkspellmem'
+ } else if (varp == &p_msm) { // 'mkspellmem'
did_set_mkspellmem(&errmsg);
- } else if (gvarp == &p_bh) {
+ } else if (gvarp == &p_bh) { // 'bufhidden'
did_set_opt_strings(buf->b_p_bh, p_bufhidden_values, false, &errmsg);
- } else if (gvarp == &p_bt) { // 'buftype'
+ } else if (gvarp == &p_bt) { // 'buftype'
did_set_buftype(buf, win, &errmsg);
- } else if (gvarp == &p_stl || gvarp == &p_wbr || varp == &p_tal
- || varp == &p_ruf || varp == &win->w_p_stc) {
- // 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn'
+ } else if (gvarp == &p_stl // 'statusline'
+ || gvarp == &p_wbr // 'winbar'
+ || varp == &p_tal // 'tabline'
+ || varp == &p_ruf // 'rulerformat'
+ || varp == &win->w_p_stc) { // 'statuscolumn'
did_set_statusline(win, varp, gvarp, &errmsg);
- } else if (gvarp == &p_cpt) { // 'complete'
+ } else if (gvarp == &p_cpt) { // 'complete'
did_set_complete(varp, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_cot) { // 'completeopt'
+ } else if (varp == &p_cot) { // 'completeopt'
did_set_completeopt(&errmsg);
#ifdef BACKSLASH_IN_FILENAME
- } else if (gvarp == &p_csl) { // 'completeslash'
- if (check_opt_strings(p_csl, p_csl_values, false) != OK
- || check_opt_strings(buf->b_p_csl, p_csl_values, false) != OK) {
- errmsg = e_invarg;
- }
+ } else if (gvarp == &p_csl) { // 'completeslash'
+ did_set_completeslash(buf, &errmsg);
#endif
- } else if (varp == &win->w_p_scl) { // 'signcolumn'
+ } else if (varp == &win->w_p_scl) { // 'signcolumn'
did_set_signcolumn(win, varp, oldval, &errmsg);
- } else if (varp == &p_sloc) { // 'showcmdloc'
+ } else if (varp == &p_sloc) { // 'showcmdloc'
did_set_opt_strings(*varp, p_sloc_values, false, &errmsg);
- } else if (varp == &win->w_p_fdc
- || varp == &win->w_allbuf_opt.wo_fdc) {
- // 'foldcolumn'
+ } else if (gvarp == &win->w_allbuf_opt.wo_fdc) { // 'foldcolumn'
did_set_foldcolumn(varp, &errmsg);
- } else if (varp == &p_pt) { // 'pastetoggle'
+ } else if (varp == &p_pt) { // 'pastetoggle'
did_set_pastetoggle();
- } else if (varp == &p_bs) { // 'backspace'
+ } else if (varp == &p_bs) { // 'backspace'
did_set_backspace(&errmsg);
} else if (varp == &p_bo) {
did_set_opt_flags(p_bo, p_bo_values, &bo_flags, true, &errmsg);
- } else if (gvarp == &p_tc) { // 'tagcase'
+ } else if (gvarp == &p_tc) { // 'tagcase'
did_set_tagcase(buf, opt_flags, &errmsg);
- } else if (varp == &p_cmp) { // 'casemap'
+ } else if (varp == &p_cmp) { // 'casemap'
did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true, &errmsg);
- } else if (varp == &p_dip) { // 'diffopt'
+ } else if (varp == &p_dip) { // 'diffopt'
did_set_diffopt(&errmsg);
- } else if (gvarp == &win->w_allbuf_opt.wo_fdm) { // 'foldmethod'
+ } else if (gvarp == &win->w_allbuf_opt.wo_fdm) { // 'foldmethod'
did_set_foldmethod(win, varp, &errmsg);
- } else if (gvarp == &win->w_allbuf_opt.wo_fmr) { // 'foldmarker'
+ } else if (gvarp == &win->w_allbuf_opt.wo_fmr) { // 'foldmarker'
did_set_foldmarker(win, varp, &errmsg);
- } else if (gvarp == &p_cms) { // 'commentstring'
+ } else if (gvarp == &p_cms) { // 'commentstring'
did_set_commentstring(varp, &errmsg);
- } else if (varp == &p_fdo) { // 'foldopen'
+ } else if (varp == &p_fdo) { // 'foldopen'
did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, true, &errmsg);
- } else if (varp == &p_fcl) { // 'foldclose'
+ } else if (varp == &p_fcl) { // 'foldclose'
did_set_opt_strings(*varp, p_fcl_values, true, &errmsg);
- } else if (gvarp == &win->w_allbuf_opt.wo_fdi) { // 'foldignore'
+ } else if (gvarp == &win->w_allbuf_opt.wo_fdi) { // 'foldignore'
did_set_foldignore(win);
- } else if (gvarp == &p_ve) { // 'virtualedit'
+ } else if (gvarp == &p_ve) { // 'virtualedit'
did_set_virtualedit(win, opt_flags, oldval, &errmsg);
- } else if (gvarp == &p_cino) { // 'cinoptions'
+ } else if (gvarp == &p_cino) { // 'cinoptions'
// TODO(vim): recognize errors
parse_cino(buf);
- } else if (gvarp == &p_lop) { // 'lispoptions'
+ } else if (gvarp == &p_lop) { // 'lispoptions'
did_set_lispoptions(varp, &errmsg);
- } else if (varp == &p_icm) { // 'inccommand'
+ } else if (varp == &p_icm) { // 'inccommand'
did_set_opt_strings(*varp, p_icm_values, false, &errmsg);
- } else if (gvarp == &p_ft || gvarp == &p_syn) {
+ } else if (gvarp == &p_ft // 'filetype'
+ || gvarp == &p_syn) { // 'syntax'
did_set_filetype_or_syntax(varp, oldval, value_checked, &value_changed, &errmsg);
- } else if (varp == &win->w_p_winhl) {
+ } else if (varp == &win->w_p_winhl) { // 'winhighlight'
did_set_winhl(win, &errmsg);
} else if (varp == &p_tpf) {
did_set_opt_flags(p_tpf, p_tpf_values, &tpf_flags, true, &errmsg);
- } else if (varp == &buf->b_p_vsts) { // 'varsofttabstop'
+ } else if (varp == &buf->b_p_vsts) { // 'varsofttabstop'
did_set_varsoftabstop(buf, varp, &errmsg);
- } else if (varp == &buf->b_p_vts) { // 'vartabstop'
+ } else if (varp == &buf->b_p_vts) { // 'vartabstop'
did_set_vartabstop(buf, win, varp, &errmsg);
- } else if (varp == &p_dex) { // 'diffexpr'
- did_set_optexpr(win, &p_dex, varp, gvarp);
- } else if (varp == &win->w_p_fde) { // 'foldexpr'
- did_set_optexpr(win, &win->w_p_fde, varp, gvarp);
- if (foldmethodIsExpr(win)) {
+ } else if (varp == &p_dex // 'diffexpr'
+ || gvarp == &win->w_allbuf_opt.wo_fde // 'foldexpr'
+ || gvarp == &win->w_allbuf_opt.wo_fdt // 'foldtext'
+ || gvarp == &p_fex // 'formatexpr'
+ || gvarp == &p_inex // 'includeexpr'
+ || gvarp == &p_inde // 'indentexpr'
+ || varp == &p_pex // 'patchexpr'
+ || varp == &p_ccv) { // 'charconvert'
+ did_set_optexpr(varp);
+ if (varp == &win->w_p_fde && foldmethodIsExpr(win)) {
foldUpdateAll(win);
}
- } else if (varp == &win->w_p_fdt) { // 'foldtext'
- did_set_optexpr(win, &win->w_p_fdt, varp, gvarp);
- } else if (varp == &p_pex) { // 'patchexpr'
- did_set_optexpr(win, &p_pex, varp, gvarp);
- } else if (gvarp == &p_fex) { // 'formatexpr'
- did_set_optexpr(win, &buf->b_p_fex, varp, gvarp);
- } else if (gvarp == &p_inex) { // 'includeexpr'
- did_set_optexpr(win, &buf->b_p_inex, varp, gvarp);
- } else if (gvarp == &p_inde) { // 'indentexpr'
- did_set_optexpr(win, &buf->b_p_inde, varp, gvarp);
- } else if (gvarp == &p_cfu) { // 'completefunc'
+ } else if (gvarp == &p_cfu) { // 'completefunc'
set_completefunc_option(&errmsg);
- } else if (gvarp == &p_ofu) { // 'omnifunc'
+ } else if (gvarp == &p_ofu) { // 'omnifunc'
set_omnifunc_option(buf, &errmsg);
- } else if (gvarp == &p_tsrfu) { // 'thesaurusfunc'
+ } else if (gvarp == &p_tsrfu) { // 'thesaurusfunc'
set_thesaurusfunc_option(&errmsg);
- } else if (varp == &p_opfunc) { // 'operatorfunc'
+ } else if (varp == &p_opfunc) { // 'operatorfunc'
set_operatorfunc_option(&errmsg);
- } else if (varp == &p_qftf) { // 'quickfixtextfunc'
+ } else if (varp == &p_qftf) { // 'quickfixtextfunc'
qf_process_qftf_option(&errmsg);
- } else if (gvarp == &p_tfu) { // 'tagfunc'
+ } else if (gvarp == &p_tfu) { // 'tagfunc'
set_tagfunc_option(&errmsg);
- } else if (varp == &p_ww) { // 'whichwrap'
+ } else if (varp == &p_ww) { // 'whichwrap'
did_set_option_listflag(varp, WW_ALL, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_shm) { // 'shortmess'
+ } else if (varp == &p_shm) { // 'shortmess'
did_set_option_listflag(varp, SHM_ALL, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_cpo) { // 'cpoptions'
+ } else if (varp == &p_cpo) { // 'cpoptions'
did_set_option_listflag(varp, CPO_VI, errbuf, errbuflen, &errmsg);
- } else if (varp == &buf->b_p_fo) { // 'formatoptions'
+ } else if (varp == &buf->b_p_fo) { // 'formatoptions'
did_set_option_listflag(varp, FO_ALL, errbuf, errbuflen, &errmsg);
- } else if (varp == &win->w_p_cocu) { // 'concealcursor'
+ } else if (varp == &win->w_p_cocu) { // 'concealcursor'
did_set_option_listflag(varp, COCU_ALL, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_mouse) { // 'mouse'
+ } else if (varp == &p_mouse) { // 'mouse'
did_set_option_listflag(varp, MOUSE_ALL, errbuf, errbuflen, &errmsg);
- } else if (gvarp == &p_flp) {
+ } else if (gvarp == &p_flp) { // 'formatlistpat'
if (win->w_briopt_list) {
// Changing Formatlistpattern when briopt includes the list setting:
// redraw
@@ -1857,7 +1863,7 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char
}
}
- // If error detected, restore the previous value.
+ // If an error is detected, restore the previous value.
if (errmsg != NULL) {
free_string_option(*varp);
*varp = oldval;
@@ -1894,7 +1900,7 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char
} else if (varp == &buf->b_p_ft) {
do_filetype_autocmd(buf, varp, opt_flags, value_changed);
} else if (varp == &win->w_s->b_p_spl) {
- did_set_spelllang_source(win);
+ do_spelllang_source(win);
}
}
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 302faa8140..6157341ec9 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -146,11 +146,7 @@ bool os_isdir(const char *name)
return false;
}
- if (!S_ISDIR(mode)) {
- return false;
- }
-
- return true;
+ return S_ISDIR(mode);
}
/// Check what `name` is:
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 513f366a27..e4c2253357 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1138,7 +1138,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl
if (flags & EW_ADDSLASH) {
glob_flags |= WILD_ADD_SLASH;
}
- globpath(paths, pattern, gap, glob_flags);
+ globpath(paths, pattern, gap, glob_flags, false);
xfree(paths);
return gap->ga_len;
diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c
index 1b32447d77..af3d93f7c4 100644
--- a/src/nvim/regexp_bt.c
+++ b/src/nvim/regexp_bt.c
@@ -2862,7 +2862,7 @@ static regprog_T *bt_regcomp(uint8_t *expr, int re_flags)
}
// Allocate space.
- bt_regprog_T *r = xmalloc(sizeof(bt_regprog_T) + (size_t)regsize);
+ bt_regprog_T *r = xmalloc(offsetof(bt_regprog_T, program) + (size_t)regsize);
r->re_in_use = false;
// Second pass: emit code.
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 93b03f0632..ea59e7d464 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -7511,7 +7511,7 @@ static regprog_T *nfa_regcomp(uint8_t *expr, int re_flags)
post2nfa(postfix, post_ptr, true);
// allocate the regprog with space for the compiled regexp
- size_t prog_size = sizeof(nfa_regprog_T) + sizeof(nfa_state_T) * (size_t)(nstate - 1);
+ size_t prog_size = offsetof(nfa_regprog_T, state) + sizeof(nfa_state_T) * (size_t)nstate;
prog = xmalloc(prog_size);
state_ptr = prog->state;
prog->re_in_use = false;
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 24500b80b9..b071e10cf9 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -26,6 +26,7 @@
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
@@ -208,29 +209,56 @@ void runtime_init(void)
uv_mutex_init(&runtime_search_path_mutex);
}
-/// ":runtime [what] {name}"
+/// Get DIP_ flags from the [where] argument of a :runtime command.
+/// "*argp" is advanced to after the [where] argument.
+static int get_runtime_cmd_flags(char **argp, size_t where_len)
+{
+ char *arg = *argp;
+
+ if (where_len == 0) {
+ return 0;
+ }
+
+ if (strncmp(arg, "START", where_len) == 0) {
+ *argp = skipwhite(arg + where_len);
+ return DIP_START + DIP_NORTP;
+ }
+ if (strncmp(arg, "OPT", where_len) == 0) {
+ *argp = skipwhite(arg + where_len);
+ return DIP_OPT + DIP_NORTP;
+ }
+ if (strncmp(arg, "PACK", where_len) == 0) {
+ *argp = skipwhite(arg + where_len);
+ return DIP_START + DIP_OPT + DIP_NORTP;
+ }
+ if (strncmp(arg, "ALL", where_len) == 0) {
+ *argp = skipwhite(arg + where_len);
+ return DIP_START + DIP_OPT;
+ }
+
+ return 0;
+}
+
+/// ":runtime [where] {name}"
void ex_runtime(exarg_T *eap)
{
char *arg = eap->arg;
- char *p = skiptowhite(arg);
- size_t len = (size_t)(p - arg);
int flags = eap->forceit ? DIP_ALL : 0;
+ char *p = skiptowhite(arg);
+ flags += get_runtime_cmd_flags(&arg, (size_t)(p - arg));
+ source_runtime(arg, flags);
+}
- if (strncmp(arg, "START", len) == 0) {
- flags += DIP_START + DIP_NORTP;
- arg = skipwhite(arg + len);
- } else if (strncmp(arg, "OPT", len) == 0) {
- flags += DIP_OPT + DIP_NORTP;
- arg = skipwhite(arg + len);
- } else if (strncmp(arg, "PACK", len) == 0) {
- flags += DIP_START + DIP_OPT + DIP_NORTP;
- arg = skipwhite(arg + len);
- } else if (strncmp(arg, "ALL", len) == 0) {
- flags += DIP_START + DIP_OPT;
- arg = skipwhite(arg + len);
- }
+static int runtime_expand_flags;
- source_runtime(arg, flags);
+/// Set the completion context for the :runtime command.
+void set_context_in_runtime_cmd(expand_T *xp, const char *arg)
+{
+ char *p = skiptowhite(arg);
+ runtime_expand_flags
+ = *p != NUL ? get_runtime_cmd_flags((char **)&arg, (size_t)(p - arg)) : 0;
+ xp->xp_context = EXPAND_RUNTIME;
+ xp->xp_pattern = (char *)arg;
}
static void source_callback(char *fname, void *cookie)
@@ -1175,102 +1203,154 @@ void ex_packadd(exarg_T *eap)
}
}
-/// Expand color scheme, compiler or filetype names.
-/// Search from 'runtimepath':
-/// 'runtimepath'/{dirnames}/{pat}.(vim|lua)
-/// When "flags" has DIP_START: search also from "start" of 'packpath':
-/// 'packpath'/pack/*/start/*/{dirnames}/{pat}.(vim|lua)
-/// When "flags" has DIP_OPT: search also from "opt" of 'packpath':
-/// 'packpath'/pack/*/opt/*/{dirnames}/{pat}.(vim|lua)
-/// "dirnames" is an array with one or more directory names.
-int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[])
+static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap,
+ char *dirnames[])
{
- *num_file = 0;
- *file = NULL;
- size_t pat_len = strlen(pat);
-
- garray_T ga;
- ga_init(&ga, (int)sizeof(char *), 10);
-
// TODO(bfredl): this is bullshit, expandpath should not reinvent path logic.
for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 16;
- char *s = xmalloc(size);
- snprintf(s, size, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat);
- globpath(p_rtp, s, &ga, 0);
- xfree(s);
- }
+ const size_t buf_len = strlen(dirnames[i]) + pat_len + 31;
+ char *const buf = xmalloc(buf_len);
+ char *const tail = buf + 15;
+ const size_t tail_buflen = buf_len - 15;
+ int glob_flags = 0;
+ bool expand_dirs = false;
+
+ if (*dirnames[i] == NUL) { // empty dir used for :runtime
+ snprintf(tail, tail_buflen, "%s*.\\(vim\\|lua\\)", pat);
+ } else {
+ snprintf(tail, tail_buflen, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat);
+ }
- if (flags & DIP_START) {
- for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 31;
- char *s = xmalloc(size);
- snprintf(s, size, "pack/*/start/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
- xfree(s);
+expand:
+ if ((flags & DIP_NORTP) == 0) {
+ globpath(p_rtp, tail, gap, glob_flags, expand_dirs);
}
- for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 31;
- char *s = xmalloc(size);
- snprintf(s, size, "start/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
- xfree(s);
+ if (flags & DIP_START) {
+ memcpy(tail - 15, "pack/*/start/*/", 15); // NOLINT
+ globpath(p_pp, tail - 15, gap, glob_flags, expand_dirs);
+ memcpy(tail - 8, "start/*/", 8); // NOLINT
+ globpath(p_pp, tail - 8, gap, glob_flags, expand_dirs);
}
- }
- if (flags & DIP_OPT) {
- for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 29;
- char *s = xmalloc(size);
- snprintf(s, size, "pack/*/opt/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
- xfree(s);
+ if (flags & DIP_OPT) {
+ memcpy(tail - 13, "pack/*/opt/*/", 13); // NOLINT
+ globpath(p_pp, tail - 13, gap, glob_flags, expand_dirs);
+ memcpy(tail - 6, "opt/*/", 6); // NOLINT
+ globpath(p_pp, tail - 6, gap, glob_flags, expand_dirs);
}
- for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 29;
- char *s = xmalloc(size);
- snprintf(s, size, "opt/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
- xfree(s);
+ if (*dirnames[i] == NUL && !expand_dirs) {
+ // expand dir names in another round
+ snprintf(tail, tail_buflen, "%s*", pat);
+ glob_flags = WILD_ADD_SLASH;
+ expand_dirs = true;
+ goto expand;
}
+
+ xfree(buf);
}
- for (int i = 0; i < ga.ga_len; i++) {
- char *match = ((char **)ga.ga_data)[i];
+ int pat_pathsep_cnt = 0;
+ for (size_t i = 0; i < pat_len; i++) {
+ if (vim_ispathsep(pat[i])) {
+ pat_pathsep_cnt++;
+ }
+ }
+
+ for (int i = 0; i < gap->ga_len; i++) {
+ char *match = ((char **)gap->ga_data)[i];
char *s = match;
char *e = s + strlen(s);
- if (e - s > 4 && (STRNICMP(e - 4, ".vim", 4) == 0
- || STRNICMP(e - 4, ".lua", 4) == 0)) {
+ if (e - s > 4 && !keep_ext && (STRNICMP(e - 4, ".vim", 4) == 0
+ || STRNICMP(e - 4, ".lua", 4) == 0)) {
e -= 4;
- for (s = e; s > match; MB_PTR_BACK(match, s)) {
- if (vim_ispathsep(*s)) {
- break;
- }
- }
- s++;
*e = NUL;
+ }
+
+ int match_pathsep_cnt = (e > s && e[-1] == '/') ? -1 : 0;
+ for (s = e; s > match; MB_PTR_BACK(match, s)) {
+ if (vim_ispathsep(*s) && ++match_pathsep_cnt > pat_pathsep_cnt) {
+ break;
+ }
+ }
+ s++;
+ if (s != match) {
assert((e - s) + 1 >= 0);
memmove(match, s, (size_t)(e - s) + 1);
}
}
- if (GA_EMPTY(&ga)) {
- return FAIL;
+ if (GA_EMPTY(gap)) {
+ return;
}
// Sort and remove duplicates which can happen when specifying multiple
// directories in dirnames.
- ga_remove_duplicate_strings(&ga);
+ ga_remove_duplicate_strings(gap);
+}
+
+/// Expand color scheme, compiler or filetype names.
+/// Search from 'runtimepath':
+/// 'runtimepath'/{dirnames}/{pat}.(vim|lua)
+/// When "flags" has DIP_START: search also from "start" of 'packpath':
+/// 'packpath'/pack/*/start/*/{dirnames}/{pat}.(vim|lua)
+/// When "flags" has DIP_OPT: search also from "opt" of 'packpath':
+/// 'packpath'/pack/*/opt/*/{dirnames}/{pat}.(vim|lua)
+/// "dirnames" is an array with one or more directory names.
+int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[])
+{
+ *num_file = 0;
+ *file = NULL;
+
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char *), 10);
+
+ ExpandRTDir_int(pat, strlen(pat), flags, false, &ga, dirnames);
+
+ if (GA_EMPTY(&ga)) {
+ return FAIL;
+ }
*file = ga.ga_data;
*num_file = ga.ga_len;
return OK;
}
+/// Handle command line completion for :runtime command.
+int expand_runtime_cmd(char *pat, int *numMatches, char ***matches)
+{
+ *numMatches = 0;
+ *matches = NULL;
+
+ garray_T ga;
+ ga_init(&ga, sizeof(char *), 10);
+
+ const size_t pat_len = strlen(pat);
+ char *dirnames[] = { "", NULL };
+ ExpandRTDir_int(pat, pat_len, runtime_expand_flags, true, &ga, dirnames);
+
+ // Try to complete values for [where] argument when none was found.
+ if (runtime_expand_flags == 0) {
+ char *where_values[] = { "START", "OPT", "PACK", "ALL" };
+ for (size_t i = 0; i < ARRAY_SIZE(where_values); i++) {
+ if (strncmp(pat, where_values[i], pat_len) == 0) {
+ GA_APPEND(char *, &ga, xstrdup(where_values[i]));
+ }
+ }
+ }
+
+ if (GA_EMPTY(&ga)) {
+ return FAIL;
+ }
+
+ *matches = ga.ga_data;
+ *numMatches = ga.ga_len;
+ return OK;
+}
+
/// Expand loadplugin names:
-/// 'packpath'/pack/ * /opt/{pat}
+/// 'packpath'/pack/*/opt/{pat}
int ExpandPackAddDir(char *pat, int *num_file, char ***file)
{
garray_T ga;
@@ -1283,9 +1363,9 @@ int ExpandPackAddDir(char *pat, int *num_file, char ***file)
size_t buflen = pat_len + 26;
char *s = xmalloc(buflen);
snprintf(s, buflen, "pack/*/opt/%s*", pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
+ globpath(p_pp, s, &ga, 0, true);
snprintf(s, buflen, "opt/%s*", pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
+ globpath(p_pp, s, &ga, 0, true);
xfree(s);
for (int i = 0; i < ga.ga_len; i++) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 2002f554d4..f35912849d 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -768,7 +768,6 @@ void comp_col(void)
/// Otherwise it depends on 'numberwidth' and the line count.
int number_width(win_T *wp)
{
- int n;
linenr_T lnum;
if (wp->w_p_rnu && !wp->w_p_nu) {
@@ -784,17 +783,13 @@ int number_width(win_T *wp)
}
wp->w_nrwidth_line_count = lnum;
- // make best estimate for 'statuscolumn'
+ // reset for 'statuscolumn'
if (*wp->w_p_stc != NUL) {
- char buf[MAXPATHL];
- wp->w_nrwidth_width = 0;
- n = build_statuscol_str(wp, lnum, 0, 0, NUL, buf, NULL, NULL);
- n = MAX(n, (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw);
- wp->w_nrwidth_width = MIN(n, MAX_NUMBERWIDTH);
+ wp->w_nrwidth_width = (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw;
return wp->w_nrwidth_width;
}
- n = 0;
+ int n = 0;
do {
lnum /= 10;
n++;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index b24b6ad27c..eb5cc2e07f 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -2644,7 +2644,12 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh
len += 2;
}
- memmove(msgbuf + strlen(msgbuf) - len, t, len);
+ size_t msgbuf_len = strlen(msgbuf);
+ if (len > msgbuf_len) {
+ len = msgbuf_len;
+ }
+ memmove(msgbuf + msgbuf_len - len, t, len);
+
if (dirc == '?' && stat.cur == maxcount + 1) {
stat.cur = -1;
}
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index d0c093d93a..00e282b76e 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -103,7 +103,7 @@ static signgroup_T *sign_group_ref(const char *groupname)
hi = hash_lookup(&sg_table, (char *)groupname, strlen(groupname), hash);
if (HASHITEM_EMPTY(hi)) {
// new group
- group = xmalloc(sizeof(signgroup_T) + strlen(groupname));
+ group = xmalloc(offsetof(signgroup_T, sg_name) + strlen(groupname) + 1);
STRCPY(group->sg_name, groupname);
group->sg_refcount = 1;
diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h
index 16e783aab7..7aa06ce48a 100644
--- a/src/nvim/sign_defs.h
+++ b/src/nvim/sign_defs.h
@@ -10,9 +10,9 @@
// Sign group
typedef struct signgroup_S {
- uint16_t sg_refcount; // number of signs in this group
- int sg_next_sign_id; // next sign id for this group
- char sg_name[1]; // sign group name
+ int sg_next_sign_id; ///< next sign id for this group
+ uint16_t sg_refcount; ///< number of signs in this group
+ char sg_name[1]; ///< sign group name, actually longer
} signgroup_T;
// Macros to get the sign group structure from the group name
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 8e18be5bd1..2204cda169 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1745,7 +1745,7 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count)
const size_t p_len = strlen(p);
hashitem_T *hi = hash_lookup(&lp->sl_wordcount, (const char *)p, p_len, hash);
if (HASHITEM_EMPTY(hi)) {
- wc = xmalloc(sizeof(wordcount_T) + p_len);
+ wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1);
memcpy(wc->wc_word, p, p_len + 1);
wc->wc_count = count;
hash_add_item(&lp->sl_wordcount, hi, (char *)wc->wc_word, hash);
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 44414ca1a5..7b124ae6b6 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -3855,7 +3855,7 @@ static void *getroom(spellinfo_T *spin, size_t len, bool align)
if (bl == NULL || (size_t)bl->sb_used + len > SBLOCKSIZE) {
// Allocate a block of memory. It is not freed until much later.
- bl = xcalloc(1, (sizeof(sblock_T) + SBLOCKSIZE));
+ bl = xcalloc(1, offsetof(sblock_T, sb_data) + SBLOCKSIZE + 1);
bl->sb_next = spin->si_blocks;
spin->si_blocks = bl;
bl->sb_used = 0;
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index 22add418a0..54b6f552b5 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -2828,7 +2828,7 @@ static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T
hi = hash_lookup(&slang->sl_sounddone, (const char *)goodword, goodword_len,
hash);
if (HASHITEM_EMPTY(hi)) {
- sft = xmalloc(sizeof(sftword_T) + goodword_len);
+ sft = xmalloc(offsetof(sftword_T, sft_word) + goodword_len + 1);
sft->sft_score = (int16_t)score;
memcpy(sft->sft_word, goodword, goodword_len + 1);
hash_add_item(&slang->sl_sounddone, hi, (char *)sft->sft_word, hash);
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 05c570e52f..49b63ad324 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -3736,7 +3736,7 @@ static void add_keyword(char *const name, const int id, const int flags,
sizeof(name_folded))
: name;
- keyentry_T *const kp = xmalloc(sizeof(keyentry_T) + strlen(name_ic));
+ keyentry_T *const kp = xmalloc(offsetof(keyentry_T, keyword) + strlen(name_ic) + 1);
STRCPY(kp->keyword, name_ic);
kp->k_syn.id = (int16_t)id;
kp->k_syn.inc_tag = current_syn_inc_tag;
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 197184c181..42618e8924 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -2732,55 +2732,57 @@ static int parse_match(char *lbuf, tagptrs_T *tagp)
tagp->tagline = 0;
tagp->command_end = NULL;
- if (retval == OK) {
- // Try to find a kind field: "kind:<kind>" or just "<kind>"
- p = tagp->command;
- if (find_extra(&p) == OK) {
- tagp->command_end = p;
- if (p > tagp->command && p[-1] == '|') {
- tagp->command_end = p - 1; // drop trailing bar
- }
- p += 2; // skip ";\""
- if (*p++ == TAB) {
- // Accept ASCII alphabetic kind characters and any multi-byte
- // character.
- while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) {
- if (strncmp(p, "kind:", 5) == 0) {
- tagp->tagkind = p + 5;
- } else if (strncmp(p, "user_data:", 10) == 0) {
- tagp->user_data = p + 10;
- } else if (strncmp(p, "line:", 5) == 0) {
- tagp->tagline = atoi(p + 5);
- }
- if (tagp->tagkind != NULL && tagp->user_data != NULL) {
- break;
- }
+ if (retval != OK) {
+ return retval;
+ }
- pc = vim_strchr(p, ':');
- pt = vim_strchr(p, '\t');
- if (pc == NULL || (pt != NULL && pc > pt)) {
- tagp->tagkind = p;
- }
- if (pt == NULL) {
- break;
- }
- p = pt;
- MB_PTR_ADV(p);
+ // Try to find a kind field: "kind:<kind>" or just "<kind>"
+ p = tagp->command;
+ if (find_extra(&p) == OK) {
+ tagp->command_end = p;
+ if (p > tagp->command && p[-1] == '|') {
+ tagp->command_end = p - 1; // drop trailing bar
+ }
+ p += 2; // skip ";\""
+ if (*p++ == TAB) {
+ // Accept ASCII alphabetic kind characters and any multi-byte
+ // character.
+ while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) {
+ if (strncmp(p, "kind:", 5) == 0) {
+ tagp->tagkind = p + 5;
+ } else if (strncmp(p, "user_data:", 10) == 0) {
+ tagp->user_data = p + 10;
+ } else if (strncmp(p, "line:", 5) == 0) {
+ tagp->tagline = atoi(p + 5);
}
+ if (tagp->tagkind != NULL && tagp->user_data != NULL) {
+ break;
+ }
+
+ pc = vim_strchr(p, ':');
+ pt = vim_strchr(p, '\t');
+ if (pc == NULL || (pt != NULL && pc > pt)) {
+ tagp->tagkind = p;
+ }
+ if (pt == NULL) {
+ break;
+ }
+ p = pt;
+ MB_PTR_ADV(p);
}
}
- if (tagp->tagkind != NULL) {
- for (p = tagp->tagkind;
- *p && *p != '\t' && *p != '\r' && *p != '\n';
- MB_PTR_ADV(p)) {}
- tagp->tagkind_end = p;
- }
- if (tagp->user_data != NULL) {
- for (p = tagp->user_data;
- *p && *p != '\t' && *p != '\r' && *p != '\n';
- MB_PTR_ADV(p)) {}
- tagp->user_data_end = p;
- }
+ }
+ if (tagp->tagkind != NULL) {
+ for (p = tagp->tagkind;
+ *p && *p != '\t' && *p != '\r' && *p != '\n';
+ MB_PTR_ADV(p)) {}
+ tagp->tagkind_end = p;
+ }
+ if (tagp->user_data != NULL) {
+ for (p = tagp->user_data;
+ *p && *p != '\t' && *p != '\r' && *p != '\n';
+ MB_PTR_ADV(p)) {}
+ tagp->user_data_end = p;
}
return retval;
}
@@ -3329,86 +3331,88 @@ int get_tags(list_T *list, char *pat, char *buf_fname)
ret = find_tags(pat, &num_matches, &matches,
TAG_REGEXP | TAG_NOIC, MAXCOL, buf_fname);
- if (ret == OK && num_matches > 0) {
- for (i = 0; i < num_matches; i++) {
- int parse_result = parse_match(matches[i], &tp);
+ if (ret != OK || num_matches <= 0) {
+ return ret;
+ }
- // Avoid an unused variable warning in release builds.
- (void)parse_result;
- assert(parse_result == OK);
+ for (i = 0; i < num_matches; i++) {
+ int parse_result = parse_match(matches[i], &tp);
- is_static = test_for_static(&tp);
+ // Avoid an unused variable warning in release builds.
+ (void)parse_result;
+ assert(parse_result == OK);
- // Skip pseudo-tag lines.
- if (strncmp(tp.tagname, "!_TAG_", 6) == 0) {
- xfree(matches[i]);
- continue;
- }
+ is_static = test_for_static(&tp);
+
+ // Skip pseudo-tag lines.
+ if (strncmp(tp.tagname, "!_TAG_", 6) == 0) {
+ xfree(matches[i]);
+ continue;
+ }
- dict = tv_dict_alloc();
- tv_list_append_dict(list, dict);
-
- full_fname = tag_full_fname(&tp);
- if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL
- || add_tag_field(dict, "filename", full_fname, NULL) == FAIL
- || add_tag_field(dict, "cmd", tp.command, tp.command_end) == FAIL
- || add_tag_field(dict, "kind", tp.tagkind,
- tp.tagkind ? tp.tagkind_end : NULL) == FAIL
- || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) {
- ret = FAIL;
- }
-
- xfree(full_fname);
-
- if (tp.command_end != NULL) {
- for (char *p = tp.command_end + 3;
- *p != NUL && *p != '\n' && *p != '\r';
- MB_PTR_ADV(p)) {
- if (p == tp.tagkind
- || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) {
- // skip "kind:<kind>" and "<kind>"
- p = tp.tagkind_end - 1;
- } else if (strncmp(p, "file:", 5) == 0) {
- // skip "file:" (static tag)
- p += 4;
- } else if (!ascii_iswhite(*p)) {
- char *s, *n;
- int len;
-
- // Add extra field as a dict entry. Fields are
- // separated by Tabs.
- n = p;
- while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') {
+ dict = tv_dict_alloc();
+ tv_list_append_dict(list, dict);
+
+ full_fname = tag_full_fname(&tp);
+ if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL
+ || add_tag_field(dict, "filename", full_fname, NULL) == FAIL
+ || add_tag_field(dict, "cmd", tp.command, tp.command_end) == FAIL
+ || add_tag_field(dict, "kind", tp.tagkind,
+ tp.tagkind ? tp.tagkind_end : NULL) == FAIL
+ || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) {
+ ret = FAIL;
+ }
+
+ xfree(full_fname);
+
+ if (tp.command_end != NULL) {
+ for (char *p = tp.command_end + 3;
+ *p != NUL && *p != '\n' && *p != '\r';
+ MB_PTR_ADV(p)) {
+ if (p == tp.tagkind
+ || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) {
+ // skip "kind:<kind>" and "<kind>"
+ p = tp.tagkind_end - 1;
+ } else if (strncmp(p, "file:", 5) == 0) {
+ // skip "file:" (static tag)
+ p += 4;
+ } else if (!ascii_iswhite(*p)) {
+ char *s, *n;
+ int len;
+
+ // Add extra field as a dict entry. Fields are
+ // separated by Tabs.
+ n = p;
+ while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') {
+ p++;
+ }
+ len = (int)(p - n);
+ if (*p == ':' && len > 0) {
+ s = ++p;
+ while (*p != NUL && (uint8_t)(*p) >= ' ') {
p++;
}
- len = (int)(p - n);
- if (*p == ':' && len > 0) {
- s = ++p;
- while (*p != NUL && (uint8_t)(*p) >= ' ') {
- p++;
- }
- n[len] = NUL;
- if (add_tag_field(dict, n, s, p) == FAIL) {
- ret = FAIL;
- }
- n[len] = ':';
- } else {
- // Skip field without colon.
- while (*p != NUL && (uint8_t)(*p) >= ' ') {
- p++;
- }
+ n[len] = NUL;
+ if (add_tag_field(dict, n, s, p) == FAIL) {
+ ret = FAIL;
}
- if (*p == NUL) {
- break;
+ n[len] = ':';
+ } else {
+ // Skip field without colon.
+ while (*p != NUL && (uint8_t)(*p) >= ' ') {
+ p++;
}
}
+ if (*p == NUL) {
+ break;
+ }
}
}
-
- xfree(matches[i]);
}
- xfree(matches);
+
+ xfree(matches[i]);
}
+ xfree(matches);
return ret;
}
diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh
index 322265737a..3a0a94b6bf 100755
--- a/src/nvim/testdir/runnvim.sh
+++ b/src/nvim/testdir/runnvim.sh
@@ -30,6 +30,9 @@ main() {(
. "$CI_DIR/common/suite.sh"
. "$CI_DIR/common/test.sh"
+ # Redirect XDG_CONFIG_HOME so users local config doesn't interfere
+ export XDG_CONFIG_HOME="$root"
+
export VIMRUNTIME="$root/runtime"
if ! "$nvim_prg" \
-u NONE -i NONE \
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index fd54f77ccb..89a9179e60 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -336,8 +336,23 @@ func Test_edit_11_indentexpr()
endfunc
set indentexpr=s:NewIndentExpr()
call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr)
set indentexpr=<SID>NewIndentExpr()
call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr)
+ setlocal indentexpr=
+ setglobal indentexpr=s:NewIndentExpr()
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr)
+ call assert_equal('', &indentexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ bw!
+ setglobal indentexpr=<SID>NewIndentExpr()
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr)
+ call assert_equal('', &indentexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ bw!
set indentexpr&
bw!
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index cddb1349f5..7b5ec22dd4 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -123,7 +123,7 @@ let s:filename_checks = {
\ 'conaryrecipe': ['file.recipe'],
\ 'conf': ['auto.master'],
\ 'config': ['configure.in', 'configure.ac', '/etc/hostname.file', 'any/etc/hostname.file'],
- \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials'],
+ \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials', 'file.nmconnection'],
\ 'context': ['tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi', 'file.mkxl', 'file.mklx'],
\ 'cook': ['file.cook'],
\ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'],
@@ -181,6 +181,7 @@ let s:filename_checks = {
\ 'elixir': ['file.ex', 'file.exs', 'mix.lock'],
\ 'elm': ['file.elm'],
\ 'elmfilt': ['filter-rules'],
+ \ 'elsa': ['file.lc'],
\ 'elvish': ['file.elv'],
\ 'epuppet': ['file.epp'],
\ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'],
@@ -198,6 +199,7 @@ let s:filename_checks = {
\ 'fennel': ['file.fnl'],
\ 'fetchmail': ['.fetchmailrc'],
\ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'],
+ \ 'firrtl': ['file.fir'],
\ 'fish': ['file.fish'],
\ 'focexec': ['file.fex', 'file.focexec'],
\ 'form': ['file.frm'],
@@ -294,13 +296,14 @@ let s:filename_checks = {
\ 'jq': ['file.jq'],
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file', 'org.eclipse.xyz.prefs'],
- \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.prettierrc', '.firebaserc', 'file.slnf'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.prettierrc', '.firebaserc', '.stylelintrc', 'file.slnf'],
\ 'json5': ['file.json5'],
\ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json'],
\ 'jsonnet': ['file.jsonnet', 'file.libsonnet'],
\ 'jsp': ['file.jsp'],
\ 'julia': ['file.jl'],
\ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'],
+ \ 'kdl': ['file.kdl'],
\ 'kivy': ['file.kv'],
\ 'kix': ['file.kix'],
\ 'kotlin': ['file.kt', 'file.ktm', 'file.kts'],
@@ -655,7 +658,7 @@ let s:filename_checks = {
\ 'xsd': ['file.xsd'],
\ 'xslt': ['file.xsl', 'file.xslt'],
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
- \ 'yaml': ['file.yaml', 'file.yml', '.clang-format', '.clang-tidy'],
+ \ 'yaml': ['file.yaml', 'file.yml', '.clangd', '.clang-format', '.clang-tidy'],
\ 'yang': ['file.yang'],
\ 'z8a': ['file.z8a'],
\ 'zig': ['file.zig'],
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 19415286ad..9014948fb4 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -1305,6 +1305,7 @@ func Test_foldexpr_scriptlocal_func()
set foldmethod=expr foldexpr=s:FoldFunc()
redraw!
call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr)
call assert_equal(1, g:FoldLnum)
set foldmethod& foldexpr=
bw!
@@ -1314,8 +1315,31 @@ func Test_foldexpr_scriptlocal_func()
set foldmethod=expr foldexpr=<SID>FoldFunc()
redraw!
call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr)
call assert_equal(1, g:FoldLnum)
- set foldmethod& foldexpr=
+ bw!
+ call setline(1, 'abc')
+ setlocal foldmethod& foldexpr&
+ setglobal foldmethod=expr foldexpr=s:FoldFunc()
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr)
+ call assert_equal('0', &foldexpr)
+ enew!
+ call setline(1, 'abc')
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(1, g:FoldLnum)
+ bw!
+ call setline(1, 'abc')
+ setlocal foldmethod& foldexpr&
+ setglobal foldmethod=expr foldexpr=<SID>FoldFunc()
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr)
+ call assert_equal('0', &foldexpr)
+ enew!
+ call setline(1, 'abc')
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(1, g:FoldLnum)
+ set foldmethod& foldexpr&
delfunc s:FoldFunc
bw!
endfunc
@@ -1329,25 +1353,53 @@ func Test_foldtext_scriptlocal_func()
new | only
call setline(1, range(50))
let g:FoldTextArgs = []
- set foldmethod=manual
set foldtext=s:FoldText()
norm! 4Gzf4j
redraw!
call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext)
call assert_equal([4, 8], g:FoldTextArgs)
set foldtext&
bw!
new | only
call setline(1, range(50))
let g:FoldTextArgs = []
- set foldmethod=manual
set foldtext=<SID>FoldText()
norm! 8Gzf4j
redraw!
call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext)
call assert_equal([8, 12], g:FoldTextArgs)
set foldtext&
bw!
+ call setline(1, range(50))
+ let g:FoldTextArgs = []
+ setlocal foldtext&
+ setglobal foldtext=s:FoldText()
+ call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext)
+ call assert_equal('foldtext()', &foldtext)
+ enew!
+ call setline(1, range(50))
+ norm! 12Gzf4j
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal([12, 16], g:FoldTextArgs)
+ set foldtext&
+ bw!
+ call setline(1, range(50))
+ let g:FoldTextArgs = []
+ setlocal foldtext&
+ setglobal foldtext=<SID>FoldText()
+ call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext)
+ call assert_equal('foldtext()', &foldtext)
+ enew!
+ call setline(1, range(50))
+ norm! 16Gzf4j
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal([16, 20], g:FoldTextArgs)
+ set foldtext&
+ bw!
delfunc s:FoldText
endfunc
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index e369645328..f09dbd72ce 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -234,6 +234,7 @@ func Test_includeexpr_scriptlocal_func()
endfunc
set includeexpr=s:IncludeFunc()
call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr)
new | only
call setline(1, 'TestFile1')
let g:IncludeFname = ''
@@ -242,11 +243,35 @@ func Test_includeexpr_scriptlocal_func()
bw!
set includeexpr=<SID>IncludeFunc()
call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr)
new | only
call setline(1, 'TestFile2')
let g:IncludeFname = ''
call assert_fails('normal! gf', 'E447:')
call assert_equal('TestFile2', g:IncludeFname)
+ bw!
+ setlocal includeexpr=
+ setglobal includeexpr=s:IncludeFunc()
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr)
+ call assert_equal('', &includeexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ call setline(1, 'TestFile3')
+ let g:IncludeFname = ''
+ call assert_fails('normal! gf', 'E447:')
+ call assert_equal('TestFile3', g:IncludeFname)
+ bw!
+ setlocal includeexpr=
+ setglobal includeexpr=<SID>IncludeFunc()
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr)
+ call assert_equal('', &includeexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ call setline(1, 'TestFile4')
+ let g:IncludeFname = ''
+ call assert_fails('normal! gf', 'E447:')
+ call assert_equal('TestFile4', g:IncludeFname)
+ bw!
set includeexpr&
delfunc s:IncludeFunc
bw!
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 7c90b444e5..2aaa1ff830 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -262,6 +262,7 @@ func Test_formatexpr_scriptlocal_func()
endfunc
set formatexpr=s:Format()
call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
new | only
call setline(1, range(1, 40))
let g:FormatArgs = []
@@ -270,6 +271,7 @@ func Test_formatexpr_scriptlocal_func()
bw!
set formatexpr=<SID>Format()
call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
new | only
call setline(1, range(1, 40))
let g:FormatArgs = []
@@ -277,6 +279,7 @@ func Test_formatexpr_scriptlocal_func()
call assert_equal([4, 2], g:FormatArgs)
bw!
let &formatexpr = 's:Format()'
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
new | only
call setline(1, range(1, 40))
let g:FormatArgs = []
@@ -284,12 +287,55 @@ func Test_formatexpr_scriptlocal_func()
call assert_equal([6, 2], g:FormatArgs)
bw!
let &formatexpr = '<SID>Format()'
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
new | only
call setline(1, range(1, 40))
let g:FormatArgs = []
normal! 8GVjgq
call assert_equal([8, 2], g:FormatArgs)
+ bw!
setlocal formatexpr=
+ setglobal formatexpr=s:Format()
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
+ call assert_equal('', &formatexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 10GVjgq
+ call assert_equal([10, 2], g:FormatArgs)
+ bw!
+ setglobal formatexpr=<SID>Format()
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
+ call assert_equal('', &formatexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 12GVjgq
+ call assert_equal([12, 2], g:FormatArgs)
+ bw!
+ let &g:formatexpr = 's:Format()'
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
+ call assert_equal('', &formatexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 14GVjgq
+ call assert_equal([14, 2], g:FormatArgs)
+ bw!
+ let &g:formatexpr = '<SID>Format()'
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
+ call assert_equal('', &formatexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 16GVjgq
+ call assert_equal([16, 2], g:FormatArgs)
+ bw!
+ set formatexpr=
delfunc s:Format
bw!
endfunc
diff --git a/src/nvim/testdir/test_packadd.vim b/src/nvim/testdir/test_packadd.vim
index fcb8b8033b..3121b3b4d1 100644
--- a/src/nvim/testdir/test_packadd.vim
+++ b/src/nvim/testdir/test_packadd.vim
@@ -26,7 +26,7 @@ func Test_packadd()
let rtp_entries = split(rtp, ',')
for entry in rtp_entries
- if entry =~? '\<after\>'
+ if entry =~? '\<after\>'
let first_after_entry = entry
break
endif
@@ -186,15 +186,17 @@ func Test_packadd_symlink_dir2()
exec "silent !rmdir" top2_dir
endfunc
-" Check command-line completion for 'packadd'
+" Check command-line completion for :packadd
func Test_packadd_completion()
let optdir1 = &packpath . '/pack/mine/opt'
let optdir2 = &packpath . '/pack/candidate/opt'
call mkdir(optdir1 . '/pluginA', 'p')
call mkdir(optdir1 . '/pluginC', 'p')
+ call writefile([], optdir1 . '/unrelated')
call mkdir(optdir2 . '/pluginB', 'p')
call mkdir(optdir2 . '/pluginC', 'p')
+ call writefile([], optdir2 . '/unrelated')
let li = []
call feedkeys(":packadd \<Tab>')\<C-B>call add(li, '\<CR>", 't')
@@ -260,9 +262,9 @@ func Test_helptags()
helptags ALL
- let tags1 = readfile(docdir1 . '/tags')
+ let tags1 = readfile(docdir1 . '/tags')
call assert_match('look-here', tags1[0])
- let tags2 = readfile(docdir2 . '/tags')
+ let tags2 = readfile(docdir2 . '/tags')
call assert_match('look-away', tags2[0])
call assert_fails('helptags abcxyz', 'E150:')
@@ -358,4 +360,78 @@ func Test_runtime()
call assert_equal('runstartopt', g:sequence)
endfunc
+func Test_runtime_completion()
+ let rundir = &packpath . '/runtime/Aextra'
+ let startdir = &packpath . '/pack/mine/start/foo/Aextra'
+ let optdir = &packpath . '/pack/mine/opt/bar/Aextra'
+ call mkdir(rundir . '/Arunbaz', 'p')
+ call mkdir(startdir . '/Astartbaz', 'p')
+ call mkdir(optdir . '/Aoptbaz', 'p')
+ call writefile([], rundir . '/../Arunfoo.vim')
+ call writefile([], rundir . '/Arunbar.vim')
+ call writefile([], rundir . '/Aunrelated')
+ call writefile([], rundir . '/../Aunrelated')
+ call writefile([], startdir . '/../Astartfoo.vim')
+ call writefile([], startdir . '/Astartbar.vim')
+ call writefile([], startdir . '/Aunrelated')
+ call writefile([], startdir . '/../Aunrelated')
+ call writefile([], optdir . '/../Aoptfoo.vim')
+ call writefile([], optdir . '/Aoptbar.vim')
+ call writefile([], optdir . '/Aunrelated')
+ call writefile([], optdir . '/../Aunrelated')
+ exe 'set rtp=' . &packpath . '/runtime'
+
+ func Check_runtime_completion(arg, arg1, res)
+ call feedkeys(':runtime ' .. a:arg .. "\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"runtime ' .. a:arg1 .. join(a:res), @:)
+ call assert_equal(a:res, getcompletion(a:arg, 'runtime'))
+ endfunc
+
+ call Check_runtime_completion('', '',
+ \ ['Aextra/', 'Arunfoo.vim', 'START', 'OPT', 'PACK', 'ALL'])
+ call Check_runtime_completion('S', '',
+ \ ['START'])
+ call Check_runtime_completion('O', '',
+ \ ['OPT'])
+ call Check_runtime_completion('P', '',
+ \ ['PACK'])
+ call Check_runtime_completion('A', '',
+ \ ['Aextra/', 'Arunfoo.vim', 'ALL'])
+ call Check_runtime_completion('Aextra/', '',
+ \ ['Aextra/Arunbar.vim', 'Aextra/Arunbaz/'])
+
+ call Check_runtime_completion('START ', 'START ',
+ \ ['Aextra/', 'Astartfoo.vim'])
+ call Check_runtime_completion('START A', 'START ',
+ \ ['Aextra/', 'Astartfoo.vim'])
+ call Check_runtime_completion('START Aextra/', 'START ',
+ \ ['Aextra/Astartbar.vim', 'Aextra/Astartbaz/'])
+
+ call Check_runtime_completion('OPT ', 'OPT ',
+ \ ['Aextra/', 'Aoptfoo.vim'])
+ call Check_runtime_completion('OPT A', 'OPT ',
+ \ ['Aextra/', 'Aoptfoo.vim'])
+ call Check_runtime_completion('OPT Aextra/', 'OPT ',
+ \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/'])
+
+ call Check_runtime_completion('PACK ', 'PACK ',
+ \ ['Aextra/', 'Aoptfoo.vim', 'Astartfoo.vim'])
+ call Check_runtime_completion('PACK A', 'PACK ',
+ \ ['Aextra/', 'Aoptfoo.vim', 'Astartfoo.vim'])
+ call Check_runtime_completion('PACK Aextra/', 'PACK ',
+ \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/',
+ \ 'Aextra/Astartbar.vim', 'Aextra/Astartbaz/'])
+
+ call Check_runtime_completion('ALL ', 'ALL ',
+ \ ['Aextra/', 'Aoptfoo.vim', 'Arunfoo.vim', 'Astartfoo.vim'])
+ call Check_runtime_completion('ALL A', 'ALL ',
+ \ ['Aextra/', 'Aoptfoo.vim', 'Arunfoo.vim', 'Astartfoo.vim'])
+ call Check_runtime_completion('ALL Aextra/', 'ALL ',
+ \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/',
+ \ 'Aextra/Arunbar.vim', 'Aextra/Arunbaz/',
+ \ 'Aextra/Astartbar.vim', 'Aextra/Astartbaz/'])
+
+ delfunc Check_runtime_completion
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim
index 77bd50ada2..1b2d854829 100644
--- a/src/nvim/testdir/test_search_stat.vim
+++ b/src/nvim/testdir/test_search_stat.vim
@@ -270,6 +270,29 @@ func Test_searchcount_fails()
call assert_fails('echo searchcount({"pos" : [1, 2, []]})', 'E745:')
endfunc
+func Test_search_stat_narrow_screen()
+ " This used to crash Vim
+ let save_columns = &columns
+ try
+ let after =<< trim [CODE]
+ set laststatus=2
+ set columns=16
+ set shortmess-=S showcmd
+ call setline(1, 'abc')
+ call feedkeys("/abc\<CR>:quit!\<CR>")
+ autocmd VimLeavePre * call writefile(["done"], "Xdone")
+ [CODE]
+
+ if !RunVim([], after, '--clean')
+ return
+ endif
+ call assert_equal("done", readfile("Xdone")[0])
+ call delete('Xdone')
+ finally
+ let &columns = save_columns
+ endtry
+endfunc
+
func Test_searchcount_in_statusline()
CheckScreendump
diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim
index 0387ef2bd8..75d28c3ec4 100644
--- a/src/nvim/testdir/test_taglist.vim
+++ b/src/nvim/testdir/test_taglist.vim
@@ -105,8 +105,8 @@ func Test_tagfiles()
help
let tf = tagfiles()
" Nvim: expectation(s) based on tags in build dir (added to &rtp).
- " Filter out the (non-existing) '../../../runtime/doc/tags'.
- call filter(tf, 'filereadable(v:val)')
+ " Filter out the '../../../runtime/doc/tags'.
+ call filter(tf, 'v:val != "../../../runtime/doc/tags"')
call assert_equal(1, len(tf))
call assert_equal(fnamemodify(expand('$BUILD_DIR/runtime/doc/tags'), ':p:gs?\\?/?'),
\ fnamemodify(tf[0], ':p:gs?\\?/?'))
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
index 2bf8c3fc77..20a5f87517 100644
--- a/src/nvim/testdir/test_virtualedit.vim
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -537,6 +537,19 @@ func Test_global_local_virtualedit()
set virtualedit&
endfunc
+func Test_virtualedit_setlocal()
+ enew
+ setglobal virtualedit=all
+ setlocal virtualedit=all
+ normal! l
+ redraw
+ setlocal virtualedit=none
+ call assert_equal(1, wincol())
+
+ setlocal virtualedit&
+ set virtualedit&
+endfunc
+
func Test_virtualedit_mouse()
let save_mouse = &mouse
set mouse=a
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 14d62089cf..1e9629c2c4 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -1319,6 +1319,17 @@ func Test_visual_block_with_substitute()
endfunc
func Test_visual_reselect_with_count()
+ enew
+ call setline(1, ['aaaaaa', '✗ bbbb', '✗ bbbb'])
+ exe "normal! 2Gw\<C-V>jed"
+ exe "normal! gg0lP"
+ call assert_equal(['abbbbaaaaa', '✗bbbb ', '✗ '], getline(1, '$'))
+
+ exe "normal! 1vr."
+ call assert_equal(['a....aaaaa', '✗.... ', '✗ '], getline(1, '$'))
+
+ bwipe!
+
" this was causing an illegal memory access
let lines =<< trim END
diff --git a/src/nvim/testing.c b/src/nvim/testing.c
index edf92c78ac..b5921b3445 100644
--- a/src/nvim/testing.c
+++ b/src/nvim/testing.c
@@ -77,31 +77,32 @@ static void ga_concat_esc(garray_T *gap, const char *p, int clen)
memmove(buf, p, (size_t)clen);
buf[clen] = NUL;
ga_concat(gap, buf);
- } else {
- switch (*p) {
- case BS:
- ga_concat(gap, "\\b"); break;
- case ESC:
- ga_concat(gap, "\\e"); break;
- case FF:
- ga_concat(gap, "\\f"); break;
- case NL:
- ga_concat(gap, "\\n"); break;
- case TAB:
- ga_concat(gap, "\\t"); break;
- case CAR:
- ga_concat(gap, "\\r"); break;
- case '\\':
- ga_concat(gap, "\\\\"); break;
- default:
- if ((uint8_t)(*p) < ' ' || *p == 0x7f) {
- vim_snprintf(buf, NUMBUFLEN, "\\x%02x", *p);
- ga_concat(gap, buf);
- } else {
- ga_append(gap, (uint8_t)(*p));
- }
- break;
+ return;
+ }
+
+ switch (*p) {
+ case BS:
+ ga_concat(gap, "\\b"); break;
+ case ESC:
+ ga_concat(gap, "\\e"); break;
+ case FF:
+ ga_concat(gap, "\\f"); break;
+ case NL:
+ ga_concat(gap, "\\n"); break;
+ case TAB:
+ ga_concat(gap, "\\t"); break;
+ case CAR:
+ ga_concat(gap, "\\r"); break;
+ case '\\':
+ ga_concat(gap, "\\\\"); break;
+ default:
+ if ((uint8_t)(*p) < ' ' || *p == 0x7f) {
+ vim_snprintf(buf, NUMBUFLEN, "\\x%02x", *p);
+ ga_concat(gap, buf);
+ } else {
+ ga_append(gap, (uint8_t)(*p));
}
+ break;
}
}
diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c
index fbea1ccfb7..e30580a748 100644
--- a/src/nvim/textformat.c
+++ b/src/nvim/textformat.c
@@ -736,22 +736,24 @@ void check_auto_format(bool end_insert)
int c = ' ';
int cc;
- if (did_add_space) {
- cc = gchar_cursor();
- if (!WHITECHAR(cc)) {
- // Somehow the space was removed already.
+ if (!did_add_space) {
+ return;
+ }
+
+ cc = gchar_cursor();
+ if (!WHITECHAR(cc)) {
+ // Somehow the space was removed already.
+ did_add_space = false;
+ } else {
+ if (!end_insert) {
+ inc_cursor();
+ c = gchar_cursor();
+ dec_cursor();
+ }
+ if (c != NUL) {
+ // The space is no longer at the end of the line, delete it.
+ del_char(false);
did_add_space = false;
- } else {
- if (!end_insert) {
- inc_cursor();
- c = gchar_cursor();
- dec_cursor();
- }
- if (c != NUL) {
- // The space is no longer at the end of the line, delete it.
- del_char(false);
- did_add_space = false;
- }
}
}
}
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 2cb39ab26b..733aa25f03 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -117,14 +117,6 @@ static const struct kitty_key_map_entry {
static Map(KittyKey, cstr_t) kitty_key_map = MAP_INIT;
-#ifndef UNIT_TESTING
-typedef enum {
- kIncomplete = -1,
- kNotApplicable = 0,
- kComplete = 1,
-} HandleState;
-#endif
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/input.c.generated.h"
#endif
@@ -584,7 +576,7 @@ static void set_bg(char *bgvalue)
// ignored in the calculations.
//
// [1] https://en.wikipedia.org/wiki/Luma_%28video%29
-static HandleState handle_background_color(TermInput *input)
+HandleState handle_background_color(TermInput *input)
{
if (input->waiting_for_bg_response <= 0) {
return kNotApplicable;
@@ -669,12 +661,6 @@ static HandleState handle_background_color(TermInput *input)
}
return kComplete;
}
-#ifdef UNIT_TESTING
-HandleState ut_handle_background_color(TermInput *input)
-{
- return handle_background_color(input);
-}
-#endif
static void handle_raw_buffer(TermInput *input, bool force)
{
diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h
index 5df108b107..d33cea6383 100644
--- a/src/nvim/tui/input.h
+++ b/src/nvim/tui/input.h
@@ -40,18 +40,14 @@ typedef struct term_input {
TUIData *tui_data;
} TermInput;
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "tui/input.h.generated.h"
-#endif
-
-#ifdef UNIT_TESTING
typedef enum {
kIncomplete = -1,
kNotApplicable = 0,
kComplete = 1,
} HandleState;
-HandleState ut_handle_background_color(TermInput *input);
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "tui/input.h.generated.h"
#endif
#endif // NVIM_TUI_INPUT_H
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index a50e44f7a3..f760e99262 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -458,6 +458,9 @@ static void tui_terminal_stop(TUIData *tui)
void tui_stop(TUIData *tui)
{
+ if (tui->stopped) {
+ return;
+ }
tui_terminal_stop(tui);
stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598)
tinput_destroy(&tui->input);
@@ -1344,6 +1347,7 @@ static void show_verbose_terminfo(TUIData *tui)
static void suspend_event(void **argv)
{
TUIData *tui = argv[0];
+ ui_client_detach();
bool enable_mouse = tui->mouse_enabled;
tui_terminal_stop(tui);
stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598)
@@ -1356,6 +1360,7 @@ static void suspend_event(void **argv)
tui_mouse_on(tui);
}
stream_set_blocking(tui->input.in_fd, false); // libuv expects this
+ ui_client_attach(tui->width, tui->height, tui->term);
}
#endif
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index 378c0e4831..b5c8dff412 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -23,6 +23,7 @@
#include "nvim/ui_client.h"
static TUIData *tui = NULL;
+static bool ui_client_is_remote = false;
// uncrustify:off
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -66,13 +67,8 @@ uint64_t ui_client_start_server(int argc, char **argv)
return channel->id;
}
-void ui_client_run(bool remote_ui)
- FUNC_ATTR_NORETURN
+void ui_client_attach(int width, int height, char *term)
{
- int width, height;
- char *term;
- tui = tui_start(&width, &height, &term);
-
MAXSIZE_TEMP_ARRAY(args, 3);
ADD_C(args, INTEGER_OBJ(width));
ADD_C(args, INTEGER_OBJ(height));
@@ -82,14 +78,14 @@ void ui_client_run(bool remote_ui)
PUT_C(opts, "ext_linegrid", BOOLEAN_OBJ(true));
PUT_C(opts, "ext_termcolors", BOOLEAN_OBJ(true));
if (term) {
- PUT(opts, "term_name", STRING_OBJ(cstr_to_string(term)));
+ PUT_C(opts, "term_name", STRING_OBJ(cstr_as_string(term)));
}
if (ui_client_bg_response != kNone) {
bool is_dark = (ui_client_bg_response == kTrue);
PUT_C(opts, "term_background", STRING_OBJ(cstr_as_string(is_dark ? "dark" : "light")));
}
PUT_C(opts, "term_colors", INTEGER_OBJ(t_colors));
- if (!remote_ui) {
+ if (!ui_client_is_remote) {
PUT_C(opts, "stdin_tty", BOOLEAN_OBJ(stdin_isatty));
PUT_C(opts, "stdout_tty", BOOLEAN_OBJ(stdout_isatty));
if (ui_client_forward_stdin) {
@@ -100,6 +96,23 @@ void ui_client_run(bool remote_ui)
rpc_send_event(ui_client_channel_id, "nvim_ui_attach", args);
ui_client_attached = true;
+}
+
+void ui_client_detach(void)
+{
+ rpc_send_event(ui_client_channel_id, "nvim_ui_detach", (Array)ARRAY_DICT_INIT);
+ ui_client_attached = false;
+}
+
+void ui_client_run(bool remote_ui)
+ FUNC_ATTR_NORETURN
+{
+ ui_client_is_remote = remote_ui;
+ int width, height;
+ char *term;
+ tui = tui_start(&width, &height, &term);
+
+ ui_client_attach(width, height, term);
// 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 2b0bb1d243..0f12c00f15 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2985,10 +2985,12 @@ void u_saveline(linenr_T lnum)
/// (this is used externally for crossing a line while in insert mode)
void u_clearline(void)
{
- if (curbuf->b_u_line_ptr != NULL) {
- XFREE_CLEAR(curbuf->b_u_line_ptr);
- curbuf->b_u_line_lnum = 0;
+ if (curbuf->b_u_line_ptr == NULL) {
+ return;
}
+
+ XFREE_CLEAR(curbuf->b_u_line_ptr);
+ curbuf->b_u_line_lnum = 0;
}
/// Implementation of the "U" command.
diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c
index 31cb1e8936..ef13f67e49 100644
--- a/src/nvim/usercmd.c
+++ b/src/nvim/usercmd.c
@@ -89,6 +89,7 @@ static const char *command_complete[] = {
[EXPAND_SYNTIME] = "syntime",
[EXPAND_SETTINGS] = "option",
[EXPAND_PACKADD] = "packadd",
+ [EXPAND_RUNTIME] = "runtime",
[EXPAND_SHELLCMD] = "shellcmd",
[EXPAND_SIGN] = "sign",
[EXPAND_TAGS] = "tag",
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 417e5116a5..3324ac2a94 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -795,7 +795,7 @@ static const int included_patches[] = {
1702,
1701,
// 1700,
- // 1699,
+ 1699,
1698,
1697,
1696,
@@ -1361,7 +1361,7 @@ static const int included_patches[] = {
// 1136,
1135,
1134,
- // 1133,
+ 1133,
1132,
1131,
1130,
@@ -1674,7 +1674,7 @@ static const int included_patches[] = {
823,
822,
821,
- // 820,
+ 820,
819,
818,
817,
@@ -2785,13 +2785,6 @@ void maybe_intro_message(void)
/// @param colon true for ":intro"
void intro_message(int colon)
{
- int i;
- long row;
- long blanklines;
- int sponsor;
- char *p;
- char *mesg;
- int mesg_size;
static char *(lines[]) = {
N_(NVIM_VERSION_LONG),
"",
@@ -2813,7 +2806,7 @@ void intro_message(int colon)
size_t lines_size = ARRAY_SIZE(lines);
assert(lines_size <= LONG_MAX);
- blanklines = Rows - ((long)lines_size - 1L);
+ long blanklines = Rows - ((long)lines_size - 1L);
// Don't overwrite a statusline. Depends on 'cmdheight'.
if (p_ls > 1) {
@@ -2826,17 +2819,17 @@ void intro_message(int colon)
// Show the sponsor and register message one out of four times, the Uganda
// message two out of four times.
- sponsor = (int)time(NULL);
+ int sponsor = (int)time(NULL);
sponsor = ((sponsor & 2) == 0) - ((sponsor & 4) == 0);
// start displaying the message lines after half of the blank lines
- row = blanklines / 2;
+ long row = blanklines / 2;
if (((row >= 2) && (Columns >= 50)) || colon) {
- for (i = 0; i < (int)ARRAY_SIZE(lines); i++) {
- p = lines[i];
- mesg = NULL;
- mesg_size = 0;
+ for (int i = 0; i < (int)ARRAY_SIZE(lines); i++) {
+ char *p = lines[i];
+ char *mesg = NULL;
+ int mesg_size = 0;
if (strstr(p, "news") != NULL) {
p = _(p);
@@ -2846,18 +2839,15 @@ void intro_message(int colon)
mesg = xmallocz((size_t)mesg_size);
snprintf(mesg, (size_t)mesg_size + 1, p,
STR(NVIM_VERSION_MAJOR), STR(NVIM_VERSION_MINOR));
- }
-
- if (sponsor != 0) {
+ } else if (sponsor != 0) {
if (strstr(p, "children") != NULL) {
- mesg = sponsor < 0
- ? _("Sponsor Vim development!")
- : _("Become a registered Vim user!");
- }
- if (strstr(p, "iccf") != NULL) {
- mesg = sponsor < 0
- ? _("type :help sponsor<Enter> for information ")
- : _("type :help register<Enter> for information ");
+ p = sponsor < 0
+ ? N_("Sponsor Vim development!")
+ : N_("Become a registered Vim user!");
+ } else if (strstr(p, "iccf") != NULL) {
+ p = sponsor < 0
+ ? N_("type :help sponsor<Enter> for information ")
+ : N_("type :help register<Enter> for information ");
}
}
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index c4baa911f1..3c765f8eb2 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -156,6 +156,7 @@ enum {
EXPAND_DIFF_BUFFERS,
EXPAND_BREAKPOINT,
EXPAND_SCRIPTNAMES,
+ EXPAND_RUNTIME,
EXPAND_CHECKHEALTH,
EXPAND_LUA,
};
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 16405f87b6..4448b72ac0 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -2599,6 +2599,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
if (!ONE_WINDOW) {
return false;
}
+
buf_T *old_curbuf = curbuf;
Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL;
@@ -4144,12 +4145,13 @@ int may_open_tabpage(void)
{
int n = (cmdmod.cmod_tab == 0) ? postponed_split_tab : cmdmod.cmod_tab;
- if (n != 0) {
- cmdmod.cmod_tab = 0; // reset it to avoid doing it twice
- postponed_split_tab = 0;
- return win_new_tabpage(n, NULL);
+ if (n == 0) {
+ return FAIL;
}
- return FAIL;
+
+ cmdmod.cmod_tab = 0; // reset it to avoid doing it twice
+ postponed_split_tab = 0;
+ return win_new_tabpage(n, NULL);
}
// Create up to "maxcount" tabpages with empty windows.
@@ -4494,11 +4496,12 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le
/// @return true if the tab page is valid, false otherwise.
bool goto_tabpage_lastused(void)
{
- if (valid_tabpage(lastused_tabpage)) {
- goto_tabpage_tp(lastused_tabpage, true, true);
- return true;
+ if (!valid_tabpage(lastused_tabpage)) {
+ return false;
}
- return false;
+
+ goto_tabpage_tp(lastused_tabpage, true, true);
+ return true;
}
// Enter window "wp" in tab page "tp".
@@ -7261,11 +7264,12 @@ static void clear_snapshot(tabpage_T *tp, int idx)
static void clear_snapshot_rec(frame_T *fr)
{
- if (fr != NULL) {
- clear_snapshot_rec(fr->fr_next);
- clear_snapshot_rec(fr->fr_child);
- xfree(fr);
+ if (fr == NULL) {
+ return;
}
+ clear_snapshot_rec(fr->fr_next);
+ clear_snapshot_rec(fr->fr_child);
+ xfree(fr);
}
/// Traverse a snapshot to find the previous curwin.