aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md12
-rw-r--r--INSTALL.md22
-rw-r--r--cmake.deps/CMakeLists.txt1
-rw-r--r--runtime/autoload/netrw.vim6
-rw-r--r--runtime/doc/autocmd.txt5
-rw-r--r--runtime/doc/lsp.txt30
-rw-r--r--runtime/doc/lua.txt12
-rw-r--r--runtime/doc/motion.txt2
-rw-r--r--runtime/doc/options.txt8
-rw-r--r--runtime/doc/recover.txt8
-rw-r--r--runtime/ftplugin/gdscript.vim68
-rw-r--r--runtime/ftplugin/gdshader.vim13
-rw-r--r--runtime/indent/gdscript.vim154
-rw-r--r--runtime/lua/vim/_editor.lua6
-rw-r--r--runtime/lua/vim/_meta/options.lua8
-rw-r--r--runtime/lua/vim/diagnostic.lua6
-rw-r--r--runtime/lua/vim/glob.lua3
-rw-r--r--runtime/lua/vim/iter.lua8
-rw-r--r--runtime/lua/vim/lsp.lua17
-rw-r--r--runtime/lua/vim/lsp/inlay_hint.lua8
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua5
-rw-r--r--runtime/syntax/i3config.vim8
-rw-r--r--runtime/syntax/swayconfig.vim12
-rw-r--r--scripts/gen_help_html.lua6
-rw-r--r--src/nvim/README.md6
-rw-r--r--src/nvim/autocmd.c7
-rw-r--r--src/nvim/autocmd_defs.h2
-rw-r--r--src/nvim/drawline.c236
-rw-r--r--src/nvim/ex_getln.c9
-rw-r--r--src/nvim/option.c8
-rw-r--r--src/nvim/options.lua8
-rw-r--r--src/nvim/optionstr.c98
-rw-r--r--src/nvim/tui/tui.c6
-rw-r--r--src/nvim/undo.c4
-rw-r--r--test/client/msgpack_rpc_stream.lua3
-rw-r--r--test/client/session.lua14
-rw-r--r--test/client/uv_stream.lua36
-rw-r--r--test/deprecated.lua9
-rw-r--r--test/format_string.lua168
-rw-r--r--test/functional/api/vim_spec.lua36
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua2
-rw-r--r--test/functional/helpers.lua260
-rw-r--r--test/functional/legacy/prompt_buffer_spec.lua18
-rw-r--r--test/functional/lua/fs_spec.lua4
-rw-r--r--test/functional/lua/luaeval_spec.lua4
-rw-r--r--test/functional/lua/watch_spec.lua5
-rw-r--r--test/functional/options/chars_spec.lua27
-rw-r--r--test/functional/plugin/lsp_spec.lua5
-rw-r--r--test/functional/shada/merging_spec.lua2
-rw-r--r--test/functional/shada/shada_spec.lua2
-rw-r--r--test/functional/terminal/channel_spec.lua6
-rw-r--r--test/functional/ui/inccommand_spec.lua51
-rw-r--r--test/functional/ui/inccommand_user_spec.lua18
-rw-r--r--test/functional/ui/messages_spec.lua10
-rw-r--r--test/functional/ui/popupmenu_spec.lua2
-rw-r--r--test/functional/ui/sign_spec.lua17
-rw-r--r--test/functional/vimscript/ctx_functions_spec.lua4
-rw-r--r--test/functional/vimscript/input_spec.lua20
-rw-r--r--test/functional/vimscript/timer_spec.lua18
-rw-r--r--test/helpers.lua361
-rw-r--r--test/old/testdir/test_display.vim20
-rw-r--r--test/old/testdir/test_listchars.vim76
-rw-r--r--test/old/testdir/test_listdict.vim2
-rw-r--r--test/old/testdir/test_prompt_buffer.vim27
-rw-r--r--test/unit/helpers.lua10
-rw-r--r--test/unit/viml/expressions/parser_spec.lua4
-rw-r--r--test/unit/viml/expressions/parser_tests.lua4
67 files changed, 1288 insertions, 769 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3fe735cad2..ef83c22155 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -149,8 +149,10 @@ View the [Clang report] to see potential bugs found by the Clang
### Coverity
-[Coverity](https://scan.coverity.com/projects/neovim-neovim) runs against the
-master build. To view the defects, just request access; you will be approved.
+Coverity runs against the master build. To view the defects you must
+[request access](https://scan.coverity.com/projects/neovim-neovim) (Coverity
+does not have a "public" view), then you will be approved as soon as
+a maintainer sees the email.
- Use this format for commit messages (where `{id}` is the CID (Coverity ID);
([example](https://github.com/neovim/neovim/pull/804))):
@@ -283,7 +285,7 @@ If you need to modify or debug the documentation flow, these are the main files:
### Lua docstrings
Use [LuaLS] annotations in Lua docstrings to annotate parameter types, return
-types, etc. See [:help dev-doc-lua][dev-doc-lua].
+types, etc. See [:help dev-lua-doc][dev-lua-doc].
- The template for function documentation is:
```lua
@@ -331,8 +333,8 @@ as context, use the `-W` argument as well.
[complexity:low]: https://github.com/neovim/neovim/issues?q=is%3Aopen+is%3Aissue+label%3Acomplexity%3Alow
[conventional_commits]: https://www.conventionalcommits.org
[dev-doc-guide]: https://neovim.io/doc/user/develop.html#dev-doc
-[dev-doc-lua]: https://neovim.io/doc/user/develop.html#dev-lua-doc
-[LuaLS]: https://github.com/LuaLS/lua-language-server/wiki/Annotations
+[dev-lua-doc]: https://neovim.io/doc/user/develop.html#dev-lua-doc
+[LuaLS]: https://luals.github.io/wiki/annotations/
[gcc-warnings]: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
[gh]: https://cli.github.com/
[git-bisect]: http://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git
diff --git a/INSTALL.md b/INSTALL.md
index 3b882ab6c9..2246058bca 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -155,17 +155,6 @@ Python (`:python`) support is installable via the package manager on Debian unst
sudo apt-get install python3-neovim
-If installing via appimage, the following commands may be helpful in updating default paths:
-
- # CUSTOM_NVIM_PATH=/usr/local/bin/nvim.appimage
- # Set the above with the correct path, then run the rest of the commands:
- set -u
- sudo update-alternatives --install /usr/bin/ex ex "${CUSTOM_NVIM_PATH}" 110
- sudo update-alternatives --install /usr/bin/vi vi "${CUSTOM_NVIM_PATH}" 110
- sudo update-alternatives --install /usr/bin/view view "${CUSTOM_NVIM_PATH}" 110
- sudo update-alternatives --install /usr/bin/vim vim "${CUSTOM_NVIM_PATH}" 110
- sudo update-alternatives --install /usr/bin/vimdiff vimdiff "${CUSTOM_NVIM_PATH}" 110
-
### Exherbo Linux
Exhereses for scm and released versions are currently available in repository `::medvid`. Python client (with GTK+ GUI included) and Qt5 GUI are also available as suggestions:
@@ -336,17 +325,6 @@ If you're using an older version Ubuntu you must use:
For instructions to install the Python modules, see [`:help provider-python`].
-If you want to use Neovim for some (or all) of the editor alternatives, use the following commands:
-
- sudo update-alternatives --install /usr/bin/vi vi /usr/bin/nvim 60
- sudo update-alternatives --config vi
- sudo update-alternatives --install /usr/bin/vim vim /usr/bin/nvim 60
- sudo update-alternatives --config vim
- sudo update-alternatives --install /usr/bin/editor editor /usr/bin/nvim 60
- sudo update-alternatives --config editor
-
-Note, however, that special interfaces, like `view` for `nvim -R`, are not supported. (See [#1646](https://github.com/neovim/neovim/issues/1646) and [#2008](https://github.com/neovim/neovim/pull/2008).)
-
### Void-Linux
Neovim can be installed using the xbps package manager
diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt
index 90b752d250..afc4da8def 100644
--- a/cmake.deps/CMakeLists.txt
+++ b/cmake.deps/CMakeLists.txt
@@ -37,6 +37,7 @@ option(USE_BUNDLED "Use bundled dependencies." ON)
option(USE_BUNDLED_LIBUV "Use the bundled libuv." ${USE_BUNDLED})
option(USE_BUNDLED_LIBVTERM "Use the bundled libvterm." ${USE_BUNDLED})
option(USE_BUNDLED_LPEG "Use the bundled lpeg." ${USE_BUNDLED})
+# PUC Lua is only used for tests, unless explicitly requested.
option(USE_BUNDLED_LUA "Use the bundled version of lua." OFF)
option(USE_BUNDLED_LUAJIT "Use the bundled version of luajit." ${USE_BUNDLED})
option(USE_BUNDLED_LUV "Use the bundled version of luv." ${USE_BUNDLED})
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index 811a9501fe..4decfbced7 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -7802,7 +7802,7 @@ fun! s:NetrwMarkFileMove(islocal)
let movecmd = netrw#WinPath(movecmd).movecmdargs
" call Decho("windows exception: movecmd<".movecmd."> (#1: had a space)",'~'.expand("<slnum>"))
else
- let movecmd = netrw#WinPath(movecmd)
+ let movecmd = netrw#WinPath(g:netrw_localmovecmd)
" call Decho("windows exception: movecmd<".movecmd."> (#2: no space)",'~'.expand("<slnum>"))
endif
else
@@ -7816,10 +7816,6 @@ fun! s:NetrwMarkFileMove(islocal)
endif
if !g:netrw_cygwin && (has("win32") || has("win95") || has("win64") || has("win16"))
let fname= substitute(fname,'/','\\','g')
- if g:netrw_keepdir
- " Jul 19, 2022: fixing file move when g:netrw_keepdir is 1
- let fname= b:netrw_curdir."\\".fname
- endif
endif
" call Decho("system(".movecmd." ".s:ShellEscape(fname)." ".tgt.")",'~'.expand("<slnum>"))
let ret= system(movecmd.g:netrw_localmovecmdopt." ".s:ShellEscape(fname)." ".tgt)
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index ce3af01073..e43574fe86 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -784,9 +784,6 @@ OptionSet After setting an option (except during
are not global-local it is the old local
value.
- OptionSet is not triggered on startup and for
- the 'key' option for obvious reasons.
-
Usage example: Check for the existence of the
directory in the 'backupdir' and 'undodir'
options, create the directory if it doesn't
@@ -800,6 +797,8 @@ OptionSet After setting an option (except during
Non-recursive: |:set| in the autocommand does
not trigger OptionSet again.
+ Not triggered on startup.
+
*QuickFixCmdPre*
QuickFixCmdPre Before a quickfix command is run (|:make|,
|:lmake|, |:grep|, |:lgrep|, |:grepadd|,
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index e3fc616df4..ad1b838578 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -911,9 +911,8 @@ start({config}, {opts}) *vim.lsp.start()*
• `name` arbitrary name for the LSP client. Should be unique per language
server.
- • `cmd` command (in list form) used to start the language server. Must be
- absolute, or found on `$PATH`. Shell constructs like `~` are not
- expanded.
+ • `cmd` command string[] or function, described at
+ |vim.lsp.start_client()|.
• `root_dir` path to the project root. By default this is used to decide
if an existing client should be re-used. The example above uses
|vim.fs.find()| and |vim.fs.dirname()| to detect the root by traversing
@@ -953,15 +952,16 @@ start_client({config}) *vim.lsp.start_client()*
Parameters: ~
• {config} (`lsp.ClientConfig`) Configuration for the server:
- • cmd: (string[]|fun(dispatchers: table):table) command a
- list of strings treated like |jobstart()|. The command
- must launch the language server process. `cmd` can also be
- a function that creates an RPC client. The function
- receives a dispatchers table and must return a table with
- the functions `request`, `notify`, `is_closing` and
- `terminate` See |vim.lsp.rpc.request()| and
- |vim.lsp.rpc.notify()| For TCP there is a built-in rpc
- client factory: |vim.lsp.rpc.connect()|
+ • cmd: (string[]|fun(dispatchers: table):table) command
+ string[] that launches the language server (treated as in
+ |jobstart()|, must be absolute or on `$PATH`, shell
+ constructs like "~" are not expanded), or function that
+ creates an RPC client. Function receives a `dispatchers`
+ table and returns a table with member functions `request`,
+ `notify`, `is_closing` and `terminate`. See
+ |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|. For TCP
+ there is a builtin RPC client factory:
+ |vim.lsp.rpc.connect()|
• cmd_cwd: (string, default=|getcwd()|) Directory to launch
the `cmd` process. Not related to `root_dir`.
• cmd_env: (table) Environment flags to pass to the LSP on
@@ -1479,7 +1479,11 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()*
Lua module: vim.lsp.inlay_hint *lsp-inlay_hint*
enable({bufnr}, {enable}) *vim.lsp.inlay_hint.enable()*
- Enable/disable/toggle inlay hints for a buffer
+ Enables or disables inlay hints for a buffer.
+
+ To "toggle", pass the inverse of `is_enabled()`: >lua
+ vim.lsp.inlay_hint.enable(0, not vim.lsp.inlay_hint.is_enabled())
+<
Note: ~
This API is pre-release (unstable).
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 924eb99e4e..24474255ba 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -3753,9 +3753,9 @@ filter({f}, {src}, {...}) *vim.iter.filter()*
<
Parameters: ~
- • {f} (`fun(...):bool`) Filter function. Accepts the current iterator
- or table values as arguments and returns true if those values
- should be kept in the final table
+ • {f} (`fun(...):boolean`) Filter function. Accepts the current
+ iterator or table values as arguments and returns true if those
+ values should be kept in the final table
• {src} (`table|function`) Table or iterator function to filter
Return: ~
@@ -3768,7 +3768,7 @@ Iter:all({pred}) *Iter:all()*
Returns true if all items in the iterator match the given predicate.
Parameters: ~
- • {pred} (`fun(...):bool`) Predicate function. Takes all values
+ • {pred} (`fun(...):boolean`) Predicate function. Takes all values
returned from the previous stage in the pipeline as arguments
and returns true if the predicate matches.
@@ -3777,7 +3777,7 @@ Iter:any({pred}) *Iter:any()*
predicate.
Parameters: ~
- • {pred} (`fun(...):bool`) Predicate function. Takes all values
+ • {pred} (`fun(...):boolean`) Predicate function. Takes all values
returned from the previous stage in the pipeline as arguments
and returns true if the predicate matches.
@@ -3826,7 +3826,7 @@ Iter:filter({f}) *Iter:filter()*
<
Parameters: ~
- • {f} (`fun(...):bool`) Takes all values returned from the previous
+ • {f} (`fun(...):boolean`) Takes all values returned from the previous
stage in the pipeline and returns false or nil if the current
iterator element should be removed.
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index 03fe5c7b81..e80969c583 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -1048,7 +1048,7 @@ CTRL-I Go to [count] newer cursor position in jump list
|tui-modifyOtherKeys| or |tui-csiu|, CTRL-I can be
mapped separately from <Tab>, on the condition that
both keys are mapped, otherwise the mapping applies to
- both.
+ both. Except in tmux: https://github.com/tmux/tmux/issues/2705
*:ju* *:jumps*
:ju[mps] Print the jump list (not a motion command).
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 9405d73fd0..59ac3b7f34 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2485,7 +2485,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Characters to fill the statuslines, vertical separators and special
lines in the window.
It is a comma-separated list of items. Each item has a name, a colon
- and the value of that item:
+ and the value of that item: |E1511|
item default Used for ~
stl ' ' statusline of the current window
@@ -2523,7 +2523,7 @@ A jump table for the options with a short description can be found at |Q_op|.
<
For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
single-byte and multibyte characters are supported. But double-width
- characters are not supported.
+ characters are not supported. |E1512|
The highlighting used for these items:
item highlight group ~
@@ -3823,7 +3823,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'listchars' 'lcs' string (default "tab:> ,trail:-,nbsp:+")
global or local to window |global-local|
Strings to use in 'list' mode and for the |:list| command. It is a
- comma-separated list of string settings.
+ comma-separated list of string settings. *E1511*
*lcs-eol*
eol:c Character to show at the end of each line. When
@@ -3902,7 +3902,7 @@ A jump table for the options with a short description can be found at |Q_op|.
omitted.
The characters ':' and ',' should not be used. UTF-8 characters can
- be used. All characters must be single width.
+ be used. All characters must be single width. *E1512*
Each character can be specified as hex: >vim
set listchars=eol:\\x24
diff --git a/runtime/doc/recover.txt b/runtime/doc/recover.txt
index e6b5b06744..4312716b22 100644
--- a/runtime/doc/recover.txt
+++ b/runtime/doc/recover.txt
@@ -85,10 +85,10 @@ You can find this in the user manual, section |11.3|.
*W325*
The default |SwapExists| handler (|default-autocmds|) skips the |E325| prompt
-(selects "(E)dit") if the swapfile owner process (1) is still running and (2)
-was started by the current user. This presumes that you normally don't want
-to be bothered with the |ATTENTION| message just because you happen to edit
-the same file from multiple Nvim instances. In the worst case (a system
+(and automatically chooses "(E)dit") if the swapfile owner process is still
+running and owned by the current user. This presumes that you normally don't
+want to be bothered with the |ATTENTION| message just because you happen to
+edit the same file from multiple Nvim instances. In the worst case (a system
crash) there will be more than one swapfile for the file; use |:recover| to
inspect all of its swapfiles.
diff --git a/runtime/ftplugin/gdscript.vim b/runtime/ftplugin/gdscript.vim
new file mode 100644
index 0000000000..692afdd0ea
--- /dev/null
+++ b/runtime/ftplugin/gdscript.vim
@@ -0,0 +1,68 @@
+" Vim filetype plugin file
+" Language: gdscript (Godot game engine scripting language)
+" Maintainer: Maxim Kim <habamax@gmail.com>
+" Website: https://github.com/habamax/vim-gdscript
+"
+" This file has been manually translated from Vim9 script.
+
+if exists("b:did_ftplugin") | finish | endif
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+let b:did_ftplugin = 1
+let b:undo_ftplugin = 'setlocal cinkeys<'
+ \ .. '| setlocal indentkeys<'
+ \ .. '| setlocal commentstring<'
+ \ .. '| setlocal suffixesadd<'
+ \ .. '| setlocal foldexpr<'
+ \ .. '| setlocal foldignore<'
+
+setlocal cinkeys-=0#
+setlocal indentkeys-=0#
+setlocal suffixesadd=.gd
+setlocal commentstring=#\ %s
+setlocal foldignore=
+setlocal foldexpr=s:GDScriptFoldLevel()
+
+
+function s:GDScriptFoldLevel() abort
+ let line = getline(v:lnum)
+ if line =~? '^\s*$'
+ return "-1"
+ endif
+
+ let sw = shiftwidth()
+ let indent = indent(v:lnum) / sw
+ let indent_next = indent(nextnonblank(v:lnum + 1)) / sw
+
+ if indent_next > indent && line =~# ':\s*$'
+ return $">{indent_next}"
+ else
+ return $"{indent}"
+ endif
+endfunction
+
+
+if !exists("g:no_plugin_maps")
+ " Next/Previous section
+ function s:NextSection(back, cnt) abort
+ for n in range(a:cnt)
+ call search('^\s*func\s', a:back ? 'bW' : 'W')
+ endfor
+ endfunction
+
+ " Nvim: <scriptcmd> hasn't been ported yet.
+ " nnoremap <silent><buffer> ]] <scriptcmd>NextSection(false, v:count1)<CR>
+ " nnoremap <silent><buffer> [[ <scriptcmd>NextSection(true, v:count1)<CR>
+ nnoremap <silent><buffer> ]] <Cmd>call <SID>NextSection(v:false, v:count1)<CR>
+ nnoremap <silent><buffer> [[ <Cmd>call <SID>NextSection(v:true, v:count1)<CR>
+ xmap <buffer><expr> ]] $'<C-\><C-N>{v:count1}]]m>gv'
+ xmap <buffer><expr> [[ $'<C-\><C-N>{v:count1}[[m>gv'
+ let b:undo_ftplugin ..=
+ \ " | silent exe 'unmap <buffer> [['"
+ \ .. " | silent exe 'unmap <buffer> ]]'"
+endif
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
diff --git a/runtime/ftplugin/gdshader.vim b/runtime/ftplugin/gdshader.vim
new file mode 100644
index 0000000000..f0d34ee5a6
--- /dev/null
+++ b/runtime/ftplugin/gdshader.vim
@@ -0,0 +1,13 @@
+" Vim filetype plugin file
+" Language: Godot shading language
+" Maintainer: Maxim Kim <habamax@gmail.com>
+" Website: https://github.com/habamax/vim-gdscript
+"
+" This file has been manually translated from Vim9 script.
+
+if exists("b:did_ftplugin") | finish | endif
+let b:did_ftplugin = 1
+
+let b:undo_ftplugin = 'setlocal suffixesadd<'
+
+setlocal suffixesadd=.gdshader
diff --git a/runtime/indent/gdscript.vim b/runtime/indent/gdscript.vim
new file mode 100644
index 0000000000..bbb4f284f1
--- /dev/null
+++ b/runtime/indent/gdscript.vim
@@ -0,0 +1,154 @@
+" Vim indent file
+" Language: gdscript (Godot game engine)
+" Maintainer: Maxim Kim <habamax@gmail.com>
+" Based on python indent file.
+"
+" This file has been manually translated from Vim9 script.
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+let s:undo_opts = "setl indentexpr< indentkeys< lisp< autoindent<"
+
+if exists('b:undo_indent')
+ let b:undo_indent ..= "|" .. s:undo_opts
+else
+ let b:undo_indent = s:undo_opts
+endif
+
+setlocal nolisp
+setlocal autoindent
+setlocal indentexpr=s:GDScriptIndent()
+setlocal indentkeys+=<:>,=elif,=except
+
+
+function s:GDScriptIndent() abort
+ " If this line is explicitly joined: If the previous line was also joined,
+ " line it up with that one, otherwise add two 'shiftwidth'
+ if getline(v:lnum - 1) =~# '\\$'
+ if v:lnum > 1 && getline(v:lnum - 2) =~# '\\$'
+ return indent(v:lnum - 1)
+ endif
+ return indent(v:lnum - 1) + (shiftwidth() * 2)
+ endif
+
+ " If the start of the line is in a string don't change the indent.
+ if has('syntax_items') && synIDattr(synID(v:lnum, 1, 1), "name") =~# "String$"
+ return -1
+ endif
+
+ " Search backwards for the previous non-empty line.
+ let plnum = prevnonblank(v:lnum - 1)
+
+ if plnum == 0
+ " This is the first non-empty line, use zero indent.
+ return 0
+ endif
+
+ let plindent = indent(plnum)
+ let plnumstart = plnum
+
+ " Get the line and remove a trailing comment.
+ " Use syntax highlighting attributes when possible.
+ let pline = getline(plnum)
+ let pline_len = strlen(pline)
+ if has('syntax_items')
+ " If the last character in the line is a comment, do a binary search for
+ " the start of the comment. synID() is slow, a linear search would take
+ " too long on a long line.
+ if synIDattr(synID(plnum, pline_len, 1), "name") =~# "\\(Comment\\|Todo\\)$"
+ let min = 1
+ let max = pline_len
+ while min < max
+ let col = (min + max) / 2
+ if synIDattr(synID(plnum, col, 1), "name") =~# "\\(Comment\\|Todo\\)$"
+ let max = col
+ else
+ let min = col + 1
+ endif
+ endwhile
+ let pline = strpart(pline, 0, min - 1)
+ endif
+ else
+ let col = 0
+ while col < pline_len
+ if pline[col] ==# '#'
+ let pline = strpart(pline, 0, col)
+ break
+ endif
+ let col = col + 1
+ endwhile
+ endif
+
+
+ " When "inside" parenthesis: If at the first line below the parenthesis add
+ " one 'shiftwidth' ("inside" is simplified and not really checked)
+ " my_var = (
+ " a
+ " + b
+ " + c
+ " )
+ if pline =~# '[({\[]\s*$'
+ return indent(plnum) + shiftwidth()
+ endif
+
+
+ " If the previous line ended with a colon, indent this line
+ if pline =~# ':\s*$'
+ return plindent + shiftwidth()
+ endif
+
+ " If the previous line was a stop-execution statement...
+ if getline(plnum) =~# '^\s*\(break\|continue\|raise\|return\|pass\)\>'
+ " See if the user has already dedented
+ if indent(v:lnum) > indent(plnum) - shiftwidth()
+ " If not, recommend one dedent
+ return indent(plnum) - shiftwidth()
+ endif
+ " Otherwise, trust the user
+ return -1
+ endif
+
+ " If the current line begins with a keyword that lines up with "try"
+ if getline(v:lnum) =~# '^\s*\(except\|finally\)\>'
+ let lnum = v:lnum - 1
+ while lnum >= 1
+ if getline(lnum) =~# '^\s*\(try\|except\)\>'
+ let ind = indent(lnum)
+ if ind >= indent(v:lnum)
+ return -1 " indent is already less than this
+ endif
+ return ind " line up with previous try or except
+ endif
+ let lnum = lnum - 1
+ endwhile
+ return -1 " no matching "try"!
+ endif
+
+
+ " If the current line begins with a header keyword, dedent
+ if getline(v:lnum) =~# '^\s*\(elif\|else\)\>'
+
+ " Unless the previous line was a one-liner
+ if getline(plnumstart) =~# '^\s*\(for\|if\|try\)\>'
+ return plindent
+ endif
+
+ " Or the user has already dedented
+ if indent(v:lnum) <= plindent - shiftwidth()
+ return -1
+ endif
+
+ return plindent - shiftwidth()
+ endif
+
+ return -1
+endfunction
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 4fe601dfd5..52a21587f4 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -190,12 +190,18 @@ function vim._os_proc_children(ppid)
return children
end
+--- @class vim.inspect.Opts
+--- @field depth? integer
+--- @field newline? string
+--- @field process? fun(item:any, path: string[]): any
+
--- Gets a human-readable representation of the given object.
---
---@see |vim.print()|
---@see https://github.com/kikito/inspect.lua
---@see https://github.com/mpeterv/vinspect
---@return string
+---@overload fun(x: any, opts?: vim.inspect.Opts): string
vim.inspect = vim.inspect
do
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 8c550fccdb..c9e2e302dc 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -2197,7 +2197,7 @@ vim.bo.ft = vim.bo.filetype
--- Characters to fill the statuslines, vertical separators and special
--- lines in the window.
--- It is a comma-separated list of items. Each item has a name, a colon
---- and the value of that item:
+--- and the value of that item: `E1511`
---
--- item default Used for ~
--- stl ' ' statusline of the current window
@@ -2238,7 +2238,7 @@ vim.bo.ft = vim.bo.filetype
---
--- For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
--- single-byte and multibyte characters are supported. But double-width
---- characters are not supported.
+--- characters are not supported. `E1512`
---
--- The highlighting used for these items:
--- item highlight group ~
@@ -3829,7 +3829,7 @@ vim.o.list = false
vim.wo.list = vim.o.list
--- Strings to use in 'list' mode and for the `:list` command. It is a
---- comma-separated list of string settings.
+--- comma-separated list of string settings. *E1511*
---
--- *lcs-eol*
--- eol:c Character to show at the end of each line. When
@@ -3921,7 +3921,7 @@ vim.wo.list = vim.o.list
--- omitted.
---
--- The characters ':' and ',' should not be used. UTF-8 characters can
---- be used. All characters must be single width.
+--- be used. All characters must be single width. *E1512*
---
--- Each character can be specified as hex:
---
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index c7a1e8ebd3..03a1fe9a2f 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -180,10 +180,8 @@ local all_namespaces = {}
---@return vim.diagnostic.Severity?
local function to_severity(severity)
if type(severity) == 'string' then
- return assert(
- M.severity[string.upper(severity)],
- string.format('Invalid severity: %s', severity)
- )
+ assert(M.severity[string.upper(severity)], string.format('Invalid severity: %s', severity))
+ return M.severity[string.upper(severity)]
end
return severity
end
diff --git a/runtime/lua/vim/glob.lua b/runtime/lua/vim/glob.lua
index 49d6f555da..764200dd36 100644
--- a/runtime/lua/vim/glob.lua
+++ b/runtime/lua/vim/glob.lua
@@ -77,7 +77,8 @@ function M.to_lpeg(pattern)
})
local lpeg_pattern = p:match(pattern) --[[@as vim.lpeg.Pattern?]]
- return assert(lpeg_pattern, 'Invalid glob')
+ assert(lpeg_pattern, 'Invalid glob')
+ return lpeg_pattern
end
return M
diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua
index a63d5ba565..d720745110 100644
--- a/runtime/lua/vim/iter.lua
+++ b/runtime/lua/vim/iter.lua
@@ -181,7 +181,7 @@ end
--- local bufs = vim.iter(vim.api.nvim_list_bufs()):filter(vim.api.nvim_buf_is_loaded)
--- ```
---
----@param f fun(...):bool Takes all values returned from the previous stage
+---@param f fun(...):boolean Takes all values returned from the previous stage
--- in the pipeline and returns false or nil if the
--- current iterator element should be removed.
---@return Iter
@@ -884,7 +884,7 @@ end
--- Returns true if any of the items in the iterator match the given predicate.
---
----@param pred fun(...):bool Predicate function. Takes all values returned from the previous
+---@param pred fun(...):boolean Predicate function. Takes all values returned from the previous
--- stage in the pipeline as arguments and returns true if the
--- predicate matches.
function Iter.any(self, pred)
@@ -908,7 +908,7 @@ end
--- Returns true if all items in the iterator match the given predicate.
---
----@param pred fun(...):bool Predicate function. Takes all values returned from the previous
+---@param pred fun(...):boolean Predicate function. Takes all values returned from the previous
--- stage in the pipeline as arguments and returns true if the
--- predicate matches.
function Iter.all(self, pred)
@@ -1106,7 +1106,7 @@ end
---
---@see |Iter:filter()|
---
----@param f fun(...):bool Filter function. Accepts the current iterator or table values as
+---@param f fun(...):boolean Filter function. Accepts the current iterator or table values as
--- arguments and returns true if those values should be kept in the
--- final table
---@param src table|function Table or iterator function to filter
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index a02a93d559..f3448209ba 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -488,8 +488,7 @@ end
--- See |vim.lsp.start_client()| for all available options. The most important are:
---
--- - `name` arbitrary name for the LSP client. Should be unique per language server.
---- - `cmd` command (in list form) used to start the language server. Must be absolute, or found on
---- `$PATH`. Shell constructs like `~` are not expanded.
+--- - `cmd` command string[] or function, described at |vim.lsp.start_client()|.
--- - `root_dir` path to the project root. By default this is used to decide if an existing client
--- should be re-used. The example above uses |vim.fs.find()| and |vim.fs.dirname()| to detect the
--- root by traversing the file system upwards starting from the current directory until either
@@ -666,13 +665,13 @@ end
--- Field `cmd` in {config} is required.
---
---@param config (lsp.ClientConfig) Configuration for the server:
---- - cmd: (string[]|fun(dispatchers: table):table) command a list of
---- strings treated like |jobstart()|. The command must launch the language server
---- process. `cmd` can also be a function that creates an RPC client.
---- The function receives a dispatchers table and must return a table with the
---- functions `request`, `notify`, `is_closing` and `terminate`
---- See |vim.lsp.rpc.request()| and |vim.lsp.rpc.notify()|
---- For TCP there is a built-in rpc client factory: |vim.lsp.rpc.connect()|
+--- - cmd: (string[]|fun(dispatchers: table):table) command string[] that launches the language
+--- server (treated as in |jobstart()|, must be absolute or on `$PATH`, shell constructs like
+--- "~" are not expanded), or function that creates an RPC client. Function receives
+--- a `dispatchers` table and returns a table with member functions `request`, `notify`,
+--- `is_closing` and `terminate`.
+--- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|.
+--- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
---
--- - cmd_cwd: (string, default=|getcwd()|) Directory to launch
--- the `cmd` process. Not related to `root_dir`.
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua
index ce1680549e..4816b873ba 100644
--- a/runtime/lua/vim/lsp/inlay_hint.lua
+++ b/runtime/lua/vim/lsp/inlay_hint.lua
@@ -368,7 +368,13 @@ function M.is_enabled(bufnr)
return bufstates[bufnr] and bufstates[bufnr].enabled or false
end
---- Enable/disable/toggle inlay hints for a buffer
+--- Enables or disables inlay hints for a buffer.
+---
+--- To "toggle", pass the inverse of `is_enabled()`:
+---
+--- ```lua
+--- vim.lsp.inlay_hint.enable(0, not vim.lsp.inlay_hint.is_enabled())
+--- ```
---
--- @param bufnr (integer|nil) Buffer handle, or 0 or nil for current
--- @param enable (boolean|nil) true/nil to enable, false to disable
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index a249a10f47..971c4449e8 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -757,6 +757,11 @@ end)
---@param alias string language or filetype name
---@return string? # resolved parser name
local function resolve_lang(alias)
+ -- validate that `alias` is a legal language
+ if not (alias and alias:match('[%w_]+') == alias) then
+ return
+ end
+
if has_parser(alias) then
return alias
end
diff --git a/runtime/syntax/i3config.vim b/runtime/syntax/i3config.vim
index d4512525f9..8131639a11 100644
--- a/runtime/syntax/i3config.vim
+++ b/runtime/syntax/i3config.vim
@@ -2,8 +2,8 @@
" Language: i3 config file
" Original Author: Josef Litos (JosefLitos/i3config.vim)
" Maintainer: Quentin Hibon (github user hiqua)
-" Version: 1.0.0
-" Last Change: 2023-11-11
+" Version: 1.0.2
+" Last Change: 2023-12-28
" References:
" http://i3wm.org/docs/userguide.html#configuring
@@ -137,8 +137,7 @@ syn match i3ConfigIpcKeyword /ipc-socket/ contained
syn match i3ConfigParamLine /^ipc-socket .*$/ contains=i3ConfigIpcKeyword
" 4.24 Focus follows mouse
-syn keyword i3ConfigFocusFollowsMouseOpts always contained
-syn match i3ConfigKeyword /^focus_follows_mouse \(yes\|no\|always\)$/ contains=i3ConfigBoolean,i3ConfigFocusFollowsMouseOpts
+syn match i3ConfigKeyword /^focus_follows_mouse \(yes\|no\)$/ contains=i3ConfigBoolean
" 4.25 Mouse warping
syn keyword i3ConfigMouseWarpingOpts output container none contained
@@ -298,7 +297,6 @@ hi def link i3ConfigWorkspaceDir i3ConfigOption
hi def link i3ConfigDotOperator i3ConfigOperator
hi def link i3ConfigClientOpts i3ConfigOption
hi def link i3ConfigIpcKeyword i3ConfigKeyword
-hi def link i3ConfigFocusFollowsMouseOpts i3ConfigOption
hi def link i3ConfigMouseWarpingOpts i3ConfigOption
hi def link i3ConfigPopupFullscreenOpts i3ConfigOption
hi def link i3ConfigFocusWrappingOpts i3ConfigOption
diff --git a/runtime/syntax/swayconfig.vim b/runtime/syntax/swayconfig.vim
index 7b1c889d6d..69fe26d370 100644
--- a/runtime/syntax/swayconfig.vim
+++ b/runtime/syntax/swayconfig.vim
@@ -2,8 +2,8 @@
" Language: sway config file
" Original Author: Josef Litos (JosefLitos/i3config.vim)
" Maintainer: James Eapen <james.eapen@vai.org>
-" Version: 1.0.0
-" Last Change: 2023-09-14
+" Version: 1.0.2
+" Last Change: 2023-12-28
" References:
" http://i3wm.org/docs/userguide.html#configuring
@@ -43,6 +43,12 @@ syn region swayConfigExecBlock start=/exec\(_always\)\? {/ end=/^}$/ contains=i3
syn keyword swayConfigFloatingModifierOpts normal inverse contained
syn match i3ConfigKeyword /^floating_modifier [$a-zA-Z0-9+]\+ \(normal\|inverse\)$/ contains=i3ConfigVariable,i3ConfigBindModkey,swayConfigFloatingModifierOpts
+syn keyword swayConfigSmartGapsOpts toggle contained
+syn match i3ConfigKeyword /^smart_gaps toggle$/ contains=i3ConfigSmartGapOpts,i3ConfigBoolean,swayConfigSmartGapsOpts
+
+syn keyword swayConfigFocusFollowsMouseOpts always contained
+syn match i3ConfigKeyword /^focus_follows_mouse always$/ contains=i3ConfigBoolean,swayConfigFocusFollowsMouseOpts
+
syn match i3ConfigKeyword /^hide_edge_borders --i3 \w*$/ contains=i3ConfigEdgeKeyword,i3ConfigShParam
syn keyword i3ConfigBarOpts swaybar_command gaps height pango_markup status_edge_padding status_padding wrap_scroll tray_bindcode tray_bindsym icon_theme contained
@@ -118,7 +124,9 @@ syn region swayConfigOutput start=/^output/ skip=/\\$/ end=/$/ contains=swayCon
syn region swayConfigOutput start=/^output .* {$/ end=/}$/ contains=swayConfigOutputKeyword,swayConfigOutputMode,swayConfigOutputOpts,swayConfigOutputOptVals,i3ConfigVariable,i3ConfigNumber,i3ConfigString,i3ConfigColor,i3ConfigBoolean,swayConfigDeviceOps,i3ConfigParen keepend extend
" Define the highlighting.
+hi def link swayConfigSmartGapsOpts i3ConfigOption
hi def link swayConfigFloatingModifierOpts i3ConfigOption
+hi def link swayConfigFocusFollowsMouseOpts i3ConfigOption
hi def link swayConfigBindKeyword i3ConfigBindKeyword
hi def link swayConfigXOpt i3ConfigOption
hi def link swayConfigInhibitKeyword i3ConfigCommand
diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua
index 49417e72bb..5986a399d9 100644
--- a/scripts/gen_help_html.lua
+++ b/scripts/gen_help_html.lua
@@ -1123,10 +1123,8 @@ function M._test()
'if "expected" is given, "actual" is also required'
)
if expected then
- return assert(
- cond,
- ('expected %s, got: %s'):format(vim.inspect(expected), vim.inspect(actual))
- )
+ assert(cond, ('expected %s, got: %s'):format(vim.inspect(expected), vim.inspect(actual)))
+ return cond
else
return assert(cond)
end
diff --git a/src/nvim/README.md b/src/nvim/README.md
index b264c918b6..9ef39cc90f 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -255,6 +255,12 @@ region is repainted internally. To also highlight excess internal redraws, use
- http://bazaar.launchpad.net/~libvterm/libvterm/trunk/view/head:/doc/seqs.txt
- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+Data structures
+---------------
+
+Buffer text is stored as a tree of line segments, defined in [memline.c](https://github.com/neovim/neovim/blob/v0.9.5/src/nvim/memline.c#L8-L35).
+The central idea is found in [ml_find_line](https://github.com/neovim/neovim/blob/v0.9.5/src/nvim/memline.c#L2800).
+
Nvim lifecycle
--------------
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index b44158c890..a385161beb 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -1302,9 +1302,11 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
}
aco->save_curwin_handle = curwin->handle;
- aco->save_curbuf = curbuf;
aco->save_prevwin_handle = prevwin == NULL ? 0 : prevwin->handle;
aco->save_State = State;
+ if (bt_prompt(curbuf)) {
+ aco->save_prompt_insert = curbuf->b_prompt_insert;
+ }
if (win != NULL) {
// There is a window for "buf" in the current tab page, make it the
@@ -1417,6 +1419,9 @@ win_found:
curbuf = curwin->w_buffer;
// May need to restore insert mode for a prompt buffer.
entering_window(curwin);
+ if (bt_prompt(curbuf)) {
+ curbuf->b_prompt_insert = aco->save_prompt_insert;
+ }
prevwin = win_find_by_handle(aco->save_prevwin_handle);
vars_clear(&awp->w_vars->dv_hashtab); // free all w: variables
diff --git a/src/nvim/autocmd_defs.h b/src/nvim/autocmd_defs.h
index d1f1e16e1a..6535f8a7ea 100644
--- a/src/nvim/autocmd_defs.h
+++ b/src/nvim/autocmd_defs.h
@@ -14,7 +14,6 @@
/// Struct to save values in before executing autocommands for a buffer that is
/// not the current buffer.
typedef struct {
- buf_T *save_curbuf; ///< saved curbuf
int use_aucmd_win_idx; ///< index in aucmd_win[] if >= 0
handle_T save_curwin_handle; ///< ID of saved curwin
handle_T new_curwin_handle; ///< ID of new curwin
@@ -23,6 +22,7 @@ typedef struct {
char *globaldir; ///< saved value of globaldir
bool save_VIsual_active; ///< saved VIsual_active
int save_State; ///< saved State
+ int save_prompt_insert; ///< saved b_prompt_insert
} aco_save_T;
typedef struct {
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index e8c41cb608..cead63b88d 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -61,10 +61,10 @@
/// structure with variables passed between win_line() and other functions
typedef struct {
- linenr_T lnum; ///< line number to be drawn
- foldinfo_T foldinfo; ///< fold info for this line
+ const linenr_T lnum; ///< line number to be drawn
+ const foldinfo_T foldinfo; ///< fold info for this line
- int startrow; ///< first row in the window to be drawn
+ const int startrow; ///< first row in the window to be drawn
int row; ///< row in the window, excl w_winrow
colnr_T vcol; ///< virtual column, before wrapping
@@ -901,6 +901,26 @@ static void fix_for_boguscols(winlinevars_T *wlv)
wlv->boguscols = 0;
}
+static int get_rightmost_vcol(win_T *wp, const int *color_cols)
+{
+ int ret = 0;
+
+ if (wp->w_p_cuc) {
+ ret = wp->w_virtcol;
+ }
+
+ if (color_cols) {
+ // determine rightmost colorcolumn to possibly draw
+ for (int i = 0; color_cols[i] >= 0; i++) {
+ if (ret < color_cols[i]) {
+ ret = color_cols[i];
+ }
+ }
+ }
+
+ return ret;
+}
+
/// Display line "lnum" of window "wp" on the screen.
/// wp->w_virtcol needs to be valid.
///
@@ -918,11 +938,7 @@ static void fix_for_boguscols(winlinevars_T *wlv)
int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, spellvars_T *spv,
foldinfo_T foldinfo)
{
- winlinevars_T wlv; // variables passed between functions
-
colnr_T vcol_prev = -1; // "wlv.vcol" of previous character
- char *line; // current line
- char *ptr; // current position in "line"
ScreenGrid *grid = &wp->w_grid; // grid specific to the window
static char *at_end_str = ""; // used for p_extra when displaying curwin->w_p_lcs_chars.eol
@@ -936,8 +952,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
int fromcol_prev = -2; // start of inverting after cursor
bool noinvcur = false; // don't invert the cursor
bool lnum_in_visual_area = false;
- pos_T pos;
- ptrdiff_t v;
bool attr_pri = false; // char_attr has priority
bool area_highlighting = false; // Visual or incsearch highlighting in this line
@@ -948,7 +962,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
int decor_attr = 0; // attributes desired by syntax and extmarks
bool has_syntax = false; // this buffer has syntax highl.
int folded_attr = 0; // attributes for folded line
- int save_did_emsg;
int eol_hl_off = 0; // 1 if highlighted char after EOL
#define SPWORDLEN 150
char nextline[SPWORDLEN * 2]; // text with start of the next line
@@ -967,8 +980,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
int change_end = -1; // last col of changed area
bool in_multispace = false; // in multiple consecutive spaces
int multispace_pos = 0; // position in lcs-multispace string
- int line_attr_save;
- int line_attr_lowprio_save;
bool search_attr_from_match = false; // if search_attr is from :match
bool has_decor = false; // this buffer has decoration
@@ -1005,16 +1016,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
assert(startrow < endrow);
- CLEAR_FIELD(wlv);
-
- wlv.lnum = lnum;
- wlv.foldinfo = foldinfo;
- wlv.startrow = startrow;
- wlv.row = startrow;
- wlv.fromcol = -10;
- wlv.tocol = MAXCOL;
- wlv.vcol_sbr = -1;
- wlv.old_boguscols = 0;
+ // variables passed between functions
+ winlinevars_T wlv = {
+ .lnum = lnum,
+ .foldinfo = foldinfo,
+ .startrow = startrow,
+ .row = startrow,
+ .fromcol = -10,
+ .tocol = MAXCOL,
+ .vcol_sbr = -1,
+ .old_boguscols = 0,
+ };
buf_T *buf = wp->w_buffer;
const bool end_fill = (lnum == buf->b_ml.ml_line_count + 1);
@@ -1027,7 +1039,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
&& !has_fold && !end_fill) {
// Prepare for syntax highlighting in this line. When there is an
// error, stop syntax highlighting.
- save_did_emsg = did_emsg;
+ int save_did_emsg = did_emsg;
did_emsg = false;
syntax_start(wp, lnum);
if (did_emsg) {
@@ -1095,7 +1107,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
} else if (bot->col == MAXCOL) {
wlv.tocol = MAXCOL;
} else {
- pos = *bot;
+ pos_T pos = *bot;
if (*p_sel == 'e') {
getvvcol(wp, &pos, (colnr_T *)&wlv.tocol, NULL, NULL);
} else {
@@ -1130,8 +1142,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
wlv.fromcol = 0;
}
if (lnum == curwin->w_cursor.lnum + search_match_lines) {
- pos.lnum = lnum;
- pos.col = search_match_endcol;
+ pos_T pos = {
+ .lnum = lnum,
+ .col = search_match_endcol,
+ };
getvcol(curwin, &pos, (colnr_T *)&wlv.tocol, NULL, NULL);
}
// do at least one character; happens when past end of line
@@ -1224,10 +1238,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
area_highlighting = true;
}
- if (cul_screenline) {
- line_attr_save = wlv.line_attr;
- line_attr_lowprio_save = wlv.line_attr_lowprio;
- }
+ int line_attr_save = wlv.line_attr;
+ int line_attr_lowprio_save = wlv.line_attr_lowprio;
if (spv->spv_has_spell && col_rows == 0) {
// Prepare for spell checking.
@@ -1252,14 +1264,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// Trick: skip a few chars for C/shell/Vim comments
nextline[SPWORDLEN] = NUL;
if (lnum < wp->w_buffer->b_ml.ml_line_count) {
- line = ml_get_buf(wp->w_buffer, lnum + 1);
+ char *line = ml_get_buf(wp->w_buffer, lnum + 1);
spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
}
assert(!end_fill);
- line = ml_get_buf(wp->w_buffer, lnum);
+ char *line = ml_get_buf(wp->w_buffer, lnum);
// If current line is empty, check first word in next line for capital.
- ptr = skipwhite(line);
+ char *ptr = skipwhite(line);
if (*ptr == NUL) {
spv->spv_cap_col = 0;
spv->spv_capcol_lnum = lnum + 1;
@@ -1274,25 +1286,27 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
nextlinecol = MAXCOL;
nextline_idx = 0;
} else {
- v = (ptrdiff_t)strlen(line);
- if (v < SPWORDLEN) {
+ const size_t line_len = strlen(line);
+ if (line_len < SPWORDLEN) {
// Short line, use it completely and append the start of the
// next line.
nextlinecol = 0;
- memmove(nextline, line, (size_t)v);
- STRMOVE(nextline + v, nextline + SPWORDLEN);
- nextline_idx = (int)v + 1;
+ memmove(nextline, line, line_len);
+ STRMOVE(nextline + line_len, nextline + SPWORDLEN);
+ nextline_idx = (int)line_len + 1;
} else {
// Long line, use only the last SPWORDLEN bytes.
- nextlinecol = (int)v - SPWORDLEN;
+ nextlinecol = (int)line_len - SPWORDLEN;
memmove(nextline, line + nextlinecol, SPWORDLEN);
nextline_idx = SPWORDLEN + 1;
}
}
}
- line = end_fill ? "" : ml_get_buf(wp->w_buffer, lnum);
- ptr = line;
+ // current line
+ char *line = end_fill ? "" : ml_get_buf(wp->w_buffer, lnum);
+ // current position in "line"
+ char *ptr = line;
colnr_T trailcol = MAXCOL; // start of trailing spaces
colnr_T leadcol = 0; // start of leading spaces
@@ -1316,20 +1330,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
// first character to be displayed.
- if (wp->w_p_wrap) {
- v = startrow == 0 ? wp->w_skipcol : 0;
- } else {
- v = wp->w_leftcol;
- }
- if (v > 0 && col_rows == 0) {
+ const int start_col = wp->w_p_wrap
+ ? (startrow == 0 ? wp->w_skipcol : 0)
+ : wp->w_leftcol;
+
+ if (start_col > 0 && col_rows == 0) {
char *prev_ptr = ptr;
chartabsize_T cts;
int charsize = 0;
int head = 0;
init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, ptr);
- cts.cts_max_head_vcol = (int)v;
- while (cts.cts_vcol < v && *cts.cts_ptr != NUL) {
+ cts.cts_max_head_vcol = start_col;
+ while (cts.cts_vcol < start_col && *cts.cts_ptr != NUL) {
head = 0;
charsize = win_lbr_chartabsize(&cts, &head);
cts.cts_vcol += charsize;
@@ -1365,22 +1378,22 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// - 'virtualedit' is set, or
// - the visual mode is active,
// the end of the line may be before the start of the displayed part.
- if (wlv.vcol < v && (wp->w_p_cuc
- || wlv.color_cols
- || virtual_active()
- || (VIsual_active && wp->w_buffer == curwin->w_buffer))) {
- wlv.vcol = (colnr_T)v;
+ if (wlv.vcol < start_col && (wp->w_p_cuc
+ || wlv.color_cols
+ || virtual_active()
+ || (VIsual_active && wp->w_buffer == curwin->w_buffer))) {
+ wlv.vcol = start_col;
}
// Handle a character that's not completely on the screen: Put ptr at
// that character but skip the first few screen characters.
- if (wlv.vcol > v) {
+ if (wlv.vcol > start_col) {
wlv.vcol -= charsize;
ptr = prev_ptr;
}
- if (v > wlv.vcol) {
- wlv.skip_cells = (int)v - wlv.vcol - head;
+ if (start_col > wlv.vcol) {
+ wlv.skip_cells = start_col - wlv.vcol - head;
}
// Adjust for when the inverted text is before the screen,
@@ -1398,14 +1411,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// When spell checking a word we need to figure out the start of the
// word and if it's badly spelled or not.
if (spv->spv_has_spell) {
- size_t len;
colnr_T linecol = (colnr_T)(ptr - line);
hlf_T spell_hlf = HLF_COUNT;
- pos = wp->w_cursor;
+ pos_T pos = wp->w_cursor;
wp->w_cursor.lnum = lnum;
wp->w_cursor.col = linecol;
- len = spell_move_to(wp, FORWARD, true, true, &spell_hlf);
+ size_t len = spell_move_to(wp, FORWARD, true, true, &spell_hlf);
// spell_move_to() may call ml_get() and make "line" invalid
line = ml_get_buf(wp->w_buffer, lnum);
@@ -1455,8 +1467,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
}
if (col_rows == 0 && !has_fold && !end_fill) {
- v = ptr - line;
- area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v,
+ const int v = (int)(ptr - line);
+ area_highlighting |= prepare_search_hl_line(wp, lnum, v,
&line, &screen_search_hl, &search_attr,
&search_attr_from_match);
ptr = line + v; // "line" may have been updated
@@ -1513,7 +1525,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
if (sign_num_attr == 0) {
statuscol.num_attr = get_line_number_attr(wp, &wlv);
}
- v = ptr - line;
+ const int v = (int)(ptr - line);
draw_statuscol(wp, &wlv, lnum, wlv.row - startrow - wlv.filler_lines, &statuscol);
if (wp->w_redr_statuscol) {
break;
@@ -1670,8 +1682,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// Check for start/end of 'hlsearch' and other matches.
// After end, check for start/end of next match.
// When another match, have to check for start again.
- v = ptr - line;
- search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, &screen_search_hl,
+ const int v = (int)(ptr - line);
+ search_attr = update_search_hl(wp, lnum, v, &line, &screen_search_hl,
&has_match_conc, &match_conc, lcs_eol_todo,
&on_last_col, &search_attr_from_match);
ptr = line + v; // "line" may have been changed
@@ -1734,7 +1746,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
}
if (draw_folded && wlv.n_extra == 0 && wlv.col == win_col_offset) {
- v = ptr - line;
+ const int v = (int)(ptr - line);
linenr_T lnume = lnum + foldinfo.fi_lines - 1;
memset(buf_fold, ' ', FOLD_TEXT_LEN);
wlv.p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold, &fold_vt);
@@ -1839,7 +1851,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// skip writing the buffer line itself
mb_schar = NUL;
} else {
- char *prev_ptr = ptr;
+ const char *prev_ptr = ptr;
// first byte of next char
int c0 = (uint8_t)(*ptr);
@@ -1917,20 +1929,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
decor_attr = 0;
if (extra_check) {
- bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0;
+ const bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0;
bool can_spell = !no_plain_buffer;
// Get extmark and syntax attributes, unless still at the start of the line
// (double-wide char that doesn't fit).
- v = ptr - line;
+ const int v = (int)(ptr - line);
+ const ptrdiff_t prev_v = prev_ptr - line;
if (has_syntax && v > 0) {
// Get the syntax attribute for the character. If there
// is an error, disable syntax highlighting.
- save_did_emsg = did_emsg;
+ int save_did_emsg = did_emsg;
did_emsg = false;
- decor_attr = get_syntax_attr((colnr_T)v - 1,
- spv->spv_has_spell ? &can_spell : NULL, false);
+ decor_attr = get_syntax_attr(v - 1, spv->spv_has_spell ? &can_spell : NULL, false);
if (did_emsg) {
wp->w_s->b_syn_error = true;
@@ -1947,6 +1959,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// have made it invalid.
line = ml_get_buf(wp->w_buffer, lnum);
ptr = line + v;
+ prev_ptr = line + prev_v;
// no concealing past the end of the line, it interferes
// with line highlighting.
@@ -1980,28 +1993,28 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// Only do this when there is no syntax highlighting, the
// @Spell cluster is not used or the current syntax item
// contains the @Spell cluster.
- v = ptr - line;
- if (spv->spv_has_spell && v >= word_end && v > cur_checked_col) {
+ int v1 = (int)(ptr - line);
+ if (spv->spv_has_spell && v1 >= word_end && v1 > cur_checked_col) {
spell_attr = 0;
// do not calculate cap_col at the end of the line or when
// only white space is following
if (mb_schar != 0 && (*skipwhite(prev_ptr) != NUL) && can_spell) {
char *p;
hlf_T spell_hlf = HLF_COUNT;
- v -= mb_l - 1;
+ v1 -= mb_l - 1;
// Use nextline[] if possible, it has the start of the
// next line concatenated.
if ((prev_ptr - line) - nextlinecol >= 0) {
p = nextline + ((prev_ptr - line) - nextlinecol);
} else {
- p = prev_ptr;
+ p = (char *)prev_ptr;
}
spv->spv_cap_col -= (int)(prev_ptr - line);
size_t tmplen = spell_check(wp, p, &spell_hlf, &spv->spv_cap_col, spv->spv_unchanged);
assert(tmplen <= INT_MAX);
int len = (int)tmplen;
- word_end = (int)v + len;
+ word_end = v1 + len;
// In Insert mode only highlight a word that
// doesn't touch the cursor.
@@ -2448,8 +2461,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
if (mb_schar == NUL && eol_hl_off == 0) {
// flag to indicate whether prevcol equals startcol of search_hl or
// one of the matches
- bool prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl,
- (colnr_T)(ptr - line) - 1);
+ const bool prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl,
+ (colnr_T)(ptr - line) - 1);
// Invert at least one char, used for Visual and empty line or
// highlight match at end of line. If it's beyond the last
@@ -2485,10 +2498,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
&wlv.char_attr);
}
- int eol_attr = wlv.char_attr;
- if (wlv.cul_attr) {
- eol_attr = hl_combine_attr(wlv.cul_attr, eol_attr);
- }
+ const int eol_attr = wlv.cul_attr
+ ? hl_combine_attr(wlv.cul_attr, wlv.char_attr)
+ : wlv.char_attr;
+
linebuf_attr[wlv.off] = eol_attr;
linebuf_vcol[wlv.off] = MAXCOL;
wlv.col++;
@@ -2501,15 +2514,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// At end of the text line.
if (mb_schar == NUL) {
// Highlight 'cursorcolumn' & 'colorcolumn' past end of the line.
- if (wp->w_p_wrap) {
- v = wlv.startrow == 0 ? wp->w_skipcol : 0;
- } else {
- v = wp->w_leftcol;
- }
// check if line ends before left margin
- if (wlv.vcol < v + wlv.col - win_col_off(wp)) {
- wlv.vcol = (colnr_T)v + wlv.col - win_col_off(wp);
+ if (wlv.vcol < start_col + wlv.col - win_col_off(wp)) {
+ wlv.vcol = start_col + wlv.col - win_col_off(wp);
}
// Get rid of the boguscols now, we want to draw until the right
// edge for 'cursorcolumn'.
@@ -2521,7 +2529,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
bool has_virttext = false;
// Make sure alignment is the same regardless
// if listchars=eol:X is used or not.
- int eol_skip = (lcs_eol_todo && eol_hl_off == 0 ? 1 : 0);
+ const int eol_skip = (lcs_eol_todo && eol_hl_off == 0 ? 1 : 0);
if (has_decor) {
has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip);
@@ -2529,37 +2537,23 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
if (((wp->w_p_cuc
&& wp->w_virtcol >= vcol_hlc(wlv) - eol_hl_off
- && wp->w_virtcol < grid->cols * (ptrdiff_t)(wlv.row - startrow + 1) + v
+ && wp->w_virtcol < grid->cols * (ptrdiff_t)(wlv.row - startrow + 1) + start_col
&& lnum != wp->w_cursor.lnum)
|| wlv.color_cols || wlv.line_attr_lowprio || wlv.line_attr
|| wlv.diff_hlf != 0 || has_virttext)) {
- int rightmost_vcol = 0;
-
- if (wp->w_p_cuc) {
- rightmost_vcol = wp->w_virtcol;
- }
+ int rightmost_vcol = get_rightmost_vcol(wp, wlv.color_cols);
+ const int cuc_attr = win_hl_attr(wp, HLF_CUC);
+ const int mc_attr = win_hl_attr(wp, HLF_MC);
- if (wlv.color_cols) {
- // determine rightmost colorcolumn to possibly draw
- for (int i = 0; wlv.color_cols[i] >= 0; i++) {
- if (rightmost_vcol < wlv.color_cols[i]) {
- rightmost_vcol = wlv.color_cols[i];
- }
- }
- }
-
- int cuc_attr = win_hl_attr(wp, HLF_CUC);
- int mc_attr = win_hl_attr(wp, HLF_MC);
-
- int diff_attr = 0;
if (wlv.diff_hlf == HLF_TXD) {
wlv.diff_hlf = HLF_CHD;
}
- if (wlv.diff_hlf != 0) {
- diff_attr = win_hl_attr(wp, (int)wlv.diff_hlf);
- }
- int base_attr = hl_combine_attr(wlv.line_attr_lowprio, diff_attr);
+ const int diff_attr = wlv.diff_hlf != 0
+ ? win_hl_attr(wp, (int)wlv.diff_hlf)
+ : 0;
+
+ const int base_attr = hl_combine_attr(wlv.line_attr_lowprio, diff_attr);
if (base_attr || wlv.line_attr || has_virttext) {
rightmost_vcol = INT_MAX;
}
@@ -2808,13 +2802,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
&& wlv.p_extra != at_end_str)
|| (wlv.n_extra != 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL))
|| has_more_inline_virt(&wlv, ptr - line))) {
- bool wrap = wp->w_p_wrap // Wrapping enabled.
- && wlv.filler_todo <= 0 // Not drawing diff filler lines.
- && lcs_eol_todo // Haven't printed the lcs_eol character.
- && wlv.row != endrow - 1 // Not the last line being displayed.
- && (grid->cols == Columns // Window spans the width of the screen,
- || ui_has(kUIMultigrid)) // or has dedicated grid.
- && !wp->w_p_rl; // Not right-to-left.
+ const bool wrap = wp->w_p_wrap // Wrapping enabled.
+ && wlv.filler_todo <= 0 // Not drawing diff filler lines.
+ && lcs_eol_todo // Haven't printed the lcs_eol character.
+ && wlv.row != endrow - 1 // Not the last line being displayed.
+ && (grid->cols == Columns // Window spans the width of the screen,
+ || ui_has(kUIMultigrid)) // or has dedicated grid.
+ && !wp->w_p_rl; // Not right-to-left.
int draw_col = wlv.col - wlv.boguscols;
if (virt_line_offset >= 0) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index d10214b48f..2c5c291216 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -2277,6 +2277,7 @@ static buf_T *cmdpreview_open_buf(void)
///
/// @return Pointer to command preview window if succeeded, NULL if failed.
static win_T *cmdpreview_open_win(buf_T *cmdpreview_buf)
+ FUNC_ATTR_NONNULL_ALL
{
win_T *save_curwin = curwin;
@@ -2548,10 +2549,10 @@ static bool cmdpreview_may_show(CommandLineState *s)
cmdpreview_prepare(&cpinfo);
// Open preview buffer if inccommand=split.
- if (!icm_split) {
- cmdpreview_bufnr = 0;
- } else if ((cmdpreview_buf = cmdpreview_open_buf()) == NULL) {
- abort();
+ if (icm_split && (cmdpreview_buf = cmdpreview_open_buf()) == NULL) {
+ // Failed to create preview buffer, so disable preview.
+ set_string_option_direct(kOptInccommand, "nosplit", 0, SID_NONE);
+ icm_split = false;
}
// Setup preview namespace if it's not already set.
if (!cmdpreview_ns) {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 68ddb95e38..0185b62daa 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1703,10 +1703,10 @@ static void didset_options2(void)
highlight_changed();
// Parse default for 'fillchars'.
- set_chars_option(curwin, curwin->w_p_fcs, kFillchars, true);
+ set_chars_option(curwin, curwin->w_p_fcs, kFillchars, true, NULL, 0);
// Parse default for 'listchars'.
- set_chars_option(curwin, curwin->w_p_lcs, kListchars, true);
+ set_chars_option(curwin, curwin->w_p_lcs, kListchars, true, NULL, 0);
// Parse default for 'wildmode'.
check_opt_wim();
@@ -4998,8 +4998,8 @@ void didset_window_options(win_T *wp, bool valid_cursor)
check_colorcolumn(wp);
briopt_check(wp);
fill_culopt_flags(NULL, wp);
- set_chars_option(wp, wp->w_p_fcs, kFillchars, true);
- set_chars_option(wp, wp->w_p_lcs, kListchars, true);
+ set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0);
+ set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0);
parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
check_blending(wp);
set_winbar_win(wp, false, valid_cursor);
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 65f6bc76ba..db33c94be3 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2818,7 +2818,7 @@ return {
Characters to fill the statuslines, vertical separators and special
lines in the window.
It is a comma-separated list of items. Each item has a name, a colon
- and the value of that item:
+ and the value of that item: |E1511|
item default Used for ~
stl ' ' statusline of the current window
@@ -2856,7 +2856,7 @@ return {
<
For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
single-byte and multibyte characters are supported. But double-width
- characters are not supported.
+ characters are not supported. |E1512|
The highlighting used for these items:
item highlight group ~
@@ -4879,7 +4879,7 @@ return {
deny_duplicates = true,
desc = [=[
Strings to use in 'list' mode and for the |:list| command. It is a
- comma-separated list of string settings.
+ comma-separated list of string settings. *E1511*
*lcs-eol*
eol:c Character to show at the end of each line. When
@@ -4958,7 +4958,7 @@ return {
omitted.
The characters ':' and ',' should not be used. UTF-8 characters can
- be used. All characters must be single width.
+ be used. All characters must be single width. *E1512*
Each character can be specified as hex: >vim
set listchars=eol:\\x24
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index cef9443e63..e37569ee56 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -62,6 +62,10 @@ static const char e_backupext_and_patchmode_are_equal[]
= N_("E589: 'backupext' and 'patchmode' are equal");
static const char e_showbreak_contains_unprintable_or_wide_character[]
= N_("E595: 'showbreak' contains unprintable or wide character");
+static const char e_wrong_number_of_characters_for_field_str[]
+ = N_("E1511: Wrong number of characters for field \"%s\"");
+static const char e_wrong_character_width_for_field_str[]
+ = N_("E1512: Wrong character width for field \"%s\"");
static char *(p_ambw_values[]) = { "single", "double", NULL };
static char *(p_bg_values[]) = { "light", "dark", NULL };
@@ -879,14 +883,16 @@ int expand_set_casemap(optexpand_T *args, int *numMatches, char ***matches)
/// The global 'listchars' or 'fillchars' option is changed.
static const char *did_set_global_chars_option(win_T *win, char *val, CharsOption what,
- int opt_flags)
+ int opt_flags, char *errbuf, size_t errbuflen)
{
const char *errmsg = NULL;
char **local_ptr = (what == kListchars) ? &win->w_p_lcs : &win->w_p_fcs;
// only apply the global value to "win" when it does not have a
// local value
- errmsg = set_chars_option(win, val, what, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL));
+ errmsg = set_chars_option(win, val, what,
+ **local_ptr == NUL || !(opt_flags & OPT_GLOBAL),
+ errbuf, errbuflen);
if (errmsg != NULL) {
return errmsg;
}
@@ -904,7 +910,7 @@ static const char *did_set_global_chars_option(win_T *win, char *val, CharsOptio
// here, so ignore the return value.
char *opt = (what == kListchars) ? wp->w_p_lcs : wp->w_p_fcs;
if (*opt == NUL) {
- set_chars_option(wp, opt, what, true);
+ set_chars_option(wp, opt, what, true, errbuf, errbuflen);
}
}
@@ -921,13 +927,17 @@ const char *did_set_chars_option(optset_T *args)
const char *errmsg = NULL;
if (varp == &p_lcs) { // global 'listchars'
- errmsg = did_set_global_chars_option(win, *varp, kListchars, args->os_flags);
+ errmsg = did_set_global_chars_option(win, *varp, kListchars, args->os_flags,
+ args->os_errbuf, args->os_errbuflen);
} else if (varp == &p_fcs) { // global 'fillchars'
- errmsg = did_set_global_chars_option(win, *varp, kFillchars, args->os_flags);
+ errmsg = did_set_global_chars_option(win, *varp, kFillchars, args->os_flags,
+ args->os_errbuf, args->os_errbuflen);
} else if (varp == &win->w_p_lcs) { // local 'listchars'
- errmsg = set_chars_option(win, *varp, kListchars, true);
+ errmsg = set_chars_option(win, *varp, kListchars, true,
+ args->os_errbuf, args->os_errbuflen);
} else if (varp == &win->w_p_fcs) { // local 'fillchars'
- errmsg = set_chars_option(win, *varp, kFillchars, true);
+ errmsg = set_chars_option(win, *varp, kFillchars, true,
+ args->os_errbuf, args->os_errbuflen);
}
return errmsg;
@@ -2668,14 +2678,27 @@ static const struct chars_tab lcs_tab[] = {
{ NULL, "leadmultispace", NULL, NULL },
};
+static char *field_value_err(char *errbuf, size_t errbuflen, const char *fmt, const char *field)
+{
+ if (errbuf == NULL) {
+ return "";
+ }
+ vim_snprintf(errbuf, errbuflen, _(fmt), field);
+ return errbuf;
+}
+
/// Handle setting 'listchars' or 'fillchars'.
/// Assume monocell characters
///
-/// @param value points to either the global or the window-local value.
-/// @param what kListchars or kFillchars
-/// @param apply if false, do not store the flags, only check for errors.
+/// @param value points to either the global or the window-local value.
+/// @param what kListchars or kFillchars
+/// @param apply if false, do not store the flags, only check for errors.
+/// @param errbuf buffer for error message, can be NULL if it won't be used.
+/// @param errbuflen size of error buffer.
+///
/// @return error message, NULL if it's OK.
-const char *set_chars_option(win_T *wp, const char *value, CharsOption what, bool apply)
+const char *set_chars_option(win_T *wp, const char *value, CharsOption what, bool apply,
+ char *errbuf, size_t errbuflen)
{
const char *last_multispace = NULL; // Last occurrence of "multispace:"
const char *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
@@ -2736,9 +2759,7 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
int i;
for (i = 0; i < entries; i++) {
const size_t len = strlen(tab[i].name);
- if (!(strncmp(p, tab[i].name, len) == 0
- && p[len] == ':'
- && p[len + 1] != NUL)) {
+ if (!(strncmp(p, tab[i].name, len) == 0 && p[len] == ':')) {
continue;
}
@@ -2751,13 +2772,17 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
while (*s != NUL && *s != ',') {
schar_T c1 = get_encoded_char_adv(&s);
if (c1 == 0) {
- return e_invarg;
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
multispace_len++;
}
if (multispace_len == 0) {
// lcs-multispace cannot be an empty string
- return e_invarg;
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_number_of_characters_for_field_str,
+ tab[i].name);
}
p = s;
} else {
@@ -2782,13 +2807,17 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
while (*s != NUL && *s != ',') {
schar_T c1 = get_encoded_char_adv(&s);
if (c1 == 0) {
- return e_invarg;
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
lead_multispace_len++;
}
if (lead_multispace_len == 0) {
// lcs-leadmultispace cannot be an empty string
- return e_invarg;
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_number_of_characters_for_field_str,
+ tab[i].name);
}
p = s;
} else {
@@ -2805,24 +2834,37 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
}
const char *s = p + len + 1;
+ if (*s == NUL) {
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_number_of_characters_for_field_str,
+ tab[i].name);
+ }
schar_T c1 = get_encoded_char_adv(&s);
if (c1 == 0) {
- return e_invarg;
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
schar_T c2 = 0;
schar_T c3 = 0;
if (tab[i].cp == &lcs_chars.tab2) {
if (*s == NUL) {
- return e_invarg;
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_number_of_characters_for_field_str,
+ tab[i].name);
}
c2 = get_encoded_char_adv(&s);
if (c2 == 0) {
- return e_invarg;
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
if (!(*s == ',' || *s == NUL)) {
c3 = get_encoded_char_adv(&s);
if (c3 == 0) {
- return e_invarg;
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
}
}
@@ -2839,6 +2881,10 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
}
p = s;
break;
+ } else {
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_number_of_characters_for_field_str,
+ tab[i].name);
}
}
@@ -2893,17 +2939,17 @@ char *get_listchars_name(expand_T *xp FUNC_ATTR_UNUSED, int idx)
/// @return an untranslated error message if any of them is invalid, NULL otherwise.
const char *check_chars_options(void)
{
- if (set_chars_option(curwin, p_lcs, kListchars, false) != NULL) {
+ if (set_chars_option(curwin, p_lcs, kListchars, false, NULL, 0) != NULL) {
return e_conflicts_with_value_of_listchars;
}
- if (set_chars_option(curwin, p_fcs, kFillchars, false) != NULL) {
+ if (set_chars_option(curwin, p_fcs, kFillchars, false, NULL, 0) != NULL) {
return e_conflicts_with_value_of_fillchars;
}
FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (set_chars_option(wp, wp->w_p_lcs, kListchars, true) != NULL) {
+ if (set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0) != NULL) {
return e_conflicts_with_value_of_listchars;
}
- if (set_chars_option(wp, wp->w_p_fcs, kFillchars, true) != NULL) {
+ if (set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0) != NULL) {
return e_conflicts_with_value_of_fillchars;
}
}
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 9cd0c64bfe..6b8b73a2a0 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1312,6 +1312,9 @@ void tui_default_colors_set(TUIData *tui, Integer rgb_fg, Integer rgb_bg, Intege
invalidate(tui, 0, tui->grid.height, 0, tui->grid.width);
}
+/// Flushes TUI grid state to a buffer (which is later flushed to the TTY by `flush_buf`).
+///
+/// @see flush_buf
void tui_flush(TUIData *tui)
{
UGrid *grid = &tui->grid;
@@ -2327,6 +2330,9 @@ static size_t flush_buf_end(TUIData *tui, char *buf, size_t len)
return offset;
}
+/// Flushes the rendered buffer to the TTY.
+///
+/// @see tui_flush
static void flush_buf(TUIData *tui)
{
uv_write_t req;
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index d343fb5fa0..d517f07b32 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2389,7 +2389,9 @@ static void u_undoredo(bool undo, bool do_buf_event)
// When text has been changed, possibly the start of the next line
// may have SpellCap that should be removed or it needs to be
// displayed. Schedule the next line for redrawing just in case.
- if (spell_check_window(curwin) && bot <= curbuf->b_ml.ml_line_count) {
+ // Also just in case the line had a sign which needs to be removed.
+ if ((spell_check_window(curwin) || curbuf->b_signs_with_text)
+ && bot <= curbuf->b_ml.ml_line_count) {
redrawWinline(curwin, bot);
}
diff --git a/test/client/msgpack_rpc_stream.lua b/test/client/msgpack_rpc_stream.lua
index 4b4f30e0ec..7131940a58 100644
--- a/test/client/msgpack_rpc_stream.lua
+++ b/test/client/msgpack_rpc_stream.lua
@@ -22,6 +22,9 @@ function Response:send(value, is_error)
self._msgpack_rpc_stream._stream:write(data)
end
+--- @class test.MsgpackRpcStream
+--- @field private _stream test.Stream
+--- @field private __pack table
local MsgpackRpcStream = {}
MsgpackRpcStream.__index = MsgpackRpcStream
diff --git a/test/client/session.lua b/test/client/session.lua
index 86b4ee7103..cf3d8c4f25 100644
--- a/test/client/session.lua
+++ b/test/client/session.lua
@@ -1,6 +1,12 @@
local uv = vim.uv
local MsgpackRpcStream = require('test.client.msgpack_rpc_stream')
+--- @class test.Session
+--- @field private _pending_messages string[]
+--- @field private _msgpack_rpc_stream test.MsgpackRpcStream
+--- @field private _prepare uv.uv_prepare_t
+--- @field private _timer uv.uv_timer_t
+--- @field private _is_running boolean
local Session = {}
Session.__index = Session
if package.loaded['jit'] then
@@ -26,7 +32,7 @@ end
local function coroutine_exec(func, ...)
local args = { ... }
- local on_complete
+ local on_complete --- @type function?
if #args > 0 and type(args[#args]) == 'function' then
-- completion callback
@@ -54,6 +60,8 @@ function Session.new(stream)
}, Session)
end
+--- @param timeout integer?
+--- @return string?
function Session:next_message(timeout)
local function on_request(method, args, response)
table.insert(self._pending_messages, { 'request', method, args, response })
@@ -86,6 +94,10 @@ function Session:notify(method, ...)
self._msgpack_rpc_stream:write(method, { ... })
end
+--- @param method string
+--- @param ... any
+--- @return boolean
+--- @return table
function Session:request(method, ...)
local args = { ... }
local err, result
diff --git a/test/client/uv_stream.lua b/test/client/uv_stream.lua
index 9e9a69e0a1..0540c44eb2 100644
--- a/test/client/uv_stream.lua
+++ b/test/client/uv_stream.lua
@@ -1,18 +1,28 @@
local uv = vim.uv
+--- @class test.Stream
+--- @field write fun(self, data: string|string[])
+--- @field read_start fun(self, cb: fun(chunk: string))
+--- @field read_stop fun(self)
+--- @field close fun(self, signal?: string)
+
+--- @class vim.StdioStream : test.Stream
+--- @field private _in uv.uv_pipe_t
+--- @field private _out uv.uv_pipe_t
local StdioStream = {}
StdioStream.__index = StdioStream
function StdioStream.open()
local self = setmetatable({
- _in = uv.new_pipe(false),
- _out = uv.new_pipe(false),
+ _in = assert(uv.new_pipe(false)),
+ _out = assert(uv.new_pipe(false)),
}, StdioStream)
self._in:open(0)
self._out:open(1)
return self
end
+--- @param data string|string[]
function StdioStream:write(data)
self._out:write(data)
end
@@ -35,11 +45,14 @@ function StdioStream:close()
self._out:close()
end
+--- @class test.SocketStream : test.Stream
+--- @field package _stream_error? string
+--- @field package _socket uv.uv_pipe_t
local SocketStream = {}
SocketStream.__index = SocketStream
function SocketStream.open(file)
- local socket = uv.new_pipe(false)
+ local socket = assert(uv.new_pipe(false))
local self = setmetatable({
_socket = socket,
_stream_error = nil,
@@ -51,7 +64,7 @@ function SocketStream.open(file)
end
function SocketStream.connect(host, port)
- local socket = uv.new_tcp()
+ local socket = assert(uv.new_tcp())
local self = setmetatable({
_socket = socket,
_stream_error = nil,
@@ -96,9 +109,20 @@ function SocketStream:close()
uv.close(self._socket)
end
+--- @class test.ChildProcessStream : test.Stream
+--- @field private _proc uv.uv_process_t
+--- @field private _pid integer
+--- @field private _child_stdin uv.uv_pipe_t
+--- @field private _child_stdout uv.uv_pipe_t
+--- @field status integer
+--- @field signal integer
local ChildProcessStream = {}
ChildProcessStream.__index = ChildProcessStream
+--- @param argv string[]
+--- @param env string[]?
+--- @param io_extra uv.uv_pipe_t?
+--- @return test.ChildProcessStream
function ChildProcessStream.spawn(argv, env, io_extra)
local self = setmetatable({
_child_stdin = uv.new_pipe(false),
@@ -106,13 +130,15 @@ function ChildProcessStream.spawn(argv, env, io_extra)
_exiting = false,
}, ChildProcessStream)
local prog = argv[1]
- local args = {}
+ local args = {} --- @type string[]
for i = 2, #argv do
args[#args + 1] = argv[i]
end
+ --- @diagnostic disable-next-line:missing-fields
self._proc, self._pid = uv.spawn(prog, {
stdio = { self._child_stdin, self._child_stdout, 2, io_extra },
args = args,
+ --- @diagnostic disable-next-line:assign-type-mismatch
env = env,
}, function(status, signal)
self.status = status
diff --git a/test/deprecated.lua b/test/deprecated.lua
deleted file mode 100644
index e30dfcf3ab..0000000000
--- a/test/deprecated.lua
+++ /dev/null
@@ -1,9 +0,0 @@
--- Island of Misfit Toys
-
-local M = {}
-
-function M.redir_exec()
- error('redir_exec is deprecated, use nvim_exec2() or pcall_err()')
-end
-
-return M
diff --git a/test/format_string.lua b/test/format_string.lua
new file mode 100644
index 0000000000..777fb652e8
--- /dev/null
+++ b/test/format_string.lua
@@ -0,0 +1,168 @@
+local luaassert = require('luassert')
+
+local M = {}
+
+local SUBTBL = {
+ '\\000',
+ '\\001',
+ '\\002',
+ '\\003',
+ '\\004',
+ '\\005',
+ '\\006',
+ '\\007',
+ '\\008',
+ '\\t',
+ '\\n',
+ '\\011',
+ '\\012',
+ '\\r',
+ '\\014',
+ '\\015',
+ '\\016',
+ '\\017',
+ '\\018',
+ '\\019',
+ '\\020',
+ '\\021',
+ '\\022',
+ '\\023',
+ '\\024',
+ '\\025',
+ '\\026',
+ '\\027',
+ '\\028',
+ '\\029',
+ '\\030',
+ '\\031',
+}
+
+--- @param v any
+--- @return string
+local function format_float(v)
+ -- On windows exponent appears to have three digits and not two
+ local ret = ('%.6e'):format(v)
+ local l, f, es, e = ret:match('^(%-?%d)%.(%d+)e([+%-])0*(%d%d+)$')
+ return l .. '.' .. f .. 'e' .. es .. e
+end
+
+-- Formats Lua value `v`.
+--
+-- TODO(justinmk): redundant with vim.inspect() ?
+--
+-- "Nice table formatting similar to screen:snapshot_util()".
+-- Commit: 520c0b91a528
+function M.format_luav(v, indent, opts)
+ opts = opts or {}
+ local linesep = '\n'
+ local next_indent_arg = nil
+ local indent_shift = opts.indent_shift or ' '
+ local next_indent
+ local nl = '\n'
+ if indent == nil then
+ indent = ''
+ linesep = ''
+ next_indent = ''
+ nl = ' '
+ else
+ next_indent_arg = indent .. indent_shift
+ next_indent = indent .. indent_shift
+ end
+ local ret = ''
+ if type(v) == 'string' then
+ if opts.literal_strings then
+ ret = v
+ else
+ local quote = opts.dquote_strings and '"' or "'"
+ ret = quote
+ .. tostring(v)
+ :gsub(opts.dquote_strings and '["\\]' or "['\\]", '\\%0')
+ :gsub('[%z\1-\31]', function(match)
+ return SUBTBL[match:byte() + 1]
+ end)
+ .. quote
+ end
+ elseif type(v) == 'table' then
+ if v == vim.NIL then
+ ret = 'REMOVE_THIS'
+ else
+ local processed_keys = {}
+ ret = '{' .. linesep
+ local non_empty = false
+ local format_luav = M.format_luav
+ for i, subv in ipairs(v) do
+ ret = ('%s%s%s,%s'):format(ret, next_indent, format_luav(subv, next_indent_arg, opts), nl)
+ processed_keys[i] = true
+ non_empty = true
+ end
+ for k, subv in pairs(v) do
+ if not processed_keys[k] then
+ if type(k) == 'string' and k:match('^[a-zA-Z_][a-zA-Z0-9_]*$') then
+ ret = ret .. next_indent .. k .. ' = '
+ else
+ ret = ('%s%s[%s] = '):format(ret, next_indent, format_luav(k, nil, opts))
+ end
+ ret = ret .. format_luav(subv, next_indent_arg, opts) .. ',' .. nl
+ non_empty = true
+ end
+ end
+ if nl == ' ' and non_empty then
+ ret = ret:sub(1, -3)
+ end
+ ret = ret .. indent .. '}'
+ end
+ elseif type(v) == 'number' then
+ if v % 1 == 0 then
+ ret = ('%d'):format(v)
+ else
+ ret = format_float(v)
+ end
+ elseif type(v) == 'nil' then
+ ret = 'nil'
+ elseif type(v) == 'boolean' then
+ ret = (v and 'true' or 'false')
+ else
+ print(type(v))
+ -- Not implemented yet
+ luaassert(false)
+ end
+ return ret
+end
+
+-- Like Python repr(), "{!r}".format(s)
+--
+-- Commit: 520c0b91a528
+function M.format_string(fmt, ...)
+ local i = 0
+ local args = { ... }
+ local function getarg()
+ i = i + 1
+ return args[i]
+ end
+ local ret = fmt:gsub('%%[0-9*]*%.?[0-9*]*[cdEefgGiouXxqsr%%]', function(match)
+ local subfmt = match:gsub('%*', function()
+ return tostring(getarg())
+ end)
+ local arg = nil
+ if subfmt:sub(-1) ~= '%' then
+ arg = getarg()
+ end
+ if subfmt:sub(-1) == 'r' or subfmt:sub(-1) == 'q' then
+ -- %r is like built-in %q, but it is supposed to single-quote strings and
+ -- not double-quote them, and also work not only for strings.
+ -- Builtin %q is replaced here as it gives invalid and inconsistent with
+ -- luajit results for e.g. "\e" on lua: luajit transforms that into `\27`,
+ -- lua leaves as-is.
+ arg = M.format_luav(arg, nil, { dquote_strings = (subfmt:sub(-1) == 'q') })
+ subfmt = subfmt:sub(1, -2) .. 's'
+ end
+ if subfmt == '%e' then
+ return format_float(arg)
+ else
+ return subfmt:format(arg)
+ end
+ end)
+ return ret
+end
+
+return M
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 8d9789a3ce..91f61b5053 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -8,7 +8,7 @@ local assert_alive = helpers.assert_alive
local NIL = vim.NIL
local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq
local command = helpers.command
-local command_output = helpers.api.command_output
+local command_output = helpers.api.nvim_command_output
local exec = helpers.exec
local exec_capture = helpers.exec_capture
local eval = helpers.eval
@@ -19,6 +19,7 @@ local matches = helpers.matches
local pesc = vim.pesc
local mkdir_p = helpers.mkdir_p
local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed
+local async_meths = helpers.async_meths
local is_os = helpers.is_os
local parse_context = helpers.parse_context
local request = helpers.request
@@ -33,7 +34,7 @@ local insert = helpers.insert
local skip = helpers.skip
local pcall_err = helpers.pcall_err
-local format_string = helpers.format_string
+local format_string = require('test.format_string').format_string
local intchar2lua = helpers.intchar2lua
local mergedicts_copy = helpers.mergedicts_copy
local endswith = vim.endswith
@@ -76,7 +77,7 @@ describe('API', function()
eq({
'notification',
'nvim_error_event',
- { error_types.Exception.id, 'Invalid method: nvim_bogus' },
+ { error_types.Exception.id, 'Invalid method: bogus' },
}, next_msg())
-- error didn't close channel.
assert_alive()
@@ -84,7 +85,7 @@ describe('API', function()
it('failed async request emits nvim_error_event', function()
local error_types = api.nvim_get_api_info()[2].error_types
- nvim_async('command', 'bogus')
+ async_meths.nvim_command('bogus')
eq({
'notification',
'nvim_error_event',
@@ -2081,13 +2082,13 @@ describe('API', function()
{ ['rc'] = { 'hjkl' }, ['n'] = 97 },
},
- ['jumps'] = eval(([[
+ ['jumps'] = eval((([[
filter(map(add(
getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }),
'filter(
{ "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
{ k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
- ]]):gsub('\n', '')),
+ ]]):gsub('\n', ''))),
['bufs'] = eval([[
filter(map(getbufinfo(), '{ "f": v:val.name }'), '!empty(v:val.f)')
@@ -2301,7 +2302,7 @@ describe('API', function()
end)
it('can show one line', function()
- nvim_async('err_write', 'has bork\n')
+ async_meths.nvim_err_write('has bork\n')
screen:expect([[
^ |
{0:~ }|*6
@@ -2310,7 +2311,7 @@ describe('API', function()
end)
it('shows return prompt when more than &cmdheight lines', function()
- nvim_async('err_write', 'something happened\nvery bad\n')
+ async_meths.nvim_err_write('something happened\nvery bad\n')
screen:expect([[
|
{0:~ }|*3
@@ -2322,7 +2323,7 @@ describe('API', function()
end)
it('shows return prompt after all lines are shown', function()
- nvim_async('err_write', 'FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n')
+ async_meths.nvim_err_write('FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n')
screen:expect([[
|
{0:~ }|
@@ -2337,8 +2338,8 @@ describe('API', function()
it('handles multiple calls', function()
-- without linebreak text is joined to one line
- nvim_async('err_write', 'very ')
- nvim_async('err_write', 'fail\n')
+ async_meths.nvim_err_write('very ')
+ async_meths.nvim_err_write('fail\n')
screen:expect([[
^ |
{0:~ }|*6
@@ -2347,7 +2348,7 @@ describe('API', function()
helpers.poke_eventloop()
-- shows up to &cmdheight lines
- nvim_async('err_write', 'more fail\ntoo fail\n')
+ async_meths.nvim_err_write('more fail\ntoo fail\n')
screen:expect([[
|
{0:~ }|*3
@@ -2360,7 +2361,7 @@ describe('API', function()
end)
it('NUL bytes in message', function()
- nvim_async('err_write', 'aaa\0bbb\0\0ccc\nddd\0\0\0eee\n')
+ async_meths.nvim_err_write('aaa\0bbb\0\0ccc\nddd\0\0\0eee\n')
screen:expect {
grid = [[
|
@@ -2389,7 +2390,7 @@ describe('API', function()
end)
it('shows only one return prompt after all lines are shown', function()
- nvim_async('err_writeln', 'FAILURE\nERROR\nEXCEPTION\nTRACEBACK')
+ async_meths.nvim_err_writeln('FAILURE\nERROR\nEXCEPTION\nTRACEBACK')
screen:expect([[
|
{0:~ }|
@@ -3394,8 +3395,7 @@ describe('API', function()
end)
it('can show highlighted line', function()
- nvim_async(
- 'echo',
+ async_meths.nvim_echo(
{ { 'msg_a' }, { 'msg_b', 'Statement' }, { 'msg_c', 'Special' } },
true,
{}
@@ -3410,7 +3410,7 @@ describe('API', function()
end)
it('can show highlighted multiline', function()
- nvim_async('echo', { { 'msg_a\nmsg_a', 'Statement' }, { 'msg_b', 'Special' } }, true, {})
+ async_meths.nvim_echo({ { 'msg_a\nmsg_a', 'Statement' }, { 'msg_b', 'Special' } }, true, {})
screen:expect {
grid = [[
|
@@ -3431,7 +3431,7 @@ describe('API', function()
it('can disable saving message history', function()
command('set cmdheight=2') -- suppress Press ENTER
- nvim_async('echo', { { 'msg\nmsg' }, { 'msg' } }, false, {})
+ async_meths.nvim_echo({ { 'msg\nmsg' }, { 'msg' } }, false, {})
eq('', exec_capture('messages'))
end)
end)
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
index 4c2e54cc6b..a6fdb919c5 100644
--- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -222,7 +222,7 @@ describe('swapfile detection', function()
screen2:expect(expected_no_dialog)
-- With API call and shortmess+=F
- async_meths.command('edit %')
+ async_meths.nvim_command('edit %')
screen2:expect {
any = [[Found a swap file by the name ".*]]
.. [[Xtest_swapdialog_dir[/\].*]]
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index e9f8f30aa0..eddf336b6f 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -18,7 +18,7 @@ local fail = global_helpers.fail
local module = {}
local runtime_set = 'set runtimepath^=./build/lib/nvim/'
-module.nvim_prog = (os.getenv('NVIM_PRG') or global_helpers.test_build_dir .. '/bin/nvim')
+module.nvim_prog = (os.getenv('NVIM_PRG') or global_helpers.paths.test_build_dir .. '/bin/nvim')
-- Default settings for the test session.
module.nvim_set = (
'set shortmess+=IS background=light termguicolors noswapfile noautoindent startofline'
@@ -55,7 +55,7 @@ if module.nvim_dir == module.nvim_prog then
module.nvim_dir = '.'
end
-local prepend_argv
+local prepend_argv --- @type string[]?
if os.getenv('VALGRIND') then
local log_file = os.getenv('VALGRIND_LOG') or 'valgrind-%p.log'
@@ -79,7 +79,7 @@ elseif os.getenv('GDB') then
end
if prepend_argv then
- local new_nvim_argv = {}
+ local new_nvim_argv = {} --- @type string[]
local len = #prepend_argv
for i = 1, len do
new_nvim_argv[i] = prepend_argv[i]
@@ -91,10 +91,13 @@ if prepend_argv then
module.prepend_argv = prepend_argv
end
-local session, loop_running, last_error, method_error
+local session --- @type test.Session?
+local loop_running --- @type boolean?
+local last_error --- @type string?
+local method_error --- @type string?
if not is_os('win') then
- local sigpipe_handler = uv.new_signal()
+ local sigpipe_handler = assert(uv.new_signal())
uv.signal_start(sigpipe_handler, 'sigpipe', function()
print('warning: got SIGPIPE signal. Likely related to a crash in nvim')
end)
@@ -108,10 +111,15 @@ function module.set_session(s)
session = s
end
+--- @param method string
+--- @param ... any
+--- @return any
function module.request(method, ...)
+ assert(session)
local status, rv = session:request(method, ...)
if not status then
if loop_running then
+ --- @type string
last_error = rv[2]
session:stop()
else
@@ -121,12 +129,18 @@ function module.request(method, ...)
return rv
end
+--- @param method string
+--- @param ... any
+--- @return any
function module.request_lua(method, ...)
return module.exec_lua([[return vim.api[...](select(2, ...))]], method, ...)
end
+--- @param timeout? integer
+--- @return string?
function module.next_msg(timeout)
- return session:next_message(timeout and timeout or 10000)
+ assert(session)
+ return session:next_message(timeout or 10000)
end
function module.expect_twostreams(msgs1, msgs2)
@@ -164,6 +178,7 @@ function module.expect_msg_seq(...)
error('invalid args')
end
local ignore = arg1['ignore'] and arg1['ignore'] or {}
+ --- @type string[]
local seqs = arg1['seqs'] and arg1['seqs'] or { ... }
if type(ignore) ~= 'table' then
error("'ignore' arg must be a list of strings")
@@ -213,6 +228,7 @@ function module.expect_msg_seq(...)
local message = result
if type(result) == 'table' then
-- 'eq' returns several things
+ --- @type string
message = result.message
end
final_error = cat_err(final_error, message)
@@ -234,8 +250,16 @@ function module.set_method_error(err)
method_error = err
end
+--- @param lsession test.Session
+--- @param request_cb function
+--- @param notification_cb function
+--- @param setup_cb function
+--- @param timeout integer
+--- @return {[1]: integer, [2]: string}
function module.run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
- local on_request, on_notification, on_setup
+ local on_request --- @type function?
+ local on_notification --- @type function?
+ local on_setup --- @type function?
if request_cb then
function on_request(method, args)
@@ -273,11 +297,12 @@ function module.run_session(lsession, request_cb, notification_cb, setup_cb, tim
end
function module.run(request_cb, notification_cb, setup_cb, timeout)
+ assert(session)
return module.run_session(session, request_cb, notification_cb, setup_cb, timeout)
end
function module.stop()
- session:stop()
+ assert(session):stop()
end
function module.nvim_prog_abs()
@@ -301,6 +326,7 @@ function module.expect_exit(fn_or_timeout, ...)
eof_err_msg,
module.pcall_err(function(timeout, fn, ...)
fn(...)
+ assert(session)
while session:next_message(timeout) do
end
if session.eof_err then
@@ -311,26 +337,18 @@ function module.expect_exit(fn_or_timeout, ...)
end
end
--- Evaluates a Vimscript expression.
--- Fails on Vimscript error, but does not update v:errmsg.
-function module.eval(expr)
- return module.request('nvim_eval', expr)
-end
-
--- Executes a Vimscript function via RPC.
--- Fails on Vimscript error, but does not update v:errmsg.
-function module.call(name, ...)
- return module.request('nvim_call_function', name, { ... })
-end
-
--- Executes a Vimscript function via Lua.
--- Fails on Vimscript error, but does not update v:errmsg.
+--- Executes a Vimscript function via Lua.
+--- Fails on Vimscript error, but does not update v:errmsg.
+--- @param name string
+--- @param ... any
+--- @return any
function module.call_lua(name, ...)
return module.exec_lua([[return vim.call(...)]], name, ...)
end
--- Sends user input to Nvim.
--- Does not fail on Vimscript error, but v:errmsg will be updated.
+--- Sends user input to Nvim.
+--- Does not fail on Vimscript error, but v:errmsg will be updated.
+--- @param input string
local function nvim_feed(input)
while #input > 0 do
local written = module.request('nvim_input', input)
@@ -342,22 +360,27 @@ local function nvim_feed(input)
end
end
+--- @param ... string
function module.feed(...)
for _, v in ipairs({ ... }) do
nvim_feed(dedent(v))
end
end
+--- @param ... string
function module.rawfeed(...)
for _, v in ipairs({ ... }) do
nvim_feed(dedent(v))
end
end
+---@param ... string[]?
+---@return string[]
function module.merge_args(...)
local i = 1
- local argv = {}
+ local argv = {} --- @type string[]
for anum = 1, select('#', ...) do
+ --- @type string[]?
local args = select(anum, ...)
if args then
for _, arg in ipairs(args) do
@@ -369,26 +392,29 @@ function module.merge_args(...)
return argv
end
--- Removes Nvim startup args from `args` matching items in `args_rm`.
---
--- - Special case: "-u", "-i", "--cmd" are treated specially: their "values" are also removed.
--- - Special case: "runtimepath" will remove only { '--cmd', 'set runtimepath^=…', }
---
--- Example:
--- args={'--headless', '-u', 'NONE'}
--- args_rm={'--cmd', '-u'}
--- Result:
--- {'--headless'}
---
--- All matching cases are removed.
---
--- Example:
--- args={'--cmd', 'foo', '-N', '--cmd', 'bar'}
--- args_rm={'--cmd', '-u'}
--- Result:
--- {'-N'}
+--- Removes Nvim startup args from `args` matching items in `args_rm`.
+---
+--- - Special case: "-u", "-i", "--cmd" are treated specially: their "values" are also removed.
+--- - Special case: "runtimepath" will remove only { '--cmd', 'set runtimepath^=…', }
+---
+--- Example:
+--- args={'--headless', '-u', 'NONE'}
+--- args_rm={'--cmd', '-u'}
+--- Result:
+--- {'--headless'}
+---
+--- All matching cases are removed.
+---
+--- Example:
+--- args={'--cmd', 'foo', '-N', '--cmd', 'bar'}
+--- args_rm={'--cmd', '-u'}
+--- Result:
+--- {'-N'}
+--- @param args string[]
+--- @param args_rm string[]
+--- @return string[]
local function remove_args(args, args_rm)
- local new_args = {}
+ local new_args = {} --- @type string[]
local skip_following = { '-u', '-i', '-c', '--cmd', '-s', '--listen' }
if not args_rm or #args_rm == 0 then
return { unpack(args) }
@@ -433,7 +459,12 @@ function module.check_close()
session = nil
end
---- @param io_extra used for stdin_fd, see :help ui-option
+--- @param argv string[]
+--- @param merge boolean?
+--- @param env string[]?
+--- @param keep boolean
+--- @param io_extra uv.uv_pipe_t? used for stdin_fd, see :help ui-option
+--- @return test.Session
function module.spawn(argv, merge, env, keep, io_extra)
if not keep then
module.check_close()
@@ -469,16 +500,27 @@ function module.clear(...)
return module.get_session()
end
--- same params as clear, but does returns the session instead
--- of replacing the default session
+--- same params as clear, but does returns the session instead
+--- of replacing the default session
+--- @return test.Session
function module.spawn_argv(keep, ...)
local argv, env, io_extra = module.new_argv(...)
return module.spawn(argv, nil, env, keep, io_extra)
end
--- Builds an argument list for use in clear().
---
----@see clear() for parameters.
+--- @class test.new_argv.Opts
+--- @field args? string[]
+--- @field args_rm? string[]
+--- @field env? table<string,string>
+--- @field io_extra? uv.uv_pipe_t
+
+--- Builds an argument list for use in clear().
+---
+--- @see clear() for parameters.
+--- @param ... string
+--- @return string[]
+--- @return string[]?
+--- @return uv.uv_pipe_t?
function module.new_argv(...)
local args = { unpack(module.nvim_argv) }
table.insert(args, '--headless')
@@ -487,16 +529,17 @@ function module.new_argv(...)
table.insert(args, '--listen')
table.insert(args, _G._nvim_test_id)
end
- local new_args
- local io_extra
- local env = nil
+ local new_args --- @type string[]
+ local io_extra --- @type uv.uv_pipe_t?
+ local env --- @type string[]?
+ --- @type test.new_argv.Opts|string
local opts = select(1, ...)
if type(opts) ~= 'table' then
new_args = { ... }
else
args = remove_args(args, opts.args_rm)
if opts.env then
- local env_opt = {}
+ local env_opt = {} --- @type table<string,string>
for k, v in pairs(opts.env) do
assert(type(k) == 'string')
assert(type(v) == 'string')
@@ -535,6 +578,7 @@ function module.new_argv(...)
return args, env, io_extra
end
+--- @param ... string
function module.insert(...)
nvim_feed('i')
for _, v in ipairs({ ... }) do
@@ -544,8 +588,9 @@ function module.insert(...)
nvim_feed('<ESC>')
end
--- Executes an ex-command by user input. Because nvim_input() is used, Vimscript
--- errors will not manifest as client (lua) errors. Use command() for that.
+--- Executes an ex-command by user input. Because nvim_input() is used, Vimscript
+--- errors will not manifest as client (lua) errors. Use command() for that.
+--- @param ... string
function module.feed_command(...)
for _, v in ipairs({ ... }) do
if v:sub(1, 1) ~= '/' then
@@ -598,8 +643,10 @@ function module.set_shell_powershell(fake)
end
function module.create_callindex(func)
- local table = {}
- setmetatable(table, {
+ return setmetatable({}, {
+ --- @param tbl table<any,function>
+ --- @param arg1 string
+ --- @return function
__index = function(tbl, arg1)
local ret = function(...)
return func(arg1, ...)
@@ -608,36 +655,34 @@ function module.create_callindex(func)
return ret
end,
})
- return table
end
-local function ui(method, ...)
- return module.request('nvim_ui_' .. method, ...)
+--- @param method string
+--- @param ... any
+function module.nvim_async(method, ...)
+ assert(session):notify(method, ...)
end
-function module.nvim_async(method, ...)
- session:notify('nvim_' .. method, ...)
+--- Executes a Vimscript function via RPC.
+--- Fails on Vimscript error, but does not update v:errmsg.
+--- @param name string
+--- @param ... any
+--- @return any
+function module.call(name, ...)
+ return module.request('nvim_call_function', name, { ... })
end
module.async_meths = module.create_callindex(module.nvim_async)
-module.uimeths = module.create_callindex(ui)
-
-local function create_bridge(request, call)
- local function nvim(method, ...)
- if vim.startswith(method, 'nvim_') then
- return request(method, ...)
- end
- return request('nvim_' .. method, ...)
- end
- return {
- fn = module.create_callindex(call),
- api = module.create_callindex(nvim),
- }
-end
+module.rpc = {
+ fn = module.create_callindex(module.call),
+ api = module.create_callindex(module.request),
+}
-module.rpc = create_bridge(module.request, module.call)
-module.lua = create_bridge(module.request_lua, module.call_lua)
+module.lua = {
+ fn = module.create_callindex(module.call_lua),
+ api = module.create_callindex(module.request_lua),
+}
module.describe_lua_and_rpc = function(describe)
return function(what, tests)
@@ -657,6 +702,7 @@ module.api = vim.api
module.fn = vim.fn
for name, fns in pairs(module.rpc) do
+ --- @diagnostic disable-next-line:no-unknown
module[name] = fns
end
@@ -664,10 +710,14 @@ end
-- v:errmsg will not be updated.
module.command = module.api.nvim_command
+-- Evaluates a Vimscript expression.
+-- Fails on Vimscript error, but does not update v:errmsg.
+module.eval = module.api.nvim_eval
+
function module.poke_eventloop()
-- Execute 'nvim_eval' (a deferred function) to
-- force at least one main_loop iteration
- session:request('nvim_eval', '1')
+ module.api.nvim_eval('1')
end
function module.buf_lines(bufnr)
@@ -689,6 +739,10 @@ function module.expect_any(contents)
return ok(nil ~= string.find(module.curbuf_contents(), contents, 1, true))
end
+--- @param expected any[]
+--- @param received any[]
+--- @param kind string
+--- @return any
function module.expect_events(expected, received, kind)
if not pcall(eq, expected, received) then
local msg = 'unexpected ' .. kind .. ' received.\n\n'
@@ -728,6 +782,7 @@ function module.assert_visible(bufnr, visible)
end
end
+--- @param path string
local function do_rmdir(path)
local stat = uv.fs_stat(path)
if stat == nil then
@@ -795,14 +850,17 @@ function module.exc_exec(cmd)
return ret
end
+--- @param cond boolean
+--- @param reason string
+--- @return boolean
function module.skip(cond, reason)
if cond then
+ --- @type fun(reason: string)
local pending = getfenv(2).pending
pending(reason or 'FIXME')
return true
- else
- return false
end
+ return false
end
-- Calls pending() and returns `true` if the system is too slow to
@@ -825,6 +883,8 @@ function module.exec(code)
module.api.nvim_exec2(code, {})
end
+--- @param code string
+--- @return string
function module.exec_capture(code)
return module.api.nvim_exec2(code, { output = true }).output
end
@@ -832,7 +892,7 @@ end
--- @param code string
--- @return any
function module.exec_lua(code, ...)
- return module.api.exec_lua(code, { ... })
+ return module.api.nvim_exec_lua(code, { ... })
end
function module.get_pathsep()
@@ -871,19 +931,24 @@ function module.new_pipename()
return pipename
end
+--- @param provider string
+--- @return string|false?
function module.missing_provider(provider)
if provider == 'ruby' or provider == 'node' or provider == 'perl' then
+ --- @type string?
local e = module.fn['provider#' .. provider .. '#Detect']()[2]
return e ~= '' and e or false
elseif provider == 'python' or provider == 'python3' then
local py_major_version = (provider == 'python3' and 3 or 2)
+ --- @type string?
local e = module.fn['provider#pythonx#Detect'](py_major_version)[2]
return e ~= '' and e or false
- else
- assert(false, 'Unknown provider: ' .. provider)
end
+ assert(false, 'Unknown provider: ' .. provider)
end
+--- @param obj string|table
+--- @return any
function module.alter_slashes(obj)
if not is_os('win') then
return obj
@@ -892,14 +957,14 @@ function module.alter_slashes(obj)
local ret = obj:gsub('/', '\\')
return ret
elseif type(obj) == 'table' then
- local ret = {}
+ --- @cast obj table<any,any>
+ local ret = {} --- @type table<any,any>
for k, v in pairs(obj) do
ret[k] = module.alter_slashes(v)
end
return ret
- else
- assert(false, 'expected string or table of strings, got ' .. type(obj))
end
+ assert(false, 'expected string or table of strings, got ' .. type(obj))
end
local load_factor = 1
@@ -909,18 +974,25 @@ if global_helpers.is_ci() then
module.request('nvim_command', 'source test/old/testdir/load.vim')
load_factor = module.request('nvim_eval', 'g:test_load_factor')
end
+
+--- @param num number
+--- @return number
function module.load_adjust(num)
return math.ceil(num * load_factor)
end
+--- @param ctx table<string,any>
+--- @return table
function module.parse_context(ctx)
- local parsed = {}
+ local parsed = {} --- @type table<string,any>
for _, item in ipairs({ 'regs', 'jumps', 'bufs', 'gvars' }) do
+ --- @param v any
parsed[item] = vim.tbl_filter(function(v)
return type(v) == 'table'
end, module.call('msgpackparse', ctx[item]))
end
parsed['bufs'] = parsed['bufs'][1]
+ --- @param v any
return vim.tbl_map(function(v)
if #v == 0 then
return nil
@@ -931,10 +1003,12 @@ end
function module.add_builddir_to_rtp()
-- Add runtime from build dir for doc/tags (used with :help).
- module.command(string.format([[set rtp+=%s/runtime]], module.test_build_dir))
+ module.command(string.format([[set rtp+=%s/runtime]], module.paths.test_build_dir))
end
--- Kill (reap) a process by PID.
+--- Kill (reap) a process by PID.
+--- @param pid string
+--- @return boolean?
function module.os_kill(pid)
return os.execute(
(
@@ -944,7 +1018,9 @@ function module.os_kill(pid)
)
end
--- Create folder with non existing parents
+--- Create folder with non existing parents
+--- @param path string
+--- @return boolean?
function module.mkdir_p(path)
return os.execute((is_os('win') and 'mkdir ' .. path or 'mkdir -p ' .. path))
end
diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua
index 59a9283868..e4810feedb 100644
--- a/test/functional/legacy/prompt_buffer_spec.lua
+++ b/test/functional/legacy/prompt_buffer_spec.lua
@@ -219,7 +219,7 @@ describe('prompt buffer', function()
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
end)
- -- oldtest: Test_prompt_close_modify_hidden()
+ -- oldtest: Test_prompt_leave_modify_hidden()
it('modifying hidden buffer does not prevent prompt buffer mode change', function()
source([[
file hidden
@@ -228,14 +228,26 @@ describe('prompt buffer', function()
new prompt
set buftype=prompt
+ inoremap <buffer> w <Cmd>wincmd w<CR>
inoremap <buffer> q <Cmd>bwipe!<CR>
- autocmd BufWinLeave prompt call setbufline('hidden', 1, 'Test')
+ autocmd BufLeave prompt call appendbufline('hidden', '$', 'Leave')
+ autocmd BufEnter prompt call appendbufline('hidden', '$', 'Enter')
+ autocmd BufWinLeave prompt call appendbufline('hidden', '$', 'Close')
]])
feed('a')
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
+ feed('w')
+ eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
+ feed('<C-W>w')
+ eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
feed('q')
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
command('bwipe!')
- expect('Test')
+ expect([[
+
+ Leave
+ Enter
+ Leave
+ Close]])
end)
end)
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
index 66ba0f71f2..6821fe3c5e 100644
--- a/test/functional/lua/fs_spec.lua
+++ b/test/functional/lua/fs_spec.lua
@@ -6,8 +6,8 @@ local eq = helpers.eq
local mkdir_p = helpers.mkdir_p
local rmdir = helpers.rmdir
local nvim_dir = helpers.nvim_dir
-local test_build_dir = helpers.test_build_dir
-local test_source_path = helpers.test_source_path
+local test_build_dir = helpers.paths.test_build_dir
+local test_source_path = helpers.paths.test_source_path
local nvim_prog = helpers.nvim_prog
local is_os = helpers.is_os
local mkdir = helpers.mkdir
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index 6ed7af6b6e..171d37ba55 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -162,7 +162,7 @@ describe('luaeval()', function()
return sp('map', '[' .. val .. ']')
end
local function luaevalarg(argexpr, expr)
- return eval(([=[
+ return eval((([=[
[
extend(g:, {'_ret': luaeval(%s, %s)})._ret,
type(g:_ret)==type({})&&has_key(g:_ret, '_TYPE')
@@ -172,7 +172,7 @@ describe('luaeval()', function()
get(g:_ret, '_VAL', g:_ret)
]
: [0, g:_ret]][1]
- ]=]):format(expr or '"_A"', argexpr):gsub('\n', ''))
+ ]=]):format(expr or '"_A"', argexpr):gsub('\n', '')))
end
it('correctly passes special dictionaries', function()
diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua
index 106d40fe0e..044d707499 100644
--- a/test/functional/lua/watch_spec.lua
+++ b/test/functional/lua/watch_spec.lua
@@ -99,7 +99,10 @@ describe('vim._watch', function()
describe('poll', function()
it('detects file changes', function()
- skip(is_os('bsd'), 'bsd only reports rename on folders if file inside change')
+ skip(
+ is_os('bsd'),
+ 'kqueue only reports events on watched folder itself, not contained files #26110'
+ )
local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX')
local result = exec_lua(
diff --git a/test/functional/options/chars_spec.lua b/test/functional/options/chars_spec.lua
index 64de25112a..e9c20b5da9 100644
--- a/test/functional/options/chars_spec.lua
+++ b/test/functional/options/chars_spec.lua
@@ -1,9 +1,9 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, command = helpers.clear, helpers.command
+local pcall_err = helpers.pcall_err
local eval = helpers.eval
local eq = helpers.eq
-local exc_exec = helpers.exc_exec
local insert = helpers.insert
local feed = helpers.feed
local api = helpers.api
@@ -17,11 +17,6 @@ describe("'fillchars'", function()
screen:attach()
end)
- local function shouldfail(val, errval)
- errval = errval or val
- eq('Vim(set):E474: Invalid argument: fillchars=' .. errval, exc_exec('set fillchars=' .. val))
- end
-
describe('"eob" flag', function()
it("uses '~' by default", function()
eq('', eval('&fillchars'))
@@ -64,10 +59,22 @@ describe("'fillchars'", function()
end)
it('handles invalid values', function()
- shouldfail('eob:') -- empty string
- shouldfail('eob:馬') -- doublewidth char
- shouldfail('eob:xy') -- two ascii chars
- shouldfail('eob:\255', 'eob:<ff>') -- invalid UTF-8
+ eq(
+ 'Vim(set):E1511: Wrong number of characters for field "eob": fillchars=eob:',
+ pcall_err(command, 'set fillchars=eob:') -- empty string
+ )
+ eq(
+ 'Vim(set):E1512: Wrong character width for field "eob": fillchars=eob:馬',
+ pcall_err(command, 'set fillchars=eob:馬') -- doublewidth char
+ )
+ eq(
+ 'Vim(set):E1511: Wrong number of characters for field "eob": fillchars=eob:xy',
+ pcall_err(command, 'set fillchars=eob:xy') -- two ascii chars
+ )
+ eq(
+ 'Vim(set):E1512: Wrong character width for field "eob": fillchars=eob:<ff>',
+ pcall_err(command, 'set fillchars=eob:\255') -- invalid UTF-8
+ )
end)
end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 252931eccb..b602143443 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -4261,7 +4261,10 @@ describe('LSP', function()
describe('vim.lsp._watchfiles', function()
it('sends notifications when files change', function()
- skip(is_os('bsd'), 'bsd only reports rename on folders if file inside change')
+ skip(
+ is_os('bsd'),
+ 'kqueue only reports events on watched folder itself, not contained files #26110'
+ )
local root_dir = tmpname()
os.remove(root_dir)
mkdir(root_dir)
diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua
index 94e0ee6e82..1b5c0eab5d 100644
--- a/test/functional/shada/merging_spec.lua
+++ b/test/functional/shada/merging_spec.lua
@@ -525,7 +525,7 @@ describe('ShaDa marks support code', function()
local found = 0
for _, v in ipairs(read_shada_file(shada_fname)) do
if v.type == 7 and v.value.f == mock_file_path .. '-' then
- print(require('test.helpers').format_luav(v))
+ print(require('test.format_string').format_luav(v))
found = found + 1
end
end
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index 2942beab2f..6eb318015d 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -7,7 +7,7 @@ local is_os = helpers.is_os
local skip = helpers.skip
local uv = vim.uv
-local paths = require('test.cmakeconfig.paths')
+local paths = helpers.paths
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear, get_shada_rw =
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 2b39c93f14..9615534c87 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -151,7 +151,7 @@ describe('no crash when TermOpen autocommand', function()
it('processes job exit event when using termopen()', function()
command([[autocmd TermOpen * call input('')]])
- async_meths.command('terminal foobar')
+ async_meths.nvim_command('terminal foobar')
screen:expect {
grid = [[
|
@@ -181,7 +181,7 @@ describe('no crash when TermOpen autocommand', function()
it('wipes buffer and processes events when using termopen()', function()
command([[autocmd TermOpen * bwipe! | call input('')]])
- async_meths.command('terminal foobar')
+ async_meths.nvim_command('terminal foobar')
screen:expect {
grid = [[
|
@@ -202,7 +202,7 @@ describe('no crash when TermOpen autocommand', function()
it('wipes buffer and processes events when using nvim_open_term()', function()
command([[autocmd TermOpen * bwipe! | call input('')]])
- async_meths.open_term(0, {})
+ async_meths.nvim_open_term(0, {})
screen:expect {
grid = [[
|
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index f4347a460e..7e79479fc5 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -2895,3 +2895,54 @@ it("'inccommand' cannot be changed during preview #23136", function()
feed(':%s/foo/bar<C-E><C-E><C-E>')
assert_alive()
end)
+
+it("'inccommand' value can be changed multiple times #27086", function()
+ clear()
+ local screen = Screen.new(30, 20)
+ common_setup(screen, 'split', 'foo1\nfoo2\nfoo3')
+ for _ = 1, 3 do
+ feed(':%s/foo/bar')
+ screen:expect([[
+ {12:bar}1 |
+ {12:bar}2 |
+ {12:bar}3 |
+ {15:~ }|*7
+ {11:[No Name] [+] }|
+ |1| {12:bar}1 |
+ |2| {12:bar}2 |
+ |3| {12:bar}3 |
+ {15:~ }|*4
+ {10:[Preview] }|
+ :%s/foo/bar^ |
+ ]])
+ feed('<Esc>')
+ command('set inccommand=nosplit')
+ feed(':%s/foo/bar')
+ screen:expect([[
+ {12:bar}1 |
+ {12:bar}2 |
+ {12:bar}3 |
+ {15:~ }|*16
+ :%s/foo/bar^ |
+ ]])
+ feed('<Esc>')
+ command('set inccommand=split')
+ end
+end)
+
+it("'inccommand' disables preview if preview buffer can't be created #27086", function()
+ clear()
+ api.nvim_buf_set_name(0, '[Preview]')
+ local screen = Screen.new(30, 20)
+ common_setup(screen, 'split', 'foo1\nfoo2\nfoo3')
+ eq('split', api.nvim_get_option_value('inccommand', {}))
+ feed(':%s/foo/bar')
+ screen:expect([[
+ {12:bar}1 |
+ {12:bar}2 |
+ {12:bar}3 |
+ {15:~ }|*16
+ :%s/foo/bar^ |
+ ]])
+ eq('nosplit', api.nvim_get_option_value('inccommand', {}))
+end)
diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
index d30575a9f9..a714df72b7 100644
--- a/test/functional/ui/inccommand_user_spec.lua
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -1,6 +1,8 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local api = helpers.api
local clear = helpers.clear
+local eq = helpers.eq
local exec_lua = helpers.exec_lua
local insert = helpers.insert
local feed = helpers.feed
@@ -495,6 +497,22 @@ describe("'inccommand' for user commands", function()
test_preview_break_undo()
end)
end)
+
+ it('disables preview if preview buffer cannot be created #27086', function()
+ command('set inccommand=split')
+ api.nvim_buf_set_name(0, '[Preview]')
+ exec_lua([[
+ vim.api.nvim_create_user_command('Test', function() end, {
+ nargs = '*',
+ preview = function(_, _, _)
+ return 2
+ end
+ })
+ ]])
+ eq('split', api.nvim_get_option_value('inccommand', {}))
+ feed(':Test')
+ eq('nosplit', api.nvim_get_option_value('inccommand', {}))
+ end)
end)
describe("'inccommand' with multiple buffers", function()
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 4f95cd909c..9d1b6163d2 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -7,7 +7,7 @@ local command = helpers.command
local set_method_error = helpers.set_method_error
local api = helpers.api
local async_meths = helpers.async_meths
-local test_build_dir = helpers.test_build_dir
+local test_build_dir = helpers.paths.test_build_dir
local nvim_prog = helpers.nvim_prog
local exec = helpers.exec
local exec_capture = helpers.exec_capture
@@ -1039,7 +1039,7 @@ stack traceback:
end)
it('supports nvim_echo messages with multiple attrs', function()
- async_meths.echo(
+ async_meths.nvim_echo(
{ { 'wow, ', 'Search' }, { 'such\n\nvery ', 'ErrorMsg' }, { 'color', 'LineNr' } },
true,
{}
@@ -1403,7 +1403,7 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
end)
it('supports nvim_echo messages with multiple attrs', function()
- async_meths.echo(
+ async_meths.nvim_echo(
{ { 'wow, ', 'Search' }, { 'such\n\nvery ', 'ErrorMsg' }, { 'color', 'LineNr' } },
true,
{}
@@ -1521,7 +1521,7 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
end)
it('consecutive calls to win_move_statusline() work after multiline message #21014', function()
- async_meths.exec(
+ async_meths.nvim_exec(
[[
echo "\n"
call win_move_statusline(0, -4)
@@ -2196,7 +2196,7 @@ aliquip ex ea commodo consequat.]]
}
-- not processed while command is executing
- async_meths.ui_try_resize(35, 5)
+ async_meths.nvim_ui_try_resize(35, 5)
-- TODO(bfredl): ideally it should be processed just
-- before the "press ENTER" prompt though
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index b74a15d56f..1f7d187016 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -2527,7 +2527,7 @@ describe('builtin popupmenu', function()
]])
end
feed('<C-E>')
- async_meths.call_function('input', { '', '', 'sign' })
+ async_meths.nvim_call_function('input', { '', '', 'sign' })
if multigrid then
screen:expect {
grid = [[
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 29ec08e15c..af03bce4a0 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -548,4 +548,21 @@ describe('Signs', function()
delete | redraw | undo
]])
end)
+
+ it('sign not shown on line it was previously on after undo', function()
+ exec([[
+ call setline(1, range(1, 4))
+ call nvim_buf_set_extmark(0, nvim_create_namespace(''), 1, 0, {'sign_text':'S1'})
+ ]])
+ exec('norm 2Gdd')
+ exec('silent undo')
+ screen:expect([[
+ {2: }1 |
+ S1^2 |
+ {2: }3 |
+ {2: }4 |
+ {0:~ }|*9
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/vimscript/ctx_functions_spec.lua b/test/functional/vimscript/ctx_functions_spec.lua
index b8f9bbc92d..dc60a474f3 100644
--- a/test/functional/vimscript/ctx_functions_spec.lua
+++ b/test/functional/vimscript/ctx_functions_spec.lua
@@ -314,13 +314,13 @@ describe('context functions', function()
}
local with_jumps = {
- ['jumps'] = eval(([[
+ ['jumps'] = eval((([[
filter(map(add(
getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }),
'filter(
{ "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
{ k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
- ]]):gsub('\n', '')),
+ ]]):gsub('\n', ''))),
}
local with_bufs = {
diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua
index 6dd22078d6..b749d5a7f0 100644
--- a/test/functional/vimscript/input_spec.lua
+++ b/test/functional/vimscript/input_spec.lua
@@ -414,19 +414,19 @@ describe('confirm()', function()
-- screen:expect() calls are needed to avoid feeding input too early
screen:expect({ any = '%[No Name%]' })
- async_meths.command([[let a = confirm('Press O to proceed')]])
+ async_meths.nvim_command([[let a = confirm('Press O to proceed')]])
screen:expect({ any = '{CONFIRM:.+: }' })
feed('o')
screen:expect({ any = '%[No Name%]' })
eq(1, api.nvim_get_var('a'))
- async_meths.command([[let a = 'Are you sure?'->confirm("&Yes\n&No")]])
+ async_meths.nvim_command([[let a = 'Are you sure?'->confirm("&Yes\n&No")]])
screen:expect({ any = '{CONFIRM:.+: }' })
feed('y')
screen:expect({ any = '%[No Name%]' })
eq(1, api.nvim_get_var('a'))
- async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
+ async_meths.nvim_command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
screen:expect({ any = '{CONFIRM:.+: }' })
feed('n')
screen:expect({ any = '%[No Name%]' })
@@ -435,26 +435,26 @@ describe('confirm()', function()
-- Not possible to match Vim's CTRL-C test here as CTRL-C always sets got_int in Nvim.
-- confirm() should return 0 when pressing ESC.
- async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
+ async_meths.nvim_command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
screen:expect({ any = '{CONFIRM:.+: }' })
feed('<Esc>')
screen:expect({ any = '%[No Name%]' })
eq(0, api.nvim_get_var('a'))
-- Default choice is returned when pressing <CR>.
- async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
+ async_meths.nvim_command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
screen:expect({ any = '{CONFIRM:.+: }' })
feed('<CR>')
screen:expect({ any = '%[No Name%]' })
eq(1, api.nvim_get_var('a'))
- async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No", 2)]])
+ async_meths.nvim_command([[let a = confirm('Are you sure?', "&Yes\n&No", 2)]])
screen:expect({ any = '{CONFIRM:.+: }' })
feed('<CR>')
screen:expect({ any = '%[No Name%]' })
eq(2, api.nvim_get_var('a'))
- async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No", 0)]])
+ async_meths.nvim_command([[let a = confirm('Are you sure?', "&Yes\n&No", 0)]])
screen:expect({ any = '{CONFIRM:.+: }' })
feed('<CR>')
screen:expect({ any = '%[No Name%]' })
@@ -462,7 +462,9 @@ describe('confirm()', function()
-- Test with the {type} 4th argument
for _, type in ipairs({ 'Error', 'Question', 'Info', 'Warning', 'Generic' }) do
- async_meths.command(([[let a = confirm('Are you sure?', "&Yes\n&No", 1, '%s')]]):format(type))
+ async_meths.nvim_command(
+ ([[let a = confirm('Are you sure?', "&Yes\n&No", 1, '%s')]]):format(type)
+ )
screen:expect({ any = '{CONFIRM:.+: }' })
feed('y')
screen:expect({ any = '%[No Name%]' })
@@ -518,7 +520,7 @@ describe('confirm()', function()
feed(':call nvim_command("edit x")<cr>')
check_and_clear(':call nvim_command("edit |\n')
- async_meths.command('edit x')
+ async_meths.nvim_command('edit x')
check_and_clear(' |\n')
end)
end)
diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua
index 3f53c21e7a..046d451888 100644
--- a/test/functional/vimscript/timer_spec.lua
+++ b/test/functional/vimscript/timer_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local feed, eq, eval, ok = helpers.feed, helpers.eq, helpers.eval, helpers.ok
-local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run
+local source, async_meths, run = helpers.source, helpers.async_meths, helpers.run
local clear, command, fn = helpers.clear, helpers.command, helpers.fn
local exc_exec = helpers.exc_exec
local api = helpers.api
@@ -52,9 +52,9 @@ describe('timers', function()
endfunc
]])
eval("timer_start(10, 'MyHandler', {'repeat': -1})")
- nvim_async('command', 'sleep 10')
+ async_meths.nvim_command('sleep 10')
eq(-1, eval('g:val')) -- timer did nothing yet.
- nvim_async('command', 'let g:val = 0')
+ async_meths.nvim_command('let g:val = 0')
run(nil, nil, nil, load_adjust(20))
retry(nil, nil, function()
eq(2, eval('g:val'))
@@ -70,7 +70,7 @@ describe('timers', function()
end)
it('can be started during sleep', function()
- nvim_async('command', 'sleep 10')
+ async_meths.nvim_command('sleep 10')
-- this also tests that remote requests works during sleep
eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]"))
run(nil, nil, nil, load_adjust(20))
@@ -94,7 +94,7 @@ describe('timers', function()
it('are triggered in blocking getchar() call', function()
command("call timer_start(5, 'MyHandler', {'repeat': -1})")
- nvim_async('command', 'let g:val = 0 | let g:c = getchar()')
+ async_meths.nvim_command('let g:val = 0 | let g:c = getchar()')
retry(nil, nil, function()
local val = eval('g:val')
ok(val >= 2, '>= 2', tostring(val))
@@ -128,8 +128,10 @@ describe('timers', function()
redraw
endfunc
]])
- nvim_async('command', 'let g:c2 = getchar()')
- nvim_async('command', 'call timer_start(' .. load_adjust(100) .. ", 'AddItem', {'repeat': -1})")
+ async_meths.nvim_command('let g:c2 = getchar()')
+ async_meths.nvim_command(
+ 'call timer_start(' .. load_adjust(100) .. ", 'AddItem', {'repeat': -1})"
+ )
screen:expect([[
^ITEM 1 |
@@ -137,7 +139,7 @@ describe('timers', function()
{1:~ }|*3
|
]])
- nvim_async('command', 'let g:cont = 1')
+ async_meths.nvim_command('let g:cont = 1')
screen:expect([[
^ITEM 1 |
diff --git a/test/helpers.lua b/test/helpers.lua
index 83d7a0ece6..24ccead8b2 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -18,15 +18,14 @@ end
--- @class test.helpers
local module = {
- REMOVE_THIS = {},
+ paths = Paths,
}
--- @param p string
--- @return string
local function relpath(p)
p = vim.fs.normalize(p)
- local cwd = uv.cwd()
- return p:gsub('^' .. cwd)
+ return (p:gsub('^' .. uv.cwd, ''))
end
--- @param path string
@@ -42,41 +41,34 @@ function module.isdir(path)
return stat.type == 'directory'
end
---- @param path string
---- @return boolean
-function module.isfile(path)
- if not path then
- return false
- end
- local stat = uv.fs_stat(path)
- if not stat then
- return false
- end
- return stat.type == 'file'
-end
-
+--- @param ... string|string[]
--- @return string
function module.argss_to_cmd(...)
- local cmd = ''
+ local cmd = {} --- @type string[]
for i = 1, select('#', ...) do
local arg = select(i, ...)
if type(arg) == 'string' then
- cmd = cmd .. ' ' .. shell_quote(arg)
+ cmd[#cmd + 1] = shell_quote(arg)
else
+ --- @cast arg string[]
for _, subarg in ipairs(arg) do
- cmd = cmd .. ' ' .. shell_quote(subarg)
+ cmd[#cmd + 1] = shell_quote(subarg)
end
end
end
- return cmd
+ return table.concat(cmd, ' ')
end
function module.popen_r(...)
return io.popen(module.argss_to_cmd(...), 'r')
end
--- Calls fn() until it succeeds, up to `max` times or until `max_ms`
--- milliseconds have passed.
+--- Calls fn() until it succeeds, up to `max` times or until `max_ms`
+--- milliseconds have passed.
+--- @param max integer?
+--- @param max_ms integer?
+--- @param fn function
+--- @return any
function module.retry(max, max_ms, fn)
luaassert(max == nil or max > 0)
luaassert(max_ms == nil or max_ms > 0)
@@ -84,6 +76,7 @@ function module.retry(max, max_ms, fn)
local timeout = (max_ms and max_ms or 10000)
local start_time = uv.now()
while true do
+ --- @type boolean, any
local status, result = pcall(fn)
if status then
return result
@@ -133,6 +126,9 @@ function module.fail(msg)
return luaassert.epicfail(msg)
end
+--- @param pat string
+--- @param actual string
+--- @return boolean
function module.matches(pat, actual)
if nil ~= string.match(actual, pat) then
return true
@@ -182,10 +178,16 @@ end
--- Asserts that `pat` does NOT match any line in the tail of `logfile`.
---
--- @see assert_log
+--- @param pat (string) Lua pattern to match lines in the log file
+--- @param logfile? (string) Full path to log file (default=$NVIM_LOG_FILE)
+--- @param nrlines? (number) Search up to this many log lines
function module.assert_nolog(pat, logfile, nrlines)
return module.assert_log(pat, logfile, nrlines, true)
end
+--- @param fn fun(...): any
+--- @param ... any
+--- @return boolean, any
function module.pcall(fn, ...)
luaassert(type(fn) == 'function')
local status, rv = pcall(fn, ...)
@@ -233,6 +235,8 @@ end
-- -- Match Lua pattern.
-- matches('e[or]+$', pcall_err(function(a, b) error('some error') end, 'arg1', 'arg2'))
--
+--- @param fn function
+--- @return string
function module.pcall_err_withfile(fn, ...)
luaassert(type(fn) == 'function')
local status, rv = module.pcall(fn, ...)
@@ -242,19 +246,29 @@ function module.pcall_err_withfile(fn, ...)
return rv
end
+--- @param fn function
+--- @param ... any
+--- @return string
function module.pcall_err_withtrace(fn, ...)
local errmsg = module.pcall_err_withfile(fn, ...)
- return errmsg
- :gsub('^%.%.%./helpers%.lua:0: ', '')
- :gsub('^Error executing lua:- ', '')
- :gsub('^%[string "<nvim>"%]:0: ', '')
+ return (
+ errmsg
+ :gsub('^%.%.%./helpers%.lua:0: ', '')
+ :gsub('^Error executing lua:- ', '')
+ :gsub('^%[string "<nvim>"%]:0: ', '')
+ )
end
-function module.pcall_err(...)
- return module.remove_trace(module.pcall_err_withtrace(...))
+--- @param fn function
+--- @param ... any
+--- @return string
+function module.pcall_err(fn, ...)
+ return module.remove_trace(module.pcall_err_withtrace(fn, ...))
end
+--- @param s string
+--- @return string
function module.remove_trace(s)
return (s:gsub('\n%s*stack traceback:.*', ''))
end
@@ -264,9 +278,9 @@ end
-- exc_re: exclude pattern(s) (string or table)
function module.glob(initial_path, re, exc_re)
exc_re = type(exc_re) == 'table' and exc_re or { exc_re }
- local paths_to_check = { initial_path }
- local ret = {}
- local checked_files = {}
+ local paths_to_check = { initial_path } --- @type string[]
+ local ret = {} --- @type string[]
+ local checked_files = {} --- @type table<string,true>
local function is_excluded(path)
for _, pat in pairs(exc_re) do
if path:match(pat) then
@@ -313,7 +327,7 @@ function module.check_logs()
local file = log_dir .. '/' .. tail
local fd = assert(io.open(file))
local start_msg = ('='):rep(20) .. ' File ' .. file .. ' ' .. ('='):rep(20)
- local lines = {}
+ local lines = {} --- @type string[]
local warning_line = 0
for line in fd:lines() do
local cur_warning_line = check_logs_useless_lines[line]
@@ -325,6 +339,7 @@ function module.check_logs()
end
fd:close()
if #lines > 0 then
+ --- @type boolean?, file*?
local status, f
local out = io.stdout
if os.getenv('SYMBOLIZER') then
@@ -332,6 +347,7 @@ function module.check_logs()
end
out:write(start_msg .. '\n')
if status then
+ assert(f)
for line in f:lines() do
out:write('= ' .. line .. '\n')
end
@@ -353,10 +369,7 @@ function module.check_logs()
end
function module.sysname()
- local platform = uv.os_uname()
- if platform and platform.sysname then
- return platform.sysname:lower()
- end
+ return uv.os_uname().sysname:lower()
end
function module.is_os(s)
@@ -372,26 +385,15 @@ function module.is_os(s)
)
end
-function module.is_arch(s)
- local machine = uv.os_uname().machine
- if s == 'arm64' or s == 'aarch64' then
- return machine == 'arm64' or machine == 'aarch64'
- end
-
- if s == 'x86' or s == 'x86_64' or s == 'amd64' then
- return machine == 'x86_64'
- end
-
- return machine == s
-end
-
local function tmpdir_get()
return os.getenv('TMPDIR') and os.getenv('TMPDIR') or os.getenv('TEMP')
end
--- Is temp directory `dir` defined local to the project workspace?
+--- Is temp directory `dir` defined local to the project workspace?
+--- @param dir string?
+--- @return boolean
local function tmpdir_is_local(dir)
- return not not (dir and string.find(dir, 'Xtest'))
+ return not not (dir and dir:find('Xtest'))
end
--- Creates a new temporary file for use by tests.
@@ -422,14 +424,6 @@ module.tmpname = (function()
end
end)()
-function module.hasenv(name)
- local env = os.getenv(name)
- if env and env ~= '' then
- return env
- end
- return nil
-end
-
local function deps_prefix()
local env = os.getenv('DEPS_PREFIX')
return (env and env ~= '') and env or '.deps/usr'
@@ -443,6 +437,7 @@ function module.check_cores(app, force) -- luacheck: ignore
return
end
app = app or 'build/bin/nvim' -- luacheck: ignore
+ --- @type string, string?, string[]
local initial_path, re, exc_re
local gdb_db_cmd =
'gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"'
@@ -455,13 +450,14 @@ function module.check_cores(app, force) -- luacheck: ignore
and relpath(tmpdir_get()):gsub('^[ ./]+', ''):gsub('%/+$', ''):gsub('([^%w])', '%%%1')
or nil
)
- local db_cmd
- if module.hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then
- initial_path = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY')
+ local db_cmd --- @type string
+ local test_glob_dir = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY')
+ if test_glob_dir and test_glob_dir ~= '' then
+ initial_path = test_glob_dir
re = os.getenv('NVIM_TEST_CORE_GLOB_RE')
exc_re = { os.getenv('NVIM_TEST_CORE_EXC_RE'), local_tmpdir }
db_cmd = os.getenv('NVIM_TEST_CORE_DB_CMD') or gdb_db_cmd
- random_skip = os.getenv('NVIM_TEST_CORE_RANDOM_SKIP')
+ random_skip = os.getenv('NVIM_TEST_CORE_RANDOM_SKIP') ~= ''
elseif module.is_os('mac') then
initial_path = '/cores'
re = nil
@@ -519,21 +515,28 @@ function module.repeated_read_cmd(...)
return nil
end
+--- @generic T
+--- @param orig T
+--- @return T
function module.shallowcopy(orig)
if type(orig) ~= 'table' then
return orig
end
- local copy = {}
+ --- @cast orig table<any,any>
+ local copy = {} --- @type table<any,any>
for orig_key, orig_value in pairs(orig) do
copy[orig_key] = orig_value
end
return copy
end
+--- @param d1 table<any,any>
+--- @param d2 table<any,any>
+--- @return table<any,any>
function module.mergedicts_copy(d1, d2)
local ret = module.shallowcopy(d1)
for k, v in pairs(d2) do
- if d2[k] == module.REMOVE_THIS then
+ if d2[k] == vim.NIL then
ret[k] = nil
elseif type(d1[k]) == 'table' and type(v) == 'table' then
ret[k] = module.mergedicts_copy(d1[k], v)
@@ -544,16 +547,18 @@ function module.mergedicts_copy(d1, d2)
return ret
end
--- dictdiff: find a diff so that mergedicts_copy(d1, diff) is equal to d2
---
--- Note: does not do copies of d2 values used.
+--- dictdiff: find a diff so that mergedicts_copy(d1, diff) is equal to d2
+---
+--- Note: does not do copies of d2 values used.
+--- @param d1 table<any,any>
+--- @param d2 table<any,any>
function module.dictdiff(d1, d2)
- local ret = {}
+ local ret = {} --- @type table<any,any>
local hasdiff = false
for k, v in pairs(d1) do
if d2[k] == nil then
hasdiff = true
- ret[k] = module.REMOVE_THIS
+ ret[k] = vim.NIL
elseif type(v) == type(d2[k]) then
if type(v) == 'table' then
local subdiff = module.dictdiff(v, d2[k])
@@ -584,17 +589,11 @@ function module.dictdiff(d1, d2)
end
end
-function module.updated(d, d2)
- for k, v in pairs(d2) do
- d[k] = v
- end
- return d
-end
-
-- Concat list-like tables.
function module.concat_tables(...)
- local ret = {}
+ local ret = {} --- @type table<any,any>
for i = 1, select('#', ...) do
+ --- @type table<any,any>
local tbl = select(i, ...)
if tbl then
for _, v in ipairs(tbl) do
@@ -633,192 +632,13 @@ function module.dedent(str, leave_indent)
return str
end
-local function format_float(v)
- -- On windows exponent appears to have three digits and not two
- local ret = ('%.6e'):format(v)
- local l, f, es, e = ret:match('^(%-?%d)%.(%d+)e([+%-])0*(%d%d+)$')
- return l .. '.' .. f .. 'e' .. es .. e
-end
-
-local SUBTBL = {
- '\\000',
- '\\001',
- '\\002',
- '\\003',
- '\\004',
- '\\005',
- '\\006',
- '\\007',
- '\\008',
- '\\t',
- '\\n',
- '\\011',
- '\\012',
- '\\r',
- '\\014',
- '\\015',
- '\\016',
- '\\017',
- '\\018',
- '\\019',
- '\\020',
- '\\021',
- '\\022',
- '\\023',
- '\\024',
- '\\025',
- '\\026',
- '\\027',
- '\\028',
- '\\029',
- '\\030',
- '\\031',
-}
-
--- Formats Lua value `v`.
---
--- TODO(justinmk): redundant with vim.inspect() ?
---
--- "Nice table formatting similar to screen:snapshot_util()".
--- Commit: 520c0b91a528
-function module.format_luav(v, indent, opts)
- opts = opts or {}
- local linesep = '\n'
- local next_indent_arg = nil
- local indent_shift = opts.indent_shift or ' '
- local next_indent
- local nl = '\n'
- if indent == nil then
- indent = ''
- linesep = ''
- next_indent = ''
- nl = ' '
- else
- next_indent_arg = indent .. indent_shift
- next_indent = indent .. indent_shift
- end
- local ret = ''
- if type(v) == 'string' then
- if opts.literal_strings then
- ret = v
- else
- local quote = opts.dquote_strings and '"' or "'"
- ret = quote
- .. tostring(v)
- :gsub(opts.dquote_strings and '["\\]' or "['\\]", '\\%0')
- :gsub('[%z\1-\31]', function(match)
- return SUBTBL[match:byte() + 1]
- end)
- .. quote
- end
- elseif type(v) == 'table' then
- if v == module.REMOVE_THIS then
- ret = 'REMOVE_THIS'
- else
- local processed_keys = {}
- ret = '{' .. linesep
- local non_empty = false
- local format_luav = module.format_luav
- for i, subv in ipairs(v) do
- ret = ('%s%s%s,%s'):format(ret, next_indent, format_luav(subv, next_indent_arg, opts), nl)
- processed_keys[i] = true
- non_empty = true
- end
- for k, subv in pairs(v) do
- if not processed_keys[k] then
- if type(k) == 'string' and k:match('^[a-zA-Z_][a-zA-Z0-9_]*$') then
- ret = ret .. next_indent .. k .. ' = '
- else
- ret = ('%s%s[%s] = '):format(ret, next_indent, format_luav(k, nil, opts))
- end
- ret = ret .. format_luav(subv, next_indent_arg, opts) .. ',' .. nl
- non_empty = true
- end
- end
- if nl == ' ' and non_empty then
- ret = ret:sub(1, -3)
- end
- ret = ret .. indent .. '}'
- end
- elseif type(v) == 'number' then
- if v % 1 == 0 then
- ret = ('%d'):format(v)
- else
- ret = format_float(v)
- end
- elseif type(v) == 'nil' then
- ret = 'nil'
- elseif type(v) == 'boolean' then
- ret = (v and 'true' or 'false')
- else
- print(type(v))
- -- Not implemented yet
- luaassert(false)
- end
- return ret
-end
-
--- Like Python repr(), "{!r}".format(s)
---
--- Commit: 520c0b91a528
-function module.format_string(fmt, ...)
- local i = 0
- local args = { ... }
- local function getarg()
- i = i + 1
- return args[i]
- end
- local ret = fmt:gsub('%%[0-9*]*%.?[0-9*]*[cdEefgGiouXxqsr%%]', function(match)
- local subfmt = match:gsub('%*', function()
- return tostring(getarg())
- end)
- local arg = nil
- if subfmt:sub(-1) ~= '%' then
- arg = getarg()
- end
- if subfmt:sub(-1) == 'r' or subfmt:sub(-1) == 'q' then
- -- %r is like built-in %q, but it is supposed to single-quote strings and
- -- not double-quote them, and also work not only for strings.
- -- Builtin %q is replaced here as it gives invalid and inconsistent with
- -- luajit results for e.g. "\e" on lua: luajit transforms that into `\27`,
- -- lua leaves as-is.
- arg = module.format_luav(arg, nil, { dquote_strings = (subfmt:sub(-1) == 'q') })
- subfmt = subfmt:sub(1, -2) .. 's'
- end
- if subfmt == '%e' then
- return format_float(arg)
- else
- return subfmt:format(arg)
- end
- end)
- return ret
-end
-
function module.intchar2lua(ch)
ch = tonumber(ch)
return (20 <= ch and ch < 127) and ('%c'):format(ch) or ch
end
-local fixtbl_metatable = {
- __newindex = function()
- luaassert(false)
- end,
-}
-
-function module.fixtbl(tbl)
- return setmetatable(tbl, fixtbl_metatable)
-end
-
-function module.fixtbl_rec(tbl)
- local fixtbl_rec = module.fixtbl_rec
- for _, v in pairs(tbl) do
- if type(v) == 'table' then
- fixtbl_rec(v)
- end
- end
- return module.fixtbl(tbl)
-end
-
+--- @param str string
+--- @return string
function module.hexdump(str)
local len = string.len(str)
local dump = ''
@@ -844,10 +664,10 @@ function module.hexdump(str)
return dump .. hex .. string.rep(' ', 8 - len % 8) .. asc
end
--- Reads text lines from `filename` into a table.
---
--- filename: path to file
--- start: start line (1-indexed), negative means "lines before end" (tail)
+--- Reads text lines from `filename` into a table.
+--- @param filename string path to file
+--- @param start? integer start line (1-indexed), negative means "lines before end" (tail)
+--- @return string[]?
function module.read_file_list(filename, start)
local lnum = (start ~= nil and type(start) == 'number') and start or 1
local tail = (lnum < 0)
@@ -883,9 +703,9 @@ function module.read_file_list(filename, start)
return lines
end
--- Reads the entire contents of `filename` into a string.
---
--- filename: path to file
+--- Reads the entire contents of `filename` into a string.
+--- @param filename string
+--- @return string?
function module.read_file(filename)
local file = io.open(filename, 'r')
if not file then
@@ -901,6 +721,7 @@ function module.write_file(name, text, no_dedent, append)
local file = assert(io.open(name, (append and 'a' or 'w')))
if type(text) == 'table' then
-- Byte blob
+ --- @type string[]
local bytes = text
text = ''
for _, char in ipairs(bytes) do
@@ -914,6 +735,8 @@ function module.write_file(name, text, no_dedent, append)
file:close()
end
+--- @param name? 'cirrus'|'github'
+--- @return boolean
function module.is_ci(name)
local any = (name == nil)
luaassert(any or name == 'github' or name == 'cirrus')
@@ -946,12 +769,10 @@ function module.read_nvim_log(logfile, ci_rename)
end
--- @param path string
---- @return string
+--- @return boolean?
function module.mkdir(path)
-- 493 is 0755 in decimal
- return uv.fs_mkdir(path, 493)
+ return (uv.fs_mkdir(path, 493))
end
-module = vim.tbl_extend('error', module, Paths, require('test.deprecated'))
-
return module
diff --git a/test/old/testdir/test_display.vim b/test/old/testdir/test_display.vim
index bd90287400..70029dcf3c 100644
--- a/test/old/testdir/test_display.vim
+++ b/test/old/testdir/test_display.vim
@@ -253,12 +253,12 @@ func Test_eob_fillchars()
" default value
" call assert_match('eob:\~', &fillchars)
" invalid values
- call assert_fails(':set fillchars=eob:', 'E474:')
- call assert_fails(':set fillchars=eob:xy', 'E474:')
- call assert_fails(':set fillchars=eob:\255', 'E474:')
- call assert_fails(':set fillchars=eob:<ff>', 'E474:')
- call assert_fails(":set fillchars=eob:\x01", 'E474:')
- call assert_fails(':set fillchars=eob:\\x01', 'E474:')
+ call assert_fails(':set fillchars=eob:', 'E1511:')
+ call assert_fails(':set fillchars=eob:xy', 'E1511:')
+ call assert_fails(':set fillchars=eob:\255', 'E1511:')
+ call assert_fails(':set fillchars=eob:<ff>', 'E1511:')
+ call assert_fails(":set fillchars=eob:\x01", 'E1512:')
+ call assert_fails(':set fillchars=eob:\\x01', 'E1512:')
" default is ~
new
redraw
@@ -412,14 +412,16 @@ func Run_Test_display_lastline(euro)
call StopVimInTerminal(buf)
endfunc
-func Test_display_lastline()
+func Test_display_lastline_dump()
CheckScreendump
call Run_Test_display_lastline('')
call Run_Test_display_lastline('euro_')
+endfunc
- call assert_fails(':set fillchars=lastline:', 'E474:')
- call assert_fails(':set fillchars=lastline:〇', 'E474:')
+func Test_display_lastline_fails()
+ call assert_fails(':set fillchars=lastline:', 'E1511:')
+ call assert_fails(':set fillchars=lastline:〇', 'E1512:')
endfunc
func Test_display_long_lastline()
diff --git a/test/old/testdir/test_listchars.vim b/test/old/testdir/test_listchars.vim
index 179bdfa4a0..b82b70746b 100644
--- a/test/old/testdir/test_listchars.vim
+++ b/test/old/testdir/test_listchars.vim
@@ -429,52 +429,52 @@ func Test_listchars_invalid()
call assert_fails('set listchars=leadmultispace', 'E474:')
" Too short
- call assert_fails('set listchars=space:', 'E474:')
- call assert_fails('set listchars=tab:x', 'E474:')
- call assert_fails('set listchars=multispace:', 'E474:')
- call assert_fails('set listchars=leadmultispace:', 'E474:')
+ call assert_fails('set listchars=space:', 'E1511:')
+ call assert_fails('set listchars=tab:x', 'E1511:')
+ call assert_fails('set listchars=multispace:', 'E1511:')
+ call assert_fails('set listchars=leadmultispace:', 'E1511:')
" One occurrence too short
- call assert_fails('set listchars=space:,space:x', 'E474:')
- call assert_fails('set listchars=space:x,space:', 'E474:')
- call assert_fails('set listchars=tab:x,tab:xx', 'E474:')
- call assert_fails('set listchars=tab:xx,tab:x', 'E474:')
- call assert_fails('set listchars=multispace:,multispace:x', 'E474:')
- call assert_fails('set listchars=multispace:x,multispace:', 'E474:')
- call assert_fails('set listchars=leadmultispace:,leadmultispace:x', 'E474:')
- call assert_fails('set listchars=leadmultispace:x,leadmultispace:', 'E474:')
+ call assert_fails('set listchars=space:x,space:', 'E1511:')
+ call assert_fails('set listchars=space:,space:x', 'E1511:')
+ call assert_fails('set listchars=tab:xx,tab:x', 'E1511:')
+ call assert_fails('set listchars=tab:x,tab:xx', 'E1511:')
+ call assert_fails('set listchars=multispace:,multispace:x', 'E1511:')
+ call assert_fails('set listchars=multispace:x,multispace:', 'E1511:')
+ call assert_fails('set listchars=leadmultispace:,leadmultispace:x', 'E1511:')
+ call assert_fails('set listchars=leadmultispace:x,leadmultispace:', 'E1511:')
" Too long
- call assert_fails('set listchars=space:xx', 'E474:')
- call assert_fails('set listchars=tab:xxxx', 'E474:')
+ call assert_fails('set listchars=space:xx', 'E1511:')
+ call assert_fails('set listchars=tab:xxxx', 'E1511:')
" Has double-width character
- call assert_fails('set listchars=space:·', 'E474:')
- call assert_fails('set listchars=tab:·x', 'E474:')
- call assert_fails('set listchars=tab:x·', 'E474:')
- call assert_fails('set listchars=tab:xx·', 'E474:')
- call assert_fails('set listchars=multispace:·', 'E474:')
- call assert_fails('set listchars=multispace:xxx·', 'E474:')
- call assert_fails('set listchars=leadmultispace:·', 'E474:')
- call assert_fails('set listchars=leadmultispace:xxx·', 'E474:')
+ call assert_fails('set listchars=space:·', 'E1512:')
+ call assert_fails('set listchars=tab:·x', 'E1512:')
+ call assert_fails('set listchars=tab:x·', 'E1512:')
+ call assert_fails('set listchars=tab:xx·', 'E1512:')
+ call assert_fails('set listchars=multispace:·', 'E1512:')
+ call assert_fails('set listchars=multispace:xxx·', 'E1512:')
+ call assert_fails('set listchars=leadmultispace:·', 'E1512:')
+ call assert_fails('set listchars=leadmultispace:xxx·', 'E1512:')
" Has control character
- call assert_fails("set listchars=space:\x01", 'E474:')
- call assert_fails("set listchars=tab:\x01x", 'E474:')
- call assert_fails("set listchars=tab:x\x01", 'E474:')
- call assert_fails("set listchars=tab:xx\x01", 'E474:')
- call assert_fails("set listchars=multispace:\x01", 'E474:')
- call assert_fails("set listchars=multispace:xxx\x01", 'E474:')
- call assert_fails('set listchars=space:\\x01', 'E474:')
- call assert_fails('set listchars=tab:\\x01x', 'E474:')
- call assert_fails('set listchars=tab:x\\x01', 'E474:')
- call assert_fails('set listchars=tab:xx\\x01', 'E474:')
- call assert_fails('set listchars=multispace:\\x01', 'E474:')
- call assert_fails('set listchars=multispace:xxx\\x01', 'E474:')
- call assert_fails("set listchars=leadmultispace:\x01", 'E474:')
- call assert_fails('set listchars=leadmultispace:\\x01', 'E474:')
- call assert_fails("set listchars=leadmultispace:xxx\x01", 'E474:')
- call assert_fails('set listchars=leadmultispace:xxx\\x01', 'E474:')
+ call assert_fails("set listchars=space:\x01", 'E1512:')
+ call assert_fails("set listchars=tab:\x01x", 'E1512:')
+ call assert_fails("set listchars=tab:x\x01", 'E1512:')
+ call assert_fails("set listchars=tab:xx\x01", 'E1512:')
+ call assert_fails("set listchars=multispace:\x01", 'E1512:')
+ call assert_fails("set listchars=multispace:xxx\x01", 'E1512:')
+ call assert_fails('set listchars=space:\\x01', 'E1512:')
+ call assert_fails('set listchars=tab:\\x01x', 'E1512:')
+ call assert_fails('set listchars=tab:x\\x01', 'E1512:')
+ call assert_fails('set listchars=tab:xx\\x01', 'E1512:')
+ call assert_fails('set listchars=multispace:\\x01', 'E1512:')
+ call assert_fails('set listchars=multispace:xxx\\x01', 'E1512:')
+ call assert_fails("set listchars=leadmultispace:\x01", 'E1512:')
+ call assert_fails('set listchars=leadmultispace:\\x01', 'E1512:')
+ call assert_fails("set listchars=leadmultispace:xxx\x01", 'E1512:')
+ call assert_fails('set listchars=leadmultispace:xxx\\x01', 'E1512:')
enew!
set ambiwidth& listchars& ff&
diff --git a/test/old/testdir/test_listdict.vim b/test/old/testdir/test_listdict.vim
index 33b8d55982..649d5f5c6c 100644
--- a/test/old/testdir/test_listdict.vim
+++ b/test/old/testdir/test_listdict.vim
@@ -1321,7 +1321,7 @@ func Test_listdict_index()
call CheckLegacyAndVim9Failure(['VAR l = [1, 2, 3]', 'LET l[1.1] = 4'], ['E805:', 'E1012:', 'E805:'])
call CheckLegacyAndVim9Failure(['VAR l = [1, 2, 3]', 'LET l[: i] = [4, 5]'], ['E121:', 'E1001:', 'E121:'])
call CheckLegacyAndVim9Failure(['VAR l = [1, 2, 3]', 'LET l[: 3.2] = [4, 5]'], ['E805:', 'E1012:', 'E805:'])
- " call CheckLegacyAndVim9Failure(['VAR t = test_unknown()', 'echo t[0]'], 'E685:')
+ " call CheckLegacyAndVim9Failure(['VAR t = test_unknown()', 'echo t[0]'], ['E685:', 'E909:', 'E685:'])
endfunc
" Test for a null list
diff --git a/test/old/testdir/test_prompt_buffer.vim b/test/old/testdir/test_prompt_buffer.vim
index 20daa07a3d..41e14ae427 100644
--- a/test/old/testdir/test_prompt_buffer.vim
+++ b/test/old/testdir/test_prompt_buffer.vim
@@ -298,9 +298,10 @@ func Test_prompt_appending_while_hidden()
call StopVimInTerminal(buf)
endfunc
-" Modifying a hidden buffer while closing a prompt buffer should not prevent
-" stopping of Insert mode.
-func Test_prompt_close_modify_hidden()
+" Modifying a hidden buffer while leaving a prompt buffer should not prevent
+" stopping of Insert mode, and returning to the prompt buffer later should
+" restore Insert mode.
+func Test_prompt_leave_modify_hidden()
call CanTestPromptBuffer()
let script =<< trim END
@@ -310,22 +311,34 @@ func Test_prompt_close_modify_hidden()
new prompt
set buftype=prompt
+ inoremap <buffer> w <Cmd>wincmd w<CR>
inoremap <buffer> q <Cmd>bwipe!<CR>
- autocmd BufWinLeave prompt call setbufline('hidden', 1, 'Test')
+ autocmd BufLeave prompt call appendbufline('hidden', '$', 'Leave')
+ autocmd BufEnter prompt call appendbufline('hidden', '$', 'Enter')
+ autocmd BufWinLeave prompt call appendbufline('hidden', '$', 'Close')
END
- call writefile(script, 'XpromptCloseModifyHidden', 'D')
+ call writefile(script, 'XpromptLeaveModifyHidden', 'D')
- let buf = RunVimInTerminal('-S XpromptCloseModifyHidden', {'rows': 10})
+ let buf = RunVimInTerminal('-S XpromptLeaveModifyHidden', {'rows': 10})
call TermWait(buf)
call term_sendkeys(buf, "a")
call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 10))})
+ call term_sendkeys(buf, "w")
+ call WaitForAssert({-> assert_notmatch('-- INSERT --', term_getline(buf, 10))})
+
+ call term_sendkeys(buf, "\<C-W>w")
+ call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 10))})
+
call term_sendkeys(buf, "q")
call WaitForAssert({-> assert_notmatch('-- INSERT --', term_getline(buf, 10))})
call term_sendkeys(buf, ":bwipe!\<CR>")
- call WaitForAssert({-> assert_equal('Test', term_getline(buf, 1))})
+ call WaitForAssert({-> assert_equal('Leave', term_getline(buf, 2))})
+ call WaitForAssert({-> assert_equal('Enter', term_getline(buf, 3))})
+ call WaitForAssert({-> assert_equal('Leave', term_getline(buf, 4))})
+ call WaitForAssert({-> assert_equal('Close', term_getline(buf, 5))})
call StopVimInTerminal(buf)
endfunc
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index 47499d98fa..ab4a59cfdb 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -2,8 +2,8 @@ local ffi = require('ffi')
local formatc = require('test.unit.formatc')
local Set = require('test.unit.set')
local Preprocess = require('test.unit.preprocess')
-local Paths = require('test.cmakeconfig.paths')
local global_helpers = require('test.helpers')
+local paths = global_helpers.paths
local assert = require('luassert')
local say = require('say')
@@ -15,7 +15,7 @@ local eq = global_helpers.eq
local trim = vim.trim
-- add some standard header locations
-for _, p in ipairs(Paths.include_paths) do
+for _, p in ipairs(paths.include_paths) do
Preprocess.add_to_include_path(p)
end
@@ -728,7 +728,7 @@ local function check_child_err(rd)
--- @type string
err = err .. '\nNo end of trace occurred'
end
- local cc_err, cc_emsg = pcall(check_cores, Paths.test_luajit_prg, true)
+ local cc_err, cc_emsg = pcall(check_cores, paths.test_luajit_prg, true)
if not cc_err then
--- @type string
err = err .. '\ncheck_cores failed: ' .. cc_emsg
@@ -749,7 +749,7 @@ local function itp_parent(rd, pid, allow_failure, location)
io.stderr:write('Errorred out (' .. status .. '):\n' .. tostring(emsg) .. '\n')
os.execute([[
sh -c "source ci/common/test.sh
- check_core_dumps --delete \"]] .. Paths.test_luajit_prg .. [[\""]])
+ check_core_dumps --delete \"]] .. paths.test_luajit_prg .. [[\""]])
else
error(tostring(emsg) .. '\nexit code: ' .. status)
end
@@ -797,7 +797,7 @@ local function gen_itp(it)
end
local function cppimport(path)
- return cimport(Paths.test_source_path .. '/test/includes/pre/' .. path)
+ return cimport(paths.test_source_path .. '/test/includes/pre/' .. path)
end
cimport(
diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua
index ae12136a5c..c7d3f8532f 100644
--- a/test/unit/viml/expressions/parser_spec.lua
+++ b/test/unit/viml/expressions/parser_spec.lua
@@ -14,8 +14,8 @@ local ffi = helpers.ffi
local neq = helpers.neq
local eq = helpers.eq
local mergedicts_copy = helpers.mergedicts_copy
-local format_string = helpers.format_string
-local format_luav = helpers.format_luav
+local format_string = require('test.format_string').format_string
+local format_luav = require('test.format_string').format_luav
local intchar2lua = helpers.intchar2lua
local dictdiff = helpers.dictdiff
diff --git a/test/unit/viml/expressions/parser_tests.lua b/test/unit/viml/expressions/parser_tests.lua
index a10e1098b5..aa2bf740de 100644
--- a/test/unit/viml/expressions/parser_tests.lua
+++ b/test/unit/viml/expressions/parser_tests.lua
@@ -1,6 +1,4 @@
-local global_helpers = require('test.helpers')
-
-local REMOVE_THIS = global_helpers.REMOVE_THIS
+local REMOVE_THIS = vim.NIL
return function(itp, _check_parsing, hl, fmtn)
local function check_parsing(...)