diff options
26 files changed, 251 insertions, 84 deletions
diff --git a/MAINTAIN.md b/MAINTAIN.md index d65337f92b..a587425f57 100644 --- a/MAINTAIN.md +++ b/MAINTAIN.md @@ -98,6 +98,36 @@ These dependencies are "vendored" (inlined), we must update the sources manually We may maintain forks, if we are waiting on upstream changes: https://github.com/neovim/neovim/wiki/Deps +CI +-------------- + +### General + +As our CI is primarily dependent on GitHub Actions at the moment, then so will +our CI strategy be. The following guidelines have worked well for us so far: + +* Never use a macOS runner if an Ubuntu or a Windows runner can be used + instead. This is because macOS runners have a [tighter restrictions on the + number of concurrent jobs](https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits). + +### Runner versions + +* For special-purpose jobs where the runner version doesn't really matter, + prefer `-latest` tags so we don't need to manually bump the versions. An + example of a special-purpose workflow is `labeler.yml`. + +* For our testing jobs, which is currently only `ci.yml`, prefer to use the + latest stable (i.e. non-beta) version explicitly. Avoid using the `-latest` + tags here as it makes it difficult to determine from an unrelated PR if a + failure is due to the PR itself or due to GitHub bumping the `-latest` tag + without our knowledge. There's also a high risk that automatic bumping the CI + versions will fail due to manual work being required from experience. + +* For our release job, which is `release.yml`, prefer to use the oldest stable + (i.e. non-deprecated) versions available. The reason is that we're trying to + produce images that work in the broadest number of environments, and + therefore want to use older releases. + See also -------- diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt index 7588291fbf..54a70aaa65 100644 --- a/cmake.deps/CMakeLists.txt +++ b/cmake.deps/CMakeLists.txt @@ -203,8 +203,8 @@ set(TREESITTER_LUA_SHA256 564594fe0ffd2f2fb3578a15019b723e1bc94ac82cb6a0103a6b3b set(TREESITTER_VIM_URL https://github.com/vigoux/tree-sitter-viml/archive/v0.2.0.tar.gz) set(TREESITTER_VIM_SHA256 608dcc31a7948cb66ae7f45494620e2e9face1af75598205541f80d782ec4501) -set(TREESITTER_HELP_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v1.2.3.tar.gz) -set(TREESITTER_HELP_SHA256 e0a0d1c6c142b0096bb9ca22acd7e7ad3b205fbe68c26e6bfbbe03632c04db08) +set(TREESITTER_HELP_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v1.2.4.tar.gz) +set(TREESITTER_HELP_SHA256 e1595148092c082f6d50989a0f096182b39fd684449d09c4975ed403bfa42f10) set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.7.tar.gz) set(TREESITTER_SHA256 b355e968ec2d0241bbd96748e00a9038f83968f85d822ecb9940cbe4c42e182e) diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index 9eed5a8966..376487ad1d 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1208,8 +1208,8 @@ tag command action ~ |:cgetfile| :cg[etfile] read file with error messages |:changes| :changes print the change list |:chdir| :chd[ir] change directory -|:checkhealth| :checkh[ealth] run healthchecks -|:checkpath| :che[ckpath] list included files +|:checkhealth| :che[ckhealth] run healthchecks +|:checkpath| :checkp[ath] list included files |:checktime| :checkt[ime] check timestamp of loaded buffers |:chistory| :chi[story] list the error lists |:clast| :cla[st] go to the specified error, default last one diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index ce16c208cd..70a28a7519 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1573,7 +1573,7 @@ gsplit({s}, {sep}, {plain}) *vim.gsplit()* Parameters: ~ • {s} (string) String to split • {sep} (string) Separator or pattern - • {plain} (boolean) If `true` use `sep` literally (passed to + • {plain} (boolean|nil) If `true` use `sep` literally (passed to string.find) Return: ~ @@ -1645,15 +1645,11 @@ split({s}, {sep}, {kwargs}) *vim.split()* split("|x|y|z|", "|", {trimempty=true}) => {'x', 'y', 'z'} < - @alias split_kwargs {plain: boolean, trimempty: boolean} | boolean | nil - - See also: ~ - |vim.gsplit()| - Parameters: ~ • {s} (string) String to split • {sep} (string) Separator or pattern - • {kwargs} (table|nil) Keyword arguments: + • {kwargs} ({plain: boolean, trimempty: boolean}|nil) Keyword + arguments: • plain: (boolean) If `true` use `sep` literally (passed to string.find) • trimempty: (boolean) If `true` remove empty items from the @@ -1662,6 +1658,9 @@ split({s}, {sep}, {kwargs}) *vim.split()* Return: ~ string[] List of split components + See also: ~ + |vim.gsplit()| + startswith({s}, {prefix}) *vim.startswith()* Tests if `s` starts with `prefix`. diff --git a/runtime/doc/pi_health.txt b/runtime/doc/pi_health.txt index 8a6437fdc8..5ba5d1beef 100644 --- a/runtime/doc/pi_health.txt +++ b/runtime/doc/pi_health.txt @@ -21,8 +21,8 @@ Plugin authors are encouraged to write new healthchecks. |health-dev| ============================================================================== Commands *health-commands* - *:checkhealth* *:CheckHealth* -:checkhealth Run all healthchecks. + *:che* *:checkhealth* *:CheckHealth* +:che[ckhealth] Run all healthchecks. *E5009* Nvim depends on |$VIMRUNTIME|, 'runtimepath' and 'packpath' to find the standard "runtime files" for syntax highlighting, @@ -30,7 +30,7 @@ Commands *health-commands* :checkhealth). If the runtime files cannot be found then those features will not work. -:checkhealth {plugins} +:che[ckhealth] {plugins} Run healthcheck(s) for one or more plugins. E.g. to run only the standard Nvim healthcheck: > :checkhealth nvim diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index f1294a18ba..2f91498857 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -827,7 +827,7 @@ Short explanation of each option: *option-list* 'printmbcharset' 'pmbcs' CJK character set to be used for :hardcopy 'printmbfont' 'pmbfn' font names to be used for CJK output of :hardcopy 'printoptions' 'popt' controls the format of :hardcopy output -'pumheight' 'ph' maximum height of the popup menu +'pumheight' 'ph' maximum number of items to show in the popup menu 'pumwidth' 'pw' minimum width of the popup menu 'pyxversion' 'pyx' Python version used for pyx* commands 'quoteescape' 'qe' escape characters used in a string diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt index 143930c48a..d079db0717 100644 --- a/runtime/doc/tagsrch.txt +++ b/runtime/doc/tagsrch.txt @@ -829,10 +829,10 @@ CTRL-W d Open a new window, with the cursor on the first (default: whole file). See |:search-args| for [/] and [!]. - *:che* *:chec* *:check* *:checkpath* -:che[ckpath] List all the included files that could not be found. + *:checkp* *:checkpath* +:checkp[ath] List all the included files that could not be found. -:che[ckpath]! List all the included files. +:checkp[ath]! List all the included files. *:search-args* Common arguments for the commands above: diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index f03d608e56..f980547ae4 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -62,7 +62,7 @@ end)() --- ---@param s string String to split ---@param sep string Separator or pattern ----@param plain boolean If `true` use `sep` literally (passed to string.find) +---@param plain (boolean|nil) If `true` use `sep` literally (passed to string.find) ---@return fun():string (function) Iterator over the split components function vim.gsplit(s, sep, plain) vim.validate({ s = { s, 's' }, sep = { sep, 's' }, plain = { plain, 'b', true } }) @@ -108,11 +108,9 @@ end --- ---@see |vim.gsplit()| --- ----@alias split_kwargs {plain: boolean, trimempty: boolean} | boolean | nil ---- ---@param s string String to split ---@param sep string Separator or pattern ----@param kwargs? {plain: boolean, trimempty: boolean} (table|nil) Keyword arguments: +---@param kwargs ({plain: boolean, trimempty: boolean}|nil) Keyword arguments: --- - plain: (boolean) If `true` use `sep` literally (passed to string.find) --- - trimempty: (boolean) If `true` remove empty items from the front --- and back of the list @@ -159,8 +157,8 @@ end --- ---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ----@param t table<T, any> (table) Table ---@generic T: table +---@param t table<T, any> (table) Table ---@return T[] (list) List of keys function vim.tbl_keys(t) assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) @@ -417,8 +415,8 @@ end ---@generic T: table ---@param dst T List which will be modified and appended to ---@param src table List from which values will be inserted ----@param start? number Start index on src. Defaults to 1 ----@param finish? number Final index on src. Defaults to `#src` +---@param start (number|nil) Start index on src. Defaults to 1 +---@param finish (number|nil) Final index on src. Defaults to `#src` ---@return T dst function vim.list_extend(dst, src, start, finish) vim.validate({ @@ -486,7 +484,7 @@ function vim.tbl_islist(t) -- TODO(bfredl): in the future, we will always be inside nvim -- then this check can be deleted. if vim._empty_dict_mt == nil then - return nil + return false end return getmetatable(t) ~= vim._empty_dict_mt end @@ -544,7 +542,7 @@ end ---@return string %-escaped pattern string function vim.pesc(s) vim.validate({ s = { s, 's' } }) - return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1') + return (s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')) end --- Tests if `s` starts with `prefix`. diff --git a/runtime/queries/help/highlights.scm b/runtime/queries/help/highlights.scm index cd4b6f8269..50beeed8b9 100644 --- a/runtime/queries/help/highlights.scm +++ b/runtime/queries/help/highlights.scm @@ -14,6 +14,10 @@ "`" @conceal (#set! conceal "") text: (_) @text.literal) (codeblock) @text.literal +(codeblock + ">" @conceal (#set! conceal "")) +(block + "<" @conceal (#set! conceal "")) (argument) @parameter (keycode) @string.special (url) @text.uri diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua index 16326cfe66..87a8e62503 100644 --- a/scripts/lintcommit.lua +++ b/scripts/lintcommit.lua @@ -86,11 +86,28 @@ local function validate_commit(commit_message) vim.inspect(allowed_types)) end - -- Check if scope is empty + -- Check if scope is appropriate if before_colon:match("%(") then local scope = vim.trim(before_colon:match("%((.*)%)")) + if scope == '' then - return [[Scope can't be empty.]] + return [[Scope can't be empty]] + end + + if vim.startswith(scope, "nvim_") then + return [[Scope should be "api" instead of "nvim_..."]] + end + + local alternative_scope = { + ['filetype.vim'] = 'filetype', + ['filetype.lua'] = 'filetype', + ['tree-sitter'] = 'treesitter', + ['ts'] = 'treesitter', + ['hl'] = 'highlight', + } + + if alternative_scope[scope] then + return ('Scope should be "%s" instead of "%s"'):format(alternative_scope[scope], scope) end end diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index be7c6fd8a6..0a2b1df197 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -120,9 +120,9 @@ get_vim_sources() { commit_message() { if [[ -n "$vim_tag" ]]; then - printf '%s\n%s' "${vim_message}" "${vim_commit_url}" + printf '%s\n\n%s\n\n%s' "${vim_message}" "${vim_commit_url}" "${vim_coauthor}" else - printf 'vim-patch:%s\n\n%s\n%s' "$vim_version" "$vim_message" "$vim_commit_url" + printf 'vim-patch:%s\n\n%s\n\n%s\n\n%s' "$vim_version" "$vim_message" "$vim_commit_url" "$vim_coauthor" fi } @@ -175,6 +175,7 @@ assign_commit_details() { vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}" vim_message="$(git -C "${VIM_SOURCE_DIR}" log -1 --pretty='format:%B' "${vim_commit}" \ | sed -e 's/\(#[0-9]\{1,\}\)/vim\/vim\1/g')" + vim_coauthor="$(git -C "${VIM_SOURCE_DIR}" log -1 --pretty='format:Co-authored-by: %an <%ae>' "${vim_commit}")" if [[ ${munge_commit_line} == "true" ]]; then # Remove first line of commit message. vim_message="$(echo "${vim_message}" | sed -e '1s/^patch /vim-patch:/')" @@ -278,6 +279,53 @@ preprocess_patch() { "$file" > "$file".tmp && mv "$file".tmp "$file" } +uncrustify_patch() { + local commit="$1" + local changed_files=() + while IFS='' read -r file; do changed_files+=("$file"); done < <(git diff-tree --name-only --no-commit-id -r "${commit}") + + local patch_path=$NVIM_SOURCE_DIR/build/vim_patch + rm -rf "$patch_path" + mkdir -p "$patch_path"/{before,after,patch} + + git checkout --quiet "$commit"~ + for file in "${changed_files[@]}"; do + if [[ -e $file ]]; then + cp "$file" "$patch_path"/before + fi + done + + git checkout --quiet "$commit" + for file in "${changed_files[@]}"; do + if [[ -e $file ]]; then + cp "$file" "$patch_path"/after + fi + done + + # If the difference are drastic enough uncrustify may need to be used more + # than once. This is obviously a bug that needs to be fixed on uncrustify's + # end, but in the meantime this workaround is sufficient. + for _ in {1..2}; do + uncrustify -c "$NVIM_SOURCE_DIR"/src/uncrustify.cfg -q --replace --no-backup "$patch_path"/{before,after}/*.[ch] + done + + for file in "${changed_files[@]}"; do + local basename + basename=$(basename "$file") + local before=$patch_path/before/$basename + local after=$patch_path/after/$basename + local patchfile="$patch_path"/patch/"$basename".patch + if [[ ! -e $before ]] || [[ ! -e $after ]]; then + continue + fi + git --no-pager diff --no-index --patch --unified=5 --color=never "$before" "$after" > "$patchfile" + sed -E "s|$before|/$file|g" -i "$patchfile" + sed -E "s|$after|/$file|g" -i "$patchfile" + done + + cat "$patch_path"/patch/*.patch +} + get_vimpatch() { get_vim_sources @@ -286,7 +334,12 @@ get_vimpatch() { msg_ok "Found Vim revision '${vim_commit}'." local patch_content - patch_content="$(git --no-pager show --unified=5 --color=never -1 --pretty=medium "${vim_commit}")" + if check_executable uncrustify; then + patch_content="$(uncrustify_patch "${vim_commit}")" + git switch --quiet master + else + patch_content="$(git --no-pager show --unified=5 --color=never -1 --pretty=medium "${vim_commit}")" + fi cd "${NVIM_SOURCE_DIR}" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 32d52bef46..beb48b8d7d 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1685,7 +1685,7 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er // error handled after loop break; } - // TODO(bfredl): wastefull copy. It could be avoided to encoding to msgpack + // TODO(bfredl): wasteful copy. It could be avoided to encoding to msgpack // directly here. But `result` might become invalid when next api function // is called in the loop. ADD_C(results, copy_object(result, arena)); diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 47027ae1e7..ca95a9a24e 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -2351,7 +2351,7 @@ static void expand_shellcmd(char *filepat, int *num_file, char ***file, int flag } // Go over all directories in $PATH. Expand matches in that directory and - // collect them in "ga". When "." is not in $PATH also expaned for the + // collect them in "ga". When "." is not in $PATH also expand for the // current directory, to find "subdir/cmd". ga_init(&ga, (int)sizeof(char *), 10); hashtab_T found_ht; diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f6530d0e92..4a62b4bf8d 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1877,6 +1877,36 @@ theend: #define MAX_FUNC_NESTING 50 +/// List functions. +/// +/// @param regmatch When NULL, all of them. +/// Otherwise functions matching "regmatch". +static void list_functions(regmatch_T *regmatch) +{ + const size_t used = func_hashtab.ht_used; + size_t todo = used; + const hashitem_T *const ht_array = func_hashtab.ht_array; + + for (const hashitem_T *hi = ht_array; todo > 0 && !got_int; hi++) { + if (!HASHITEM_EMPTY(hi)) { + ufunc_T *fp = HI2UF(hi); + todo--; + if ((fp->uf_flags & FC_DEAD) == 0 + && (regmatch == NULL + ? (!message_filtered((char *)fp->uf_name) + && !func_name_refcount(fp->uf_name)) + : (!isdigit(*fp->uf_name) + && vim_regexec(regmatch, (char *)fp->uf_name, 0)))) { + list_func_head(fp, false, false); + if (used != func_hashtab.ht_used || ht_array != func_hashtab.ht_array) { + emsg(_("E454: function list was modified")); + return; + } + } + } + } +} + /// ":function" void ex_function(exarg_T *eap) { @@ -1903,7 +1933,6 @@ void ex_function(exarg_T *eap) static int func_nr = 0; // number for nameless function int paren; hashtab_T *ht; - int todo; hashitem_T *hi; linenr_T sourcing_lnum_off; linenr_T sourcing_lnum_top; @@ -1916,19 +1945,7 @@ void ex_function(exarg_T *eap) // ":function" without argument: list functions. if (ends_excmd(*eap->arg)) { if (!eap->skip) { - todo = (int)func_hashtab.ht_used; - for (hi = func_hashtab.ht_array; todo > 0 && !got_int; hi++) { - if (!HASHITEM_EMPTY(hi)) { - todo--; - fp = HI2UF(hi); - if (message_filtered((char *)fp->uf_name)) { - continue; - } - if (!func_name_refcount(fp->uf_name)) { - list_func_head(fp, false, false); - } - } - } + list_functions(NULL); } eap->nextcmd = check_nextcmd(eap->arg); return; @@ -1946,18 +1963,7 @@ void ex_function(exarg_T *eap) *p = c; if (regmatch.regprog != NULL) { regmatch.rm_ic = p_ic; - - todo = (int)func_hashtab.ht_used; - for (hi = func_hashtab.ht_array; todo > 0 && !got_int; hi++) { - if (!HASHITEM_EMPTY(hi)) { - todo--; - fp = HI2UF(hi); - if (!isdigit(*fp->uf_name) - && vim_regexec(®match, (char *)fp->uf_name, 0)) { - list_func_head(fp, false, false); - } - } - } + list_functions(®match); vim_regfree(regmatch.regprog); } } diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 71956b2246..0015a82880 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -62,7 +62,7 @@ #define EX_FLAGS 0x200000u // allow flags after count in argument #define EX_LOCK_OK 0x1000000u // command can be executed when textlock is // set; when missing disallows editing another - // buffer when current buffer is locked + // buffer when curbuf->b_ro_locked is set #define EX_KEEPSCRIPT 0x4000000u // keep sctx of where command was invoked #define EX_PREVIEW 0x8000000u // allow incremental command preview #define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim index 0fd65e8f5a..443a217143 100644 --- a/src/nvim/testdir/test_arglist.vim +++ b/src/nvim/testdir/test_arglist.vim @@ -550,7 +550,7 @@ func Test_argdo() bwipe Xa.c Xb.c Xc.c endfunc -" Test for quiting Vim with unedited files in the argument list +" Test for quitting Vim with unedited files in the argument list func Test_quit_with_arglist() if !CanRunVimInTerminal() throw 'Skipped: cannot run vim in terminal' diff --git a/src/nvim/testdir/test_langmap.vim b/src/nvim/testdir/test_langmap.vim index 2284704603..aaed77e109 100644 --- a/src/nvim/testdir/test_langmap.vim +++ b/src/nvim/testdir/test_langmap.vim @@ -52,7 +52,7 @@ func Test_langmap() set langmap=RL let g:counter = 0 nnoremap L;L <Cmd>let g:counter += 1<CR> - nnoremap <C-L> <Cmd>throw 'This mapping shoud not be triggered'<CR> + nnoremap <C-L> <Cmd>throw 'This mapping should not be triggered'<CR> " 'langmap' is applied to keys without modifiers when matching a mapping call feedkeys('R;R', 'tx') diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim index db7ec92bf8..2e149ad5a5 100644 --- a/src/nvim/testdir/test_menu.vim +++ b/src/nvim/testdir/test_menu.vim @@ -429,7 +429,7 @@ func Test_menu_special() nunmenu Test.Sign endfunc -" Test for "icon=filname" in a toolbar +" Test for "icon=filename" in a toolbar func Test_menu_icon() CheckFeature toolbar nmenu icon=myicon.xpm Toolbar.Foo :echo "Foo"<CR> diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index b0e83b7f5f..dcedfe26a2 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -3251,7 +3251,7 @@ func Test_cclose_in_autocmd() " call test_override('starting', 0) endfunc -" Check that ":file" without an argument is possible even when curbuf is locked +" Check that ":file" without an argument is possible even when "curbuf->b_ro_locked" " is set. func Test_file_from_copen() " Works without argument. diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim index 4d450e180b..771f61442d 100644 --- a/src/nvim/testdir/test_timers.vim +++ b/src/nvim/testdir/test_timers.vim @@ -3,6 +3,7 @@ source check.vim CheckFeature timers +source screendump.vim source shared.vim source term_util.vim source load.vim @@ -408,6 +409,30 @@ func Test_timer_invalid_callback() call assert_fails('call timer_start(0, "0")', 'E921') endfunc +func Test_timer_changing_function_list() + CheckRunVimInTerminal + + " Create a large number of functions. Should get the "more" prompt. + " The typing "G" triggers the timer, which changes the function table. + let lines =<< trim END + for func in map(range(1,99), "'Func' .. v:val") + exe "func " .. func .. "()" + endfunc + endfor + au CmdlineLeave : call timer_start(0, {-> 0}) + END + call writefile(lines, 'XTest_timerchange') + let buf = RunVimInTerminal('-S XTest_timerchange', #{rows: 10}) + call term_sendkeys(buf, ":fu\<CR>") + call WaitForAssert({-> assert_match('-- More --', term_getline(buf, 10))}) + call term_sendkeys(buf, "G") + call WaitForAssert({-> assert_match('E454', term_getline(buf, 9))}) + call term_sendkeys(buf, "\<Esc>") + + call StopVimInTerminal(buf) + call delete('XTest_timerchange') +endfunc + func Test_timer_using_win_execute_undo_sync() let bufnr1 = bufnr() new diff --git a/src/nvim/testdir/test_vartabs.vim b/src/nvim/testdir/test_vartabs.vim index 0acd7fc1e5..32ad64cda4 100644 --- a/src/nvim/testdir/test_vartabs.vim +++ b/src/nvim/testdir/test_vartabs.vim @@ -97,7 +97,7 @@ func Test_vartabs() .retab! call assert_equal("\t\t\t\tl", getline(1)) - " Test for 'retab' with same vlaues as vts + " Test for 'retab' with same values as vts set ts=8 sts=0 vts=5,3,6,2 vsts= exe "norm! S l" .retab! 5,3,6,2 diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index 7fb34ec81f..a9c057088d 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -1281,7 +1281,7 @@ func Test_visual_block_with_virtualedit() endfunc func Test_visual_block_ctrl_w_f() - " Emtpy block selected in new buffer should not result in an error. + " Empty block selected in new buffer should not result in an error. au! BufNew foo sil norm f edit foo diff --git a/src/nvim/viml/parser/expressions.h b/src/nvim/viml/parser/expressions.h index 9d0bc9d468..77fbfa615f 100644 --- a/src/nvim/viml/parser/expressions.h +++ b/src/nvim/viml/parser/expressions.h @@ -357,7 +357,7 @@ typedef struct { int arg_len; } ExprASTError; -/// Structure representing complety AST for one expression +/// Structure representing complete AST for one expression typedef struct { /// When AST is not correct this message will be printed. /// diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index f250a3ec93..38f772c5cf 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -430,6 +430,8 @@ describe('lua stdlib', function() it('vim.pesc', function() eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) + -- pesc() returns one result. #20751 + eq({'x'}, exec_lua([[return {vim.pesc('x')}]])) -- Validates args. matches('s: expected string, got number', @@ -1016,11 +1018,11 @@ describe('lua stdlib', function() eq('hi', funcs.luaeval "vim.g.testing") eq(123, funcs.luaeval "vim.g.other") eq(5120.1, funcs.luaeval "vim.g.floaty") - eq(NIL, funcs.luaeval "vim.g.nonexistant") + eq(NIL, funcs.luaeval "vim.g.nonexistent") eq(NIL, funcs.luaeval "vim.g.nullvar") -- lost over RPC, so test locally: eq({false, true}, exec_lua [[ - return {vim.g.nonexistant == vim.NIL, vim.g.nullvar == vim.NIL} + return {vim.g.nonexistent == vim.NIL, vim.g.nullvar == vim.NIL} ]]) eq({hello="world"}, funcs.luaeval "vim.g.to_delete") @@ -1123,12 +1125,12 @@ describe('lua stdlib', function() eq('bye', funcs.luaeval "vim.b[BUF].testing") eq(123, funcs.luaeval "vim.b.other") eq(5120.1, funcs.luaeval "vim.b.floaty") - eq(NIL, funcs.luaeval "vim.b.nonexistant") - eq(NIL, funcs.luaeval "vim.b[BUF].nonexistant") + eq(NIL, funcs.luaeval "vim.b.nonexistent") + eq(NIL, funcs.luaeval "vim.b[BUF].nonexistent") eq(NIL, funcs.luaeval "vim.b.nullvar") -- lost over RPC, so test locally: eq({false, true}, exec_lua [[ - return {vim.b.nonexistant == vim.NIL, vim.b.nullvar == vim.NIL} + return {vim.b.nonexistent == vim.NIL, vim.b.nullvar == vim.NIL} ]]) matches([[attempt to index .* nil value]], @@ -1207,7 +1209,7 @@ describe('lua stdlib', function() eq(NIL, funcs.luaeval "vim.b.testing") eq(NIL, funcs.luaeval "vim.b.other") - eq(NIL, funcs.luaeval "vim.b.nonexistant") + eq(NIL, funcs.luaeval "vim.b.nonexistent") end) it('vim.w', function() @@ -1226,8 +1228,8 @@ describe('lua stdlib', function() eq('hi', funcs.luaeval "vim.w.testing") eq('bye', funcs.luaeval "vim.w[WIN].testing") eq(123, funcs.luaeval "vim.w.other") - eq(NIL, funcs.luaeval "vim.w.nonexistant") - eq(NIL, funcs.luaeval "vim.w[WIN].nonexistant") + eq(NIL, funcs.luaeval "vim.w.nonexistent") + eq(NIL, funcs.luaeval "vim.w[WIN].nonexistent") matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.w[WIN][0].testing')) @@ -1305,7 +1307,7 @@ describe('lua stdlib', function() eq(NIL, funcs.luaeval "vim.w.testing") eq(NIL, funcs.luaeval "vim.w.other") - eq(NIL, funcs.luaeval "vim.w.nonexistant") + eq(NIL, funcs.luaeval "vim.w.nonexistent") end) it('vim.t', function() @@ -1317,10 +1319,10 @@ describe('lua stdlib', function() eq('hi', funcs.luaeval "vim.t.testing") eq(123, funcs.luaeval "vim.t.other") - eq(NIL, funcs.luaeval "vim.t.nonexistant") + eq(NIL, funcs.luaeval "vim.t.nonexistent") eq('hi', funcs.luaeval "vim.t[0].testing") eq(123, funcs.luaeval "vim.t[0].other") - eq(NIL, funcs.luaeval "vim.t[0].nonexistant") + eq(NIL, funcs.luaeval "vim.t[0].nonexistent") matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.t[0][0].testing')) @@ -1387,7 +1389,7 @@ describe('lua stdlib', function() eq(NIL, funcs.luaeval "vim.t.testing") eq(NIL, funcs.luaeval "vim.t.other") - eq(NIL, funcs.luaeval "vim.t.nonexistant") + eq(NIL, funcs.luaeval "vim.t.nonexistent") end) it('vim.env', function() diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index e9072ebf98..5b62f5b3e1 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -1115,7 +1115,7 @@ if (h->n_buckets < new_n_buckets) { // expand ]]} meths.buf_set_extmark(0, ns, 5, 0, { - virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unneccesary?", "Comment"}} }; + virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unnecessary?", "Comment"}} }; }) -- TODO: what about the cursor?? screen:expect{grid=[[ @@ -1128,7 +1128,7 @@ if (h->n_buckets < new_n_buckets) { // expand if (kh_is_map && val_size) { | ^char *new_vals = {3:krealloc}( h->vals_buf, new_n_| buckets * val_size); | - {5:^^ REVIEW:}{6: new_vals variable seems unneccesary?} | + {5:^^ REVIEW:}{6: new_vals variable seems unnecessary?} | h->vals_buf = new_vals; | | ]]} diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua index 1fbdedb815..64a3cf5471 100644 --- a/test/functional/vimscript/eval_spec.lua +++ b/test/functional/vimscript/eval_spec.lua @@ -17,12 +17,16 @@ local clear = helpers.clear local eq = helpers.eq local exc_exec = helpers.exc_exec local exec = helpers.exec +local exec_lua = helpers.exec_lua local exec_capture = helpers.exec_capture local eval = helpers.eval local command = helpers.command local write_file = helpers.write_file local meths = helpers.meths local sleep = helpers.sleep +local matches = helpers.matches +local pcall_err = helpers.pcall_err +local assert_alive = helpers.assert_alive local poke_eventloop = helpers.poke_eventloop local feed = helpers.feed @@ -249,10 +253,10 @@ describe("uncaught exception", function() end) end) -describe('lambda function', function() +describe('listing functions using :function', function() before_each(clear) - it('can be shown using :function followed by <lambda> #20466', function() + it('works for lambda functions with <lambda> #20466', function() command('let A = {-> 1}') local num = exec_capture('echo A'):match("function%('<lambda>(%d+)'%)") eq(([[ @@ -260,4 +264,33 @@ describe('lambda function', function() 1 return 1 endfunction]]):format(num), exec_capture(('function <lambda>%s'):format(num))) end) + + -- FIXME: If the same function is deleted, the crash still happens. #20790 + it('does not crash if another function is deleted while listing', function() + local screen = Screen.new(80, 24) + screen:attach() + matches('.*: Vim%(function%):E454: function list was modified', pcall_err(exec_lua, [=[ + vim.cmd([[ + func Func1() + endfunc + func Func2() + endfunc + func Func3() + endfunc + ]]) + + local ns = vim.api.nvim_create_namespace('test') + + vim.ui_attach(ns, { ext_messages = true }, function(event, _, content) + if event == 'msg_show' and content[1][2] == 'function Func1()' then + vim.cmd('delfunc Func3') + end + end) + + vim.cmd('function') + + vim.ui_detach(ns) + ]=])) + assert_alive() + end) end) |