aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ci/build.ps12
-rwxr-xr-xci/install.sh2
-rw-r--r--runtime/doc/api.txt106
-rw-r--r--runtime/doc/autocmd.txt9
-rw-r--r--runtime/doc/change.txt4
-rw-r--r--runtime/doc/eval.txt64
-rw-r--r--runtime/doc/if_ruby.txt12
-rw-r--r--runtime/doc/lsp.txt35
-rw-r--r--runtime/doc/lua.txt7
-rw-r--r--runtime/doc/map.txt20
-rw-r--r--runtime/doc/quickfix.txt7
-rw-r--r--runtime/doc/vim_diff.txt3
-rw-r--r--runtime/ftplugin/markdown.vim46
-rw-r--r--runtime/lua/vim/lsp.lua108
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua28
-rw-r--r--runtime/lua/vim/lsp/protocol.lua14
-rw-r--r--runtime/lua/vim/lsp/util.lua2
-rw-r--r--runtime/lua/vim/shared.lua75
-rw-r--r--runtime/lua/vim/treesitter.lua37
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua88
-rw-r--r--runtime/lua/vim/treesitter/query.lua98
-rw-r--r--runtime/queries/c/highlights.scm151
-rw-r--r--runtime/syntax/markdown.vim66
-rwxr-xr-xscripts/vim-patch.sh5
-rwxr-xr-xsrc/clint.py2
-rw-r--r--src/nvim/api/buffer.c49
-rw-r--r--src/nvim/api/private/helpers.c14
-rw-r--r--src/nvim/api/ui_events.in.h8
-rw-r--r--src/nvim/auevents.lua3
-rw-r--r--src/nvim/buffer.c10
-rw-r--r--src/nvim/buffer_defs.h1
-rw-r--r--src/nvim/change.c3
-rw-r--r--src/nvim/charset.c46
-rw-r--r--src/nvim/edit.c91
-rw-r--r--src/nvim/eval.c11
-rw-r--r--src/nvim/eval.lua3
-rw-r--r--src/nvim/eval/funcs.c129
-rw-r--r--src/nvim/eval/userfunc.c8
-rw-r--r--src/nvim/ex_cmds.c10
-rw-r--r--src/nvim/ex_cmds2.c31
-rw-r--r--src/nvim/ex_docmd.c44
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/generators/gen_ex_cmds.lua28
-rw-r--r--src/nvim/generators/gen_options.lua9
-rw-r--r--src/nvim/getchar.c3
-rw-r--r--src/nvim/lua/treesitter.c50
-rw-r--r--src/nvim/mbyte.c144
-rw-r--r--src/nvim/memline.c49
-rw-r--r--src/nvim/message.c7
-rw-r--r--src/nvim/misc1.c4
-rw-r--r--src/nvim/normal.c2
-rw-r--r--src/nvim/ops.c113
-rw-r--r--src/nvim/option.c7
-rw-r--r--src/nvim/option_defs.h3
-rw-r--r--src/nvim/os/signal.c4
-rw-r--r--src/nvim/popupmnu.c84
-rw-r--r--src/nvim/quickfix.c225
-rw-r--r--src/nvim/screen.c4
-rw-r--r--src/nvim/search.c60
-rw-r--r--src/nvim/spell.c5
-rw-r--r--src/nvim/testdir/runtest.vim3
-rw-r--r--src/nvim/testdir/shared.vim3
-rw-r--r--src/nvim/testdir/test_alot.vim2
-rw-r--r--src/nvim/testdir/test_autocmd.vim13
-rw-r--r--src/nvim/testdir/test_cjk_linebreak.vim97
-rw-r--r--src/nvim/testdir/test_display.vim41
-rw-r--r--src/nvim/testdir/test_edit.vim31
-rw-r--r--src/nvim/testdir/test_filetype.vim2
-rw-r--r--src/nvim/testdir/test_functions.vim10
-rw-r--r--src/nvim/testdir/test_gn.vim27
-rw-r--r--src/nvim/testdir/test_ins_complete.vim24
-rw-r--r--src/nvim/testdir/test_messages.vim1
-rw-r--r--src/nvim/testdir/test_perl.vim102
-rw-r--r--src/nvim/testdir/test_put.vim26
-rw-r--r--src/nvim/testdir/test_quickfix.vim237
-rw-r--r--src/nvim/testdir/test_ruby.vim376
-rw-r--r--src/nvim/testdir/test_swap.vim60
-rw-r--r--src/nvim/testdir/test_syntax.vim98
-rw-r--r--src/nvim/testdir/test_textobjects.vim30
-rw-r--r--src/nvim/testdir/test_usercommands.vim201
-rw-r--r--src/nvim/testdir/test_version.vim12
-rw-r--r--src/nvim/testdir/test_window_cmd.vim4
-rw-r--r--src/nvim/window.c5
-rw-r--r--test/functional/api/buffer_spec.lua20
-rw-r--r--test/functional/api/vim_spec.lua14
-rw-r--r--test/functional/api/window_spec.lua8
-rw-r--r--test/functional/core/exit_spec.lua4
-rw-r--r--test/functional/core/job_spec.lua4
-rw-r--r--test/functional/eval/interrupt_spec.lua6
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua4
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua20
-rw-r--r--test/functional/helpers.lua8
-rw-r--r--test/functional/legacy/005_bufleave_delete_buffer_spec.lua6
-rw-r--r--test/functional/legacy/006_argument_list_spec.lua8
-rw-r--r--test/functional/legacy/012_directory_spec.lua8
-rw-r--r--test/functional/legacy/023_edit_arguments_spec.lua4
-rw-r--r--test/functional/legacy/030_fileformats_spec.lua34
-rw-r--r--test/functional/legacy/033_lisp_indent_spec.lua4
-rw-r--r--test/functional/legacy/036_regexp_character_classes_spec.lua2
-rw-r--r--test/functional/legacy/045_folding_spec.lua4
-rw-r--r--test/functional/legacy/051_highlight_spec.lua4
-rw-r--r--test/functional/legacy/057_sort_spec.lua62
-rw-r--r--test/functional/legacy/074_global_var_in_viminfo_spec.lua6
-rw-r--r--test/functional/legacy/075_maparg_spec.lua4
-rw-r--r--test/functional/legacy/107_adjust_window_and_contents_spec.lua4
-rw-r--r--test/functional/legacy/autoformat_join_spec.lua4
-rw-r--r--test/functional/legacy/close_count_spec.lua10
-rw-r--r--test/functional/legacy/display_spec.lua4
-rw-r--r--test/functional/legacy/eval_spec.lua10
-rw-r--r--test/functional/legacy/mapping_spec.lua8
-rw-r--r--test/functional/legacy/memory_usage_spec.lua8
-rw-r--r--test/functional/legacy/search_mbyte_spec.lua4
-rw-r--r--test/functional/legacy/search_spec.lua38
-rw-r--r--test/functional/legacy/utf8_spec.lua4
-rw-r--r--test/functional/legacy/wordcount_spec.lua10
-rw-r--r--test/functional/lua/commands_spec.lua2
-rw-r--r--test/functional/lua/luaeval_spec.lua4
-rw-r--r--test/functional/lua/treesitter_spec.lua102
-rw-r--r--test/functional/lua/vim_spec.lua207
-rw-r--r--test/functional/plugin/lsp_spec.lua76
-rw-r--r--test/functional/provider/ruby_spec.lua22
-rw-r--r--test/functional/terminal/buffer_spec.lua4
-rw-r--r--test/functional/terminal/cursor_spec.lua2
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua14
-rw-r--r--test/functional/terminal/scrollback_spec.lua6
-rw-r--r--test/functional/terminal/window_spec.lua4
-rw-r--r--test/functional/ui/float_spec.lua2
-rw-r--r--test/functional/ui/inccommand_spec.lua36
-rw-r--r--test/functional/ui/mouse_spec.lua2
-rw-r--r--test/functional/ui/multigrid_spec.lua8
-rw-r--r--test/functional/ui/popupmenu_spec.lua44
-rw-r--r--test/functional/ui/searchhl_spec.lua2
-rw-r--r--test/functional/viml/completion_spec.lua48
-rw-r--r--test/functional/viml/errorlist_spec.lua2
-rw-r--r--test/helpers.lua45
-rw-r--r--test/symbolic/klee/nvim/charset.c4
137 files changed, 3582 insertions, 1054 deletions
diff --git a/ci/build.ps1 b/ci/build.ps1
index 36570be7ae..08fc76393d 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -116,7 +116,7 @@ if (-not $NoTests) {
python3 -c "import pynvim; print(str(pynvim))" ; exitIfFailed
$env:PATH = "C:\Ruby24\bin;$env:PATH"
- gem.cmd install neovim
+ gem.cmd install --pre neovim
Get-Command -CommandType Application neovim-ruby-host.bat
npm.cmd install -g neovim
diff --git a/ci/install.sh b/ci/install.sh
index a4dfc87a1b..efb37cea4e 100755
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -19,7 +19,7 @@ echo "Install neovim module for Python 2."
CC=cc python2 -m pip -q install --user --upgrade pynvim
echo "Install neovim RubyGem."
-gem install --no-document --version ">= 0.8.0" neovim
+gem install --no-document --pre neovim
echo "Install neovim npm package"
source ~/.nvm/nvm.sh
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index b80ca9edd7..0c726ddd86 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -529,14 +529,6 @@ nvim__id_float({flt}) *nvim__id_float()*
nvim__inspect_cell({grid}, {row}, {col}) *nvim__inspect_cell()*
TODO: Documentation
- *nvim__put_attr()*
-nvim__put_attr({id}, {start_row}, {start_col}, {end_row}, {end_col})
- Set attrs in nvim__buf_set_lua_hl callbacks
-
- TODO(bfredl): This is rather pedestrian. The final interface
- should probably be derived from a reformed bufhl/virttext
- interface with full support for multi-line ranges etc
-
nvim__screenshot({path}) *nvim__screenshot()*
TODO: Documentation
@@ -1480,6 +1472,53 @@ nvim_set_current_win({window}) *nvim_set_current_win()*
Parameters: ~
{window} Window handle
+ *nvim_set_decoration_provider()*
+nvim_set_decoration_provider({ns_id}, {opts})
+ Set or change decoration provider for a namespace
+
+ This is a very general purpose interface for having lua
+ callbacks being triggered during the redraw code.
+
+ The expected usage is to set extmarks for the currently
+ redrawn buffer. |nvim_buf_set_extmark| can be called to add
+ marks on a per-window or per-lines basis. Use the `ephemeral`
+ key to only use the mark for the current screen redraw (the
+ callback will be called again for the next redraw ).
+
+ Note: this function should not be called often. Rather, the
+ callbacks themselves can be used to throttle unneeded
+ callbacks. the `on_start` callback can return `false` to
+ disable the provider until the next redraw. Similarily, return
+ `false` in `on_win` will skip the `on_lines` calls for that
+ window (but any extmarks set in `on_win` will still be used).
+ A plugin managing multiple sources of decorations should
+ ideally only set one provider, and merge the sources
+ internally. You can use multiple `ns_id` for the extmarks
+ set/modified inside the callback anyway.
+
+ Note: doing anything other than setting extmarks is considered
+ experimental. Doing things like changing options are not
+ expliticly forbidden, but is likely to have unexpected
+ consequences (such as 100% CPU consumption). doing
+ `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite
+ dubious for the moment.
+
+ Parameters: ~
+ {ns_id} Namespace id from |nvim_create_namespace()|
+ {opts} Callbacks invoked during redraw:
+ • on_start: called first on each screen redraw
+ ["start", tick]
+ • on_buf: called for each buffer being redrawn
+ (before window callbacks) ["buf", bufnr, tick]
+ • on_win: called when starting to redraw a
+ specific window. ["win", winid, bufnr, topline,
+ botline_guess]
+ • on_line: called for each buffer line being
+ redrawn. (The interation with fold lines is
+ subject to change) ["win", winid, bufnr, row]
+ • on_end: called at the end of a redraw cycle
+ ["end", tick]
+
nvim_set_keymap({mode}, {lhs}, {rhs}, {opts}) *nvim_set_keymap()*
Sets a global |mapping| for the given mode.
@@ -1575,18 +1614,6 @@ to check whether a buffer is loaded.
nvim__buf_redraw_range({buffer}, {first}, {last})
TODO: Documentation
-nvim__buf_set_luahl({buffer}, {opts}) *nvim__buf_set_luahl()*
- Unstabilized interface for defining syntax hl in lua.
-
- This is not yet safe for general use, lua callbacks will need
- to be restricted, like textlock and probably other stuff.
-
- The API on_line/nvim__put_attr is quite raw and not intended
- to be the final shape. Ideally this should operate on chunks
- larger than a single line to reduce interpreter overhead, and
- generate annotation objects (bufhl/virttext) on the fly but
- using the same representation.
-
nvim__buf_stats({buffer}) *nvim__buf_stats()*
TODO: Documentation
@@ -1690,6 +1717,29 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
|nvim_buf_detach()|
|api-buffer-updates-lua|
+nvim_buf_call({buffer}, {fun}) *nvim_buf_call()*
+ call a function with buffer as temporary current buffer
+
+ This temporarily switches current buffer to "buffer". If the
+ current window already shows "buffer", the window is not
+ switched If a window inside the current tabpage (including a
+ float) already shows the buffer One of these windows will be
+ set as current window temporarily. Otherwise a temporary
+ scratch window (calleed the "autocmd window" for historical
+ reasons) will be used.
+
+ This is useful e.g. to call vimL functions that only work with
+ the current buffer/window currently, like |termopen()|.
+
+ Parameters: ~
+ {buffer} Buffer handle, or 0 for current buffer
+ {fun} Function to call inside the buffer (currently
+ lua callable only)
+
+ Return: ~
+ Return value of function. NB: will deepcopy lua values
+ currently, use upvalues to send lua references in and out.
+
*nvim_buf_clear_namespace()*
nvim_buf_clear_namespace({buffer}, {ns_id}, {line_start}, {line_end})
Clears namespaced objects (highlights, extmarks, virtual text)
@@ -1733,6 +1783,17 @@ nvim_buf_del_var({buffer}, {name}) *nvim_buf_del_var()*
{buffer} Buffer handle, or 0 for current buffer
{name} Variable name
+nvim_buf_delete({buffer}, {opts}) *nvim_buf_delete()*
+ Deletes the buffer. See |:bwipeout|
+
+ Parameters: ~
+ {buffer} Buffer handle, or 0 for current buffer
+ {opts} Optional parameters. Keys:
+ • force: Force deletion and ignore unsaved
+ changes.
+ • unload: Unloaded only, do not delete. See
+ |:bunload|
+
nvim_buf_detach({buffer}) *nvim_buf_detach()*
Deactivates buffer-update events on the channel.
@@ -1986,6 +2047,11 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
• hl_group : name of the highlight group used to
highlight this mark.
• virt_text : virtual text to link to this mark.
+ • ephemeral : for use with
+ |nvim_set_decoration_provider| callbacks. The
+ mark will only be used for the current redraw
+ cycle, and not be permantently stored in the
+ buffer.
Return: ~
Id of the created/updated extmark
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index a6872d0af5..a728593c40 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -700,9 +700,14 @@ InsertEnter Just before starting Insert mode. Also for
The cursor is restored afterwards. If you do
not want that set |v:char| to a non-empty
string.
+ *InsertLeavePre*
+InsertLeavePre Just before leaving Insert mode. Also when
+ using CTRL-O |i_CTRL-O|. Be caseful not to
+ change mode or use `:normal`, it will likely
+ cause trouble.
*InsertLeave*
-InsertLeave When leaving Insert mode. Also when using
- CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|.
+InsertLeave Just after leaving Insert mode. Also when
+ using CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|.
*MenuPopup*
MenuPopup Just before showing the popup menu (under the
right mouse button). Useful for adjusting the
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index dcebbc524c..5c67359002 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1615,6 +1615,10 @@ B When joining lines, don't insert a space between two multi-byte
characters. Overruled by the 'M' flag.
1 Don't break a line after a one-letter word. It's broken before it
instead (if possible).
+] Respect textwidth rigorously. With this flag set, no line can be
+ longer than textwidth, unless line-break-prohibition rules make this
+ impossible. Mainly for CJK scripts and works only if 'encoding' is
+ "utf-8".
j Where it makes sense, remove a comment leader when joining lines. For
example, joining:
int i; // the index ~
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 0f848d0c27..800de63a55 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2336,6 +2336,7 @@ repeat({expr}, {count}) String repeat {expr} {count} times
resolve({filename}) String get filename a shortcut points to
reverse({list}) List reverse {list} in-place
round({expr}) Float round off {expr}
+rubyeval({expr}) any evaluate |Ruby| expression
rpcnotify({channel}, {event}[, {args}...])
Sends an |RPC| notification to {channel}
rpcrequest({channel}, {method}[, {args}...])
@@ -2468,7 +2469,8 @@ tolower({expr}) String the String {expr} switched to lowercase
toupper({expr}) String the String {expr} switched to uppercase
tr({src}, {fromstr}, {tostr}) String translate chars of {src} in {fromstr}
to chars in {tostr}
-trim({text} [, {mask}]) String trim characters in {mask} from {text}
+trim({text} [, {mask} [, {dir}]])
+ String trim characters in {mask} from {text}
trunc({expr}) Float truncate Float {expr}
type({name}) Number type of variable {name}
undofile({name}) String undo file name for {name}
@@ -3839,7 +3841,7 @@ feedkeys({string} [, {mode}]) *feedkeys()*
stuck, waiting for a character to be typed before the
script continues.
Note that if you manage to call feedkeys() while
- executing commands, thus calling it recursively, the
+ executing commands, thus calling it recursively, then
all typehead will be consumed by the last call.
'!' When used with 'x' will not end Insert mode. Can be
used in a test when a timer is set to exit Insert mode
@@ -4642,7 +4644,7 @@ getloclist({nr},[, {what}]) *getloclist()*
If {what} contains 'filewinid', then returns the id of the
window used to display files from the location list. This
field is applicable only when called from a location list
- window.
+ window. See |location-list-file-window| for more details.
getmatches([{win}]) *getmatches()*
Returns a |List| with all matches previously defined for the
@@ -4733,7 +4735,9 @@ getqflist([{what}]) *getqflist()*
id get information for the quickfix list with
|quickfix-ID|; zero means the id for the
current list or the list specified by "nr"
- idx index of the current entry in the list
+ idx index of the current entry in the quickfix
+ list specified by 'id' or 'nr'.
+ See |quickfix-index|
items quickfix list entries
lines parse a list of lines using 'efm' and return
the resulting entries. Only a |List| type is
@@ -4926,6 +4930,19 @@ getwinpos([{timeout}]) *getwinpos()*
{timeout} can be used to specify how long to wait in msec for
a response from the terminal. When omitted 100 msec is used.
+ Use a longer time for a remote terminal.
+ When using a value less than 10 and no response is received
+ within that time, a previously reported position is returned,
+ if available. This can be used to poll for the position and
+ do some work in the meantime: >
+ while 1
+ let res = getwinpos(1)
+ if res[0] >= 0
+ break
+ endif
+ " Do some work here
+ endwhile
+<
*getwinposx()*
getwinposx() The result is a Number, which is the X coordinate in pixels of
the left hand side of the GUI Vim window. The result will be
@@ -6263,6 +6280,7 @@ mode([expr]) Return a string that indicates the current mode.
nov Operator-pending (forced charwise |o_v|)
noV Operator-pending (forced linewise |o_V|)
noCTRL-V Operator-pending (forced blockwise |o_CTRL-V|)
+ CTRL-V is one character
niI Normal using |i_CTRL-O| in |Insert-mode|
niR Normal using |i_CTRL-O| in |Replace-mode|
niV Normal using |i_CTRL-O| in |Virtual-Replace-mode|
@@ -7053,6 +7071,17 @@ rpcstart({prog}[, {argv}]) *rpcstart()*
< with >
:let id = jobstart(['prog', 'arg1', 'arg2'], {'rpc': v:true})
+rubyeval({expr}) *rubyeval()*
+ Evaluate Ruby expression {expr} and return its result
+ converted to Vim data structures.
+ Numbers, floats and strings are returned as they are (strings
+ are copied though).
+ Arrays are represented as Vim |List| type.
+ Hashes are represented as Vim |Dictionary| type.
+ Other objects are represented as strings resulted from their
+ "Object#to_s" method.
+ {only available when compiled with the |+ruby| feature}
+
screenattr({row}, {col}) *screenattr()*
Like |screenchar()|, but return the attribute. This is a rather
arbitrary number that can only be used to compare to the
@@ -7622,16 +7651,22 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
efm errorformat to use when parsing text from
"lines". If this is not present, then the
'errorformat' option value is used.
+ See |quickfix-parse|
id quickfix list identifier |quickfix-ID|
+ idx index of the current entry in the quickfix
+ list specified by 'id' or 'nr'. If set to '$',
+ then the last entry in the list is set as the
+ current entry. See |quickfix-index|
items list of quickfix entries. Same as the {list}
argument.
lines use 'errorformat' to parse a list of lines and
add the resulting entries to the quickfix list
{nr} or {id}. Only a |List| value is supported.
+ See |quickfix-parse|
nr list number in the quickfix stack; zero
means the current quickfix list and "$" means
- the last quickfix list
- title quickfix list title text
+ the last quickfix list.
+ title quickfix list title text. See |quickfix-title|
Unsupported keys in {what} are ignored.
If the "nr" item is not present, then the current quickfix list
is modified. When creating a new quickfix list, "nr" can be
@@ -9015,21 +9050,28 @@ tr({src}, {fromstr}, {tostr}) *tr()*
echo tr("<blob>", "<>", "{}")
< returns "{blob}"
-trim({text} [, {mask}]) *trim()*
+trim({text} [, {mask} [, {dir}]]) *trim()*
Return {text} as a String where any character in {mask} is
- removed from the beginning and end of {text}.
+ removed from the beginning and/or end of {text}.
If {mask} is not given, {mask} is all characters up to 0x20,
which includes Tab, space, NL and CR, plus the non-breaking
space character 0xa0.
- This code deals with multibyte characters properly.
-
+ The optional {dir} argument specifies where to remove the
+ characters:
+ 0 remove from the beginning and end of {text}
+ 1 remove only at the beginning of {text}
+ 2 remove only at the end of {text}
+ When omitted both ends are trimmed.
+ This function deals with multibyte characters properly.
Examples: >
echo trim(" some text ")
< returns "some text" >
echo trim(" \r\t\t\r RESERVE \t\n\x0B\xA0") . "_TAIL"
< returns "RESERVE_TAIL" >
echo trim("rm<Xrm<>X>rrm", "rm<>")
-< returns "Xrm<>X" (characters in the middle are not removed)
+< returns "Xrm<>X" (characters in the middle are not removed) >
+ echo trim(" vim ", " ", 2)
+< returns " vim"
trunc({expr}) *trunc()*
Return the largest integral value with magnitude less than or
diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt
index 6468e4c81e..c8d2409549 100644
--- a/runtime/doc/if_ruby.txt
+++ b/runtime/doc/if_ruby.txt
@@ -136,7 +136,7 @@ self[{n}] Returns the buffer object for the number {n}. The first number
Methods:
-name Returns the name of the buffer.
+name Returns the full name of the buffer.
number Returns the number of the buffer.
count Returns the number of lines.
length Returns the number of lines.
@@ -172,6 +172,7 @@ height = {n} Sets the window height to {n}.
width Returns the width of the window.
width = {n} Sets the window width to {n}.
cursor Returns a [row, col] array for the cursor position.
+ First line number is 1 and first column number is 0.
cursor = [{row}, {col}]
Sets the cursor position to {row} and {col}.
@@ -184,4 +185,13 @@ $curwin The current window object.
$curbuf The current buffer object.
==============================================================================
+6. rubyeval() Vim function *ruby-rubyeval*
+
+To facilitate bi-directional interface, you can use |rubyeval()| function to
+evaluate Ruby expressions and pass their values to Vim script.
+
+The Ruby value "true", "false" and "nil" are converted to v:true, v:false and
+v:null, respectively.
+
+==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 44b611c2cf..33d65406a1 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -488,8 +488,8 @@ get_active_clients() *vim.lsp.get_active_clients()*
Table of |vim.lsp.client| objects
get_client_by_id({client_id}) *vim.lsp.get_client_by_id()*
- Gets an active client by id, or nil if the id is invalid or
- the client is not yet initialized.
+ Gets a client by id, or nil if the id is invalid.
+ The returned client may not yet be fully initialized.
Parameters: ~
{client_id} client id number
@@ -792,6 +792,20 @@ outgoing_calls() *vim.lsp.buf.outgoing_calls()*
cursor in the |quickfix| window. If the symbol can resolve to
multiple items, the user can pick one in the |inputlist|.
+ *vim.lsp.buf.range_code_action()*
+range_code_action({context}, {start_pos}, {end_pos})
+ Performs |vim.lsp.buf.code_action()| for a given range.
+
+ Parameters: ~
+ {context} (table, optional) Valid `CodeActionContext`
+ object
+ {start_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the start of the last
+ visual selection.
+ {end_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the end of the last
+ visual selection.
+
*vim.lsp.buf.range_formatting()*
range_formatting({options}, {start_pos}, {end_pos})
Formats a given range.
@@ -1285,6 +1299,23 @@ make_formatting_params({options})
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
+ *vim.lsp.util.make_given_range_params()*
+make_given_range_params({start_pos}, {end_pos})
+ Using the given range in the current buffer, creates an object
+ that is similar to |vim.lsp.util.make_range_params()|.
+
+ Parameters: ~
+ {start_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the start of the last
+ visual selection.
+ {end_pos} ({number, number}, optional) mark-indexed
+ position. Defaults to the end of the last
+ visual selection.
+
+ Return: ~
+ { textDocument = { uri = `current_file_uri` }, range = {
+ start = `start_position` , end = `end_position` } }
+
make_position_params() *vim.lsp.util.make_position_params()*
Creates a `TextDocumentPositionParams` object for the current
buffer and cursor position.
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index a53024d420..334bb33c1e 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -1031,6 +1031,9 @@ is_callable({f}) *vim.is_callable()*
Return: ~
true if `f` is callable, else false
+is_valid({opt}) *vim.is_valid()*
+ TODO: Documentation
+
list_extend({dst}, {src}, {start}, {finish}) *vim.list_extend()*
Extends a list-like table with the values of another list-like
table.
@@ -1286,7 +1289,9 @@ validate({opt}) *vim.validate()*
• arg_value: argument value
• fn: any function accepting one argument,
returns true if and only if the argument is
- valid
+ valid. Can optionally return an additional
+ informative error message as the second
+ returned value.
• msg: (optional) error string if validation
fails
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 1514f03c55..edec4a8de7 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1136,9 +1136,10 @@ scripts.
:com[mand] *:com* *:command*
List all user-defined commands. When listing commands,
- the characters in the first two columns are
+ the characters in the first columns are:
! Command has the -bang attribute
" Command has the -register attribute
+ | Command has the -bar attribute
b Command is local to current buffer
(see below for details on attributes)
The list can be filtered on command name with
@@ -1342,14 +1343,15 @@ It is possible that the special characters in the range like `.`, `$` or `%`
which by default correspond to the current line, last line and the whole
buffer, relate to arguments, (loaded) buffers, windows or tab pages.
-Possible values are:
- -addr=lines Range of lines (this is the default)
- -addr=arguments Range for arguments
- -addr=buffers Range for buffers (also not loaded buffers)
- -addr=loaded_buffers Range for loaded buffers
- -addr=windows Range for windows
- -addr=tabs Range for tab pages
- -addr=other other kind of range
+Possible values are (second column is the short name used in listing):
+ -addr=lines Range of lines (this is the default)
+ -addr=arguments arg Range for arguments
+ -addr=buffers buf Range for buffers (also not loaded buffers)
+ -addr=loaded_buffers load Range for loaded buffers
+ -addr=windows win Range for windows
+ -addr=tabs tab Range for tab pages
+ -addr=quickfix qf Range for quickfix entries
+ -addr=other ? other kind of range
Special cases ~
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 188cfc91b6..9da11a553d 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -43,6 +43,7 @@ A location list is a window-local quickfix list. You get one after commands
like `:lvimgrep`, `:lgrep`, `:lhelpgrep`, `:lmake`, etc., which create a
location list instead of a quickfix list as the corresponding `:vimgrep`,
`:grep`, `:helpgrep`, `:make` do.
+ *location-list-file-window*
A location list is associated with a window and each window can have a
separate location list. A location list can be associated with only one
window. The location list is independent of the quickfix list.
@@ -718,6 +719,9 @@ using these functions are below:
" get the location list window id of the third window
:echo getloclist(3, {'winid' : 0}).winid
+
+ " get the file window id of a location list window (winnr: 4)
+ :echo getloclist(4, {'filewinid' : 0}).filewinid
<
*setqflist-examples*
The |setqflist()| and |setloclist()| functions can be used to set the various
@@ -732,6 +736,9 @@ using these functions are below:
" set the title of the current quickfix list
:call setqflist([], 'a', {'title' : 'Mytitle'})
+ " change the current entry in the list specified by an identifier
+ :call setqflist([], 'a', {'id' : qfid, 'idx' : 10})
+
" set the context of a quickfix list specified by an identifier
:call setqflist([], 'a', {'id' : qfid, 'context' : {'val' : 100}})
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index ae60c1c5e8..1fcb6611b4 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -450,6 +450,9 @@ Eval:
*js_decode()*
*v:none* (used by Vim to represent JavaScript "undefined"); use |v:null| instead.
+Events:
+ *SigUSR1* Use |Signal| to detect `SIGUSR1` signal instead.
+
Highlight groups:
*hl-StatusLineTerm* *hl-StatusLineTermNC* are unnecessary because Nvim
supports 'winhighlight' window-local highlights.
diff --git a/runtime/ftplugin/markdown.vim b/runtime/ftplugin/markdown.vim
index 277ba94e8b..fc1d9e068b 100644
--- a/runtime/ftplugin/markdown.vim
+++ b/runtime/ftplugin/markdown.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin
" Language: Markdown
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
-" Last Change: 2016 Aug 29
+" Last Change: 2019 Dec 05
if exists("b:did_ftplugin")
finish
@@ -9,7 +9,7 @@ endif
runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim
-setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=>\ %s
+setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=<!--%s-->
setlocal formatoptions+=tcqln formatoptions-=r formatoptions-=o
setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\|^[-*+]\\s\\+\\\|^\\[^\\ze[^\\]]\\+\\]:
@@ -19,32 +19,56 @@ else
let b:undo_ftplugin = "setl cms< com< fo< flp<"
endif
-function! MarkdownFold()
+function! s:NotCodeBlock(lnum) abort
+ return synIDattr(synID(v:lnum, 1, 1), 'name') !=# 'markdownCode'
+endfunction
+
+function! MarkdownFold() abort
let line = getline(v:lnum)
- " Regular headers
- let depth = match(line, '\(^#\+\)\@<=\( .*$\)\@=')
- if depth > 0
- return ">" . depth
+ if line =~# '^#\+ ' && s:NotCodeBlock(v:lnum)
+ return ">" . match(line, ' ')
endif
- " Setext style headings
let nextline = getline(v:lnum + 1)
- if (line =~ '^.\+$') && (nextline =~ '^=\+$')
+ if (line =~ '^.\+$') && (nextline =~ '^=\+$') && s:NotCodeBlock(v:lnum + 1)
return ">1"
endif
- if (line =~ '^.\+$') && (nextline =~ '^-\+$')
+ if (line =~ '^.\+$') && (nextline =~ '^-\+$') && s:NotCodeBlock(v:lnum + 1)
return ">2"
endif
return "="
endfunction
+function! s:HashIndent(lnum) abort
+ let hash_header = matchstr(getline(a:lnum), '^#\{1,6}')
+ if len(hash_header)
+ return hash_header
+ else
+ let nextline = getline(a:lnum + 1)
+ if nextline =~# '^=\+\s*$'
+ return '#'
+ elseif nextline =~# '^-\+\s*$'
+ return '##'
+ endif
+ endif
+endfunction
+
+function! MarkdownFoldText() abort
+ let hash_indent = s:HashIndent(v:foldstart)
+ let title = substitute(getline(v:foldstart), '^#\+\s*', '', '')
+ let foldsize = (v:foldend - v:foldstart + 1)
+ let linecount = '['.foldsize.' lines]'
+ return hash_indent.' '.title.' '.linecount
+endfunction
+
if has("folding") && exists("g:markdown_folding")
setlocal foldexpr=MarkdownFold()
setlocal foldmethod=expr
- let b:undo_ftplugin .= " foldexpr< foldmethod<"
+ setlocal foldtext=MarkdownFoldText()
+ let b:undo_ftplugin .= " foldexpr< foldmethod< foldtext<"
endif
" vim:set sw=2:
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 585528dd5a..fad213212a 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -25,6 +25,27 @@ local lsp = {
-- format_rpc_error = lsp_rpc.format_rpc_error;
}
+-- maps request name to the required resolved_capability in the client.
+lsp._request_name_to_capability = {
+ ['textDocument/hover'] = 'hover';
+ ['textDocument/signatureHelp'] = 'signature_help';
+ ['textDocument/definition'] = 'goto_definition';
+ ['textDocument/implementation'] = 'implementation';
+ ['textDocument/declaration'] = 'declaration';
+ ['textDocument/typeDefinition'] = 'type_definition';
+ ['textDocument/documentSymbol'] = 'document_symbol';
+ ['textDocument/workspaceSymbol'] = 'workspace_symbol';
+ ['textDocument/prepareCallHierarchy'] = 'call_hierarchy';
+ ['textDocument/rename'] = 'rename';
+ ['textDocument/codeAction'] = 'code_action';
+ ['workspace/executeCommand'] = 'execute_command';
+ ['textDocument/references'] = 'find_references';
+ ['textDocument/rangeFormatting'] = 'document_range_formatting';
+ ['textDocument/formatting'] = 'document_formatting';
+ ['textDocument/completion'] = 'completion';
+ ['textDocument/documentHighlight'] = 'document_highlight';
+}
+
-- TODO improve handling of scratch buffers with LSP attached.
--@private
@@ -51,6 +72,16 @@ local function resolve_bufnr(bufnr)
end
--@private
+--- callback called by the client when trying to call a method that's not
+--- supported in any of the servers registered for the current buffer.
+--@param method (string) name of the method
+function lsp._unsupported_method(method)
+ local msg = string.format("method %s is not supported by any of the servers registered for the current buffer", method)
+ log.warn(msg)
+ return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg)
+end
+
+--@private
--- Checks whether a given path is a directory.
---
--@param filename (string) path to check
@@ -397,9 +428,8 @@ end
--@param trace: "off" | "messages" | "verbose" | nil passed directly to the language
--- server in the initialize request. Invalid/empty values will default to "off"
---
---@returns Client id. |vim.lsp.get_client_by_id()| Note: client is only
---- available after it has been initialized, which may happen after a small
---- delay (or never if there is an error). Use `on_init` to do any actions once
+--@returns Client id. |vim.lsp.get_client_by_id()| Note: client may not be
+--- fully initialized. Use `on_init` to do any actions once
--- the client has been initialized.
function lsp.start_client(config)
local cleaned_config = validate_client_config(config)
@@ -576,6 +606,15 @@ function lsp.start_client(config)
-- These are the cleaned up capabilities we use for dynamically deciding
-- when to send certain events to clients.
client.resolved_capabilities = protocol.resolve_capabilities(client.server_capabilities)
+ client.supports_method = function(method)
+ local required_capability = lsp._request_name_to_capability[method]
+ -- if we don't know about the method, assume that the client supports it.
+ if not required_capability then
+ return true
+ end
+
+ return client.resolved_capabilities[required_capability]
+ end
if config.on_init then
local status, err = pcall(config.on_init, client, result)
if not status then
@@ -599,19 +638,6 @@ function lsp.start_client(config)
end
--@private
- --- Throws error for a method that is not supported by the current LSP
- --- server.
- ---
- --@param method (string) an LSP method name not supported by the LSP server.
- --@returns (error) a 'MethodNotFound' JSON-RPC error response.
- local function unsupported_method(method)
- local msg = "server doesn't support "..method
- local _ = log.warn() and log.warn(msg)
- err_message(msg)
- return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg)
- end
-
- --@private
--- Sends a request to the server.
---
--- This is a thin wrapper around {client.rpc.request} with some additional
@@ -638,20 +664,6 @@ function lsp.start_client(config)
or error(string.format("not found: %q request callback for client %q.", method, client.name))
end
local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, callback, bufnr)
- -- TODO keep these checks or just let it go anyway?
- if (not client.resolved_capabilities.hover and method == 'textDocument/hover')
- or (not client.resolved_capabilities.signature_help and method == 'textDocument/signatureHelp')
- or (not client.resolved_capabilities.goto_definition and method == 'textDocument/definition')
- or (not client.resolved_capabilities.implementation and method == 'textDocument/implementation')
- or (not client.resolved_capabilities.declaration and method == 'textDocument/declaration')
- or (not client.resolved_capabilities.type_definition and method == 'textDocument/typeDefinition')
- or (not client.resolved_capabilities.document_symbol and method == 'textDocument/documentSymbol')
- or (not client.resolved_capabilities.workspace_symbol and method == 'textDocument/workspaceSymbol')
- or (not client.resolved_capabilities.call_hierarchy and method == 'textDocument/prepareCallHierarchy')
- then
- callback(unsupported_method(method), method, nil, client_id, bufnr)
- return
- end
return rpc.request(method, params, function(err, result)
callback(err, method, result, client_id, bufnr)
end)
@@ -910,14 +922,14 @@ function lsp.buf_is_attached(bufnr, client_id)
return (all_buffer_active_clients[bufnr] or {})[client_id] == true
end
---- Gets an active client by id, or nil if the id is invalid or the
---- client is not yet initialized.
----
+--- Gets a client by id, or nil if the id is invalid.
+--- The returned client may not yet be fully initialized.
+--
--@param client_id client id number
---
--@returns |vim.lsp.client| object, or nil
function lsp.get_client_by_id(client_id)
- return active_clients[client_id]
+ return active_clients[client_id] or uninitialized_clients[client_id]
end
--- Stops a client(s).
@@ -998,16 +1010,32 @@ function lsp.buf_request(bufnr, method, params, callback)
callback = { callback, 'f', true };
}
local client_request_ids = {}
- for_each_buffer_client(bufnr, function(client, client_id, resolved_bufnr)
- local request_success, request_id = client.request(method, params, callback, resolved_bufnr)
- -- This could only fail if the client shut down in the time since we looked
- -- it up and we did the request, which should be rare.
- if request_success then
- client_request_ids[client_id] = request_id
+ local method_supported = false
+ for_each_buffer_client(bufnr, function(client, client_id, resolved_bufnr)
+ if client.supports_method(method) then
+ method_supported = true
+ local request_success, request_id = client.request(method, params, callback, resolved_bufnr)
+
+ -- This could only fail if the client shut down in the time since we looked
+ -- it up and we did the request, which should be rare.
+ if request_success then
+ client_request_ids[client_id] = request_id
+ end
end
end)
+ -- if no clients support the given method, call the callback with the proper
+ -- error message.
+ if not method_supported then
+ local unsupported_err = lsp._unsupported_method(method)
+ local cb = callback or lsp.callbacks['method']
+ if cb then
+ cb(unsupported_err, method, bufnr)
+ end
+ return
+ end
+
local function _cancel_all_requests()
for client_id, request_id in pairs(client_request_ids) do
local client = active_clients[client_id]
diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua
index 4e7a8333a0..3270d1d2a9 100644
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ b/runtime/lua/vim/lsp/callbacks.lua
@@ -82,18 +82,6 @@ M['textDocument/publishDiagnostics'] = function(_, _, result)
return
end
- -- Unloaded buffers should not handle diagnostics.
- -- When the buffer is loaded, we'll call on_attach, which sends textDocument/didOpen.
- -- This should trigger another publish of the diagnostics.
- --
- -- In particular, this stops a ton of spam when first starting a server for current
- -- unloaded buffers.
- if not api.nvim_buf_is_loaded(bufnr) then
- return
- end
-
- util.buf_clear_diagnostics(bufnr)
-
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
-- The diagnostic's severity. Can be omitted. If omitted it is up to the
-- client to interpret diagnostics as error, warning, info or hint.
@@ -104,7 +92,23 @@ M['textDocument/publishDiagnostics'] = function(_, _, result)
end
end
+ util.buf_clear_diagnostics(bufnr)
+
+ -- Always save the diagnostics, even if the buf is not loaded.
+ -- Language servers may report compile or build errors via diagnostics
+ -- Users should be able to find these, even if they're in files which
+ -- are not loaded.
util.buf_diagnostics_save_positions(bufnr, result.diagnostics)
+
+ -- Unloaded buffers should not handle diagnostics.
+ -- When the buffer is loaded, we'll call on_attach, which sends textDocument/didOpen.
+ -- This should trigger another publish of the diagnostics.
+ --
+ -- In particular, this stops a ton of spam when first starting a server for current
+ -- unloaded buffers.
+ if not api.nvim_buf_is_loaded(bufnr) then
+ return
+ end
util.buf_diagnostics_underline(bufnr, result.diagnostics)
util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)
util.buf_diagnostics_signs(bufnr, result.diagnostics)
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 4e926381e0..2773f59b45 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -703,6 +703,10 @@ function protocol.make_client_capabilities()
};
hierarchicalDocumentSymbolSupport = true;
};
+ rename = {
+ dynamicRegistration = false;
+ prepareSupport = true;
+ };
};
workspace = {
symbol = {
@@ -914,6 +918,7 @@ function protocol.resolve_capabilities(server_capabilities)
return nil, string.format("Invalid type for textDocumentSync: %q", type(textDocumentSync))
end
end
+ general_properties.completion = server_capabilities.completionProvider ~= nil
general_properties.hover = server_capabilities.hoverProvider or false
general_properties.goto_definition = server_capabilities.definitionProvider or false
general_properties.find_references = server_capabilities.referencesProvider or false
@@ -923,6 +928,15 @@ function protocol.resolve_capabilities(server_capabilities)
general_properties.document_formatting = server_capabilities.documentFormattingProvider or false
general_properties.document_range_formatting = server_capabilities.documentRangeFormattingProvider or false
general_properties.call_hierarchy = server_capabilities.callHierarchyProvider or false
+ general_properties.execute_command = server_capabilities.executeCommandProvider ~= nil
+
+ if server_capabilities.renameProvider == nil then
+ general_properties.rename = false
+ elseif type(server_capabilities.renameProvider) == 'boolean' then
+ general_properties.rename = server_capabilities.renameProvider
+ else
+ general_properties.rename = true
+ end
if server_capabilities.codeActionProvider == nil then
general_properties.code_action = false
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 53f88dea7d..b5f171a985 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -807,7 +807,7 @@ function M.fancy_floating_markdown(contents, opts)
h.start = h.start + i - 1
h.finish = h.finish + i - 1
if h.finish + 1 <= #stripped then
- table.insert(stripped, h.finish + 1, string.rep("─", math.min(width, opts.wrap_at)))
+ table.insert(stripped, h.finish + 1, string.rep("─", math.min(width, opts.wrap_at or width)))
height = height + 1
end
end
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 5c89c63f7b..995c52e8ed 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -477,48 +477,77 @@ end
--- 2. (arg_value, fn, msg)
--- - arg_value: argument value
--- - fn: any function accepting one argument, returns true if and
---- only if the argument is valid
+--- only if the argument is valid. Can optionally return an additional
+--- informative error message as the second returned value.
--- - msg: (optional) error string if validation fails
function vim.validate(opt) end -- luacheck: no unused
-vim.validate = (function()
+
+do
local type_names = {
- t='table', s='string', n='number', b='boolean', f='function', c='callable',
- ['table']='table', ['string']='string', ['number']='number',
- ['boolean']='boolean', ['function']='function', ['callable']='callable',
- ['nil']='nil', ['thread']='thread', ['userdata']='userdata',
+ ['table'] = 'table', t = 'table',
+ ['string'] = 'string', s = 'string',
+ ['number'] = 'number', n = 'number',
+ ['boolean'] = 'boolean', b = 'boolean',
+ ['function'] = 'function', f = 'function',
+ ['callable'] = 'callable', c = 'callable',
+ ['nil'] = 'nil',
+ ['thread'] = 'thread',
+ ['userdata'] = 'userdata',
}
- local function _type_name(t)
- local tname = type_names[t]
- if tname == nil then
- error(string.format('invalid type name: %s', tostring(t)))
- end
- return tname
- end
+
local function _is_type(val, t)
return t == 'callable' and vim.is_callable(val) or type(val) == t
end
- return function(opt)
- assert(type(opt) == 'table', string.format('opt: expected table, got %s', type(opt)))
+ local function is_valid(opt)
+ if type(opt) ~= 'table' then
+ return false, string.format('opt: expected table, got %s', type(opt))
+ end
+
for param_name, spec in pairs(opt) do
- assert(type(spec) == 'table', string.format('%s: expected table, got %s', param_name, type(spec)))
+ if type(spec) ~= 'table' then
+ return false, string.format('opt[%s]: expected table, got %s', param_name, type(spec))
+ end
local val = spec[1] -- Argument value.
local t = spec[2] -- Type name, or callable.
local optional = (true == spec[3])
- if not vim.is_callable(t) then -- Check type name.
- if (not optional or val ~= nil) and not _is_type(val, _type_name(t)) then
- error(string.format("%s: expected %s, got %s", param_name, _type_name(t), type(val)))
+ if type(t) == 'string' then
+ local t_name = type_names[t]
+ if not t_name then
+ return false, string.format('invalid type name: %s', t)
+ end
+
+ if (not optional or val ~= nil) and not _is_type(val, t_name) then
+ return false, string.format("%s: expected %s, got %s", param_name, t_name, type(val))
+ end
+ elseif vim.is_callable(t) then
+ -- Check user-provided validation function.
+ local valid, optional_message = t(val)
+ if not valid then
+ local error_message = string.format("%s: expected %s, got %s", param_name, (spec[3] or '?'), val)
+ if optional_message ~= nil then
+ error_message = error_message .. string.format(". Info: %s", optional_message)
+ end
+
+ return false, error_message
end
- elseif not t(val) then -- Check user-provided validation function.
- error(string.format("%s: expected %s, got %s", param_name, (spec[3] or '?'), val))
+ else
+ return false, string.format("invalid type name: %s", tostring(t))
end
end
- return true
+
+ return true, nil
end
-end)()
+ function vim.validate(opt)
+ local ok, err_msg = is_valid(opt)
+ if not ok then
+ error(debug.traceback(err_msg, 2), 2)
+ end
+ end
+end
--- Returns true if object `f` can be called as a function.
---
--@param f Any object
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index 77bbfaa3ad..0de3388356 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -59,6 +59,24 @@ function Parser:_on_bytes(bufnr, changed_tick,
end
end
+--- Registers callbacks for the parser
+-- @param cbs An `nvim_buf_attach`-like table argument with the following keys :
+-- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
+-- `on_changedtree` : a callback that will be called everytime the tree has syntactical changes.
+-- it will only be passed one argument, that is a table of the ranges (as node ranges) that
+-- changed.
+function Parser:register_cbs(cbs)
+ if not cbs then return end
+
+ if cbs.on_changedtree then
+ table.insert(self.changedtree_cbs, cbs.on_changedtree)
+ end
+
+ if cbs.on_bytes then
+ table.insert(self.bytes_cbs, cbs.on_bytes)
+ end
+end
+
--- Sets the included ranges for the current parser
--
-- @param ranges A table of nodes that will be used as the ranges the parser should include.
@@ -68,6 +86,11 @@ function Parser:set_included_ranges(ranges)
self.valid = false
end
+--- Gets the included ranges for the parsers
+function Parser:included_ranges()
+ return self._parser:included_ranges()
+end
+
local M = vim.tbl_extend("error", query, language)
setmetatable(M, {
@@ -127,11 +150,7 @@ end
--
-- @param bufnr The buffer the parser should be tied to
-- @param ft The filetype of this parser
--- @param buf_attach_cbs An `nvim_buf_attach`-like table argument with the following keys :
--- `on_lines` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
--- `on_changedtree` : a callback that will be called everytime the tree has syntactical changes.
--- it will only be passed one argument, that is a table of the ranges (as node ranges) that
--- changed.
+-- @param buf_attach_cbs See Parser:register_cbs
--
-- @returns The parser
function M.get_parser(bufnr, lang, buf_attach_cbs)
@@ -147,13 +166,7 @@ function M.get_parser(bufnr, lang, buf_attach_cbs)
parsers[id] = M._create_parser(bufnr, lang, id)
end
- if buf_attach_cbs and buf_attach_cbs.on_changedtree then
- table.insert(parsers[id].changedtree_cbs, buf_attach_cbs.on_changedtree)
- end
-
- if buf_attach_cbs and buf_attach_cbs.on_bytes then
- table.insert(parsers[id].bytes_cbs, buf_attach_cbs.on_bytes)
- end
+ parsers[id]:register_cbs(buf_attach_cbs)
return parsers[id]
end
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 0f497fe434..decde08019 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -8,7 +8,7 @@ TSHighlighter.active = TSHighlighter.active or {}
local ns = a.nvim_create_namespace("treesitter/highlighter")
--- These are conventions defined by tree-sitter, though it
+-- These are conventions defined by nvim-treesitter, though it
-- needs to be user extensible also.
TSHighlighter.hl_map = {
["error"] = "Error",
@@ -56,21 +56,14 @@ TSHighlighter.hl_map = {
["include"] = "Include",
}
-function TSHighlighter.new(query, bufnr, ft)
- if bufnr == nil or bufnr == 0 then
- bufnr = a.nvim_get_current_buf()
- end
-
+function TSHighlighter.new(parser, query)
local self = setmetatable({}, TSHighlighter)
- self.parser = vim.treesitter.get_parser(
- bufnr,
- ft,
- {
- on_changedtree = function(...) self:on_changedtree(...) end,
- }
- )
-
- self.buf = self.parser.bufnr
+
+ self.parser = parser
+ parser:register_cbs {
+ on_changedtree = function(...) self:on_changedtree(...) end
+ }
+
self:set_query(query)
self.edit_count = 0
self.redraw_count = 0
@@ -79,7 +72,11 @@ function TSHighlighter.new(query, bufnr, ft)
a.nvim_buf_set_option(self.buf, "syntax", "")
-- TODO(bfredl): can has multiple highlighters per buffer????
- TSHighlighter.active[bufnr] = self
+ if not TSHighlighter.active[parser.bufnr] then
+ TSHighlighter.active[parser.bufnr] = {}
+ end
+
+ TSHighlighter.active[parser.bufnr][parser.lang] = self
-- Tricky: if syntax hasn't been enabled, we need to reload color scheme
-- but use synload.vim rather than syntax.vim to not enable
@@ -119,13 +116,6 @@ end
function TSHighlighter:set_query(query)
if type(query) == "string" then
query = vim.treesitter.parse_query(self.parser.lang, query)
- elseif query == nil then
- query = vim.treesitter.get_query(self.parser.lang, 'highlights')
-
- if query == nil then
- a.nvim_err_writeln("No highlights.scm query found for " .. self.parser.lang)
- query = vim.treesitter.parse_query(self.parser.lang, "")
- end
end
self.query = query
@@ -139,12 +129,16 @@ function TSHighlighter:set_query(query)
end
})
- a.nvim__buf_redraw_range(self.buf, 0, a.nvim_buf_line_count(self.buf))
+ a.nvim__buf_redraw_range(self.parser.bufnr, 0, a.nvim_buf_line_count(self.parser.bufnr))
end
-function TSHighlighter._on_line(_, _win, buf, line)
- -- on_line is only called when this is non-nil
- local self = TSHighlighter.active[buf]
+local function iter_active_tshl(buf, fn)
+ for _, hl in pairs(TSHighlighter.active[buf] or {}) do
+ fn(hl)
+ end
+end
+
+local function on_line_impl(self, buf, line)
if self.root == nil then
return -- parser bought the farm already
end
@@ -172,24 +166,38 @@ function TSHighlighter._on_line(_, _win, buf, line)
end
end
-function TSHighlighter._on_buf(_, buf)
- local self = TSHighlighter.active[buf]
- if self then
- local tree = self.parser:parse()
- self.root = (tree and tree:root()) or nil
+function TSHighlighter._on_line(_, _win, buf, line, highlighter)
+ -- on_line is only called when this is non-nil
+ if highlighter then
+ on_line_impl(highlighter, buf, line)
+ else
+ iter_active_tshl(buf, function(self)
+ on_line_impl(self, buf, line)
+ end)
end
end
+function TSHighlighter._on_buf(_, buf)
+ iter_active_tshl(buf, function(self)
+ if self then
+ local tree = self.parser:parse()
+ self.root = (tree and tree:root()) or nil
+ end
+ end)
+end
+
function TSHighlighter._on_win(_, _win, buf, _topline, botline)
- local self = TSHighlighter.active[buf]
- if not self then
- return false
- end
+ iter_active_tshl(buf, function(self)
+ if not self then
+ return false
+ end
- self.iter = nil
- self.nextrow = 0
- self.botline = botline
- self.redraw_count = self.redraw_count + 1
+ self.iter = nil
+ self.nextrow = 0
+ self.botline = botline
+ self.redraw_count = self.redraw_count + 1
+ return true
+ end)
return true
end
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 494fb59fa7..2903c5905c 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -8,6 +8,104 @@ Query.__index = Query
local M = {}
+-- Filter the runtime query files, the spec is like regular runtime files but in the new `queries`
+-- directory. They resemble ftplugins, that is that you can override queries by adding things in the
+-- `queries` directory, and extend using the `after/queries` directory.
+local function filter_files(file_list)
+ local main = nil
+ local after = {}
+
+ for _, fname in ipairs(file_list) do
+ -- Only get the name of the directory containing the queries directory
+ if vim.fn.fnamemodify(fname, ":p:h:h:h:t") == "after" then
+ table.insert(after, fname)
+ -- The first one is the one with most priority
+ elseif not main then
+ main = fname
+ end
+ end
+
+ return { main, unpack(after) }
+end
+
+local function runtime_query_path(lang, query_name)
+ return string.format('queries/%s/%s.scm', lang, query_name)
+end
+
+local function filtered_runtime_queries(lang, query_name)
+ return filter_files(a.nvim_get_runtime_file(runtime_query_path(lang, query_name), true) or {})
+end
+
+local function get_query_files(lang, query_name, is_included)
+ local lang_files = filtered_runtime_queries(lang, query_name)
+ local query_files = lang_files
+
+ if #query_files == 0 then return {} end
+
+ local base_langs = {}
+
+ -- Now get the base languages by looking at the first line of every file
+ -- The syntax is the folowing :
+ -- ;+ inherits: ({language},)*{language}
+ --
+ -- {language} ::= {lang} | ({lang})
+ local MODELINE_FORMAT = "^;+%s*inherits%s*:?%s*([a-z_,()]+)%s*$"
+
+ for _, file in ipairs(query_files) do
+ local modeline = vim.fn.readfile(file, "", 1)
+
+ if #modeline == 1 then
+ local langlist = modeline[1]:match(MODELINE_FORMAT)
+
+ if langlist then
+ for _, incllang in ipairs(vim.split(langlist, ',', true)) do
+ local is_optional = incllang:match("%(.*%)")
+
+ if is_optional then
+ if not is_included then
+ table.insert(base_langs, incllang:sub(2, #incllang - 1))
+ end
+ else
+ table.insert(base_langs, incllang)
+ end
+ end
+ end
+ end
+ end
+
+ for _, base_lang in ipairs(base_langs) do
+ local base_files = get_query_files(base_lang, query_name, true)
+ vim.list_extend(query_files, base_files)
+ end
+
+ return query_files
+end
+
+local function read_query_files(filenames)
+ local contents = {}
+
+ for _,filename in ipairs(filenames) do
+ vim.list_extend(contents, vim.fn.readfile(filename))
+ end
+
+ return table.concat(contents, '\n')
+end
+
+--- Returns the runtime query {query_name} for {lang}.
+--
+-- @param lang The language to use for the query
+-- @param query_name The name of the query (i.e. "highlights")
+--
+-- @return The corresponding query, parsed.
+function M.get_query(lang, query_name)
+ local query_files = get_query_files(lang, query_name)
+ local query_string = read_query_files(query_files)
+
+ if #query_string > 0 then
+ return M.parse_query(lang, query_string)
+ end
+end
+
--- Parses a query.
--
-- @param language The language
diff --git a/runtime/queries/c/highlights.scm b/runtime/queries/c/highlights.scm
new file mode 100644
index 0000000000..96b43cf0d0
--- /dev/null
+++ b/runtime/queries/c/highlights.scm
@@ -0,0 +1,151 @@
+(identifier) @variable
+
+[
+ "const"
+ "default"
+ "enum"
+ "extern"
+ "inline"
+ "return"
+ "sizeof"
+ "static"
+ "struct"
+ "typedef"
+ "union"
+ "volatile"
+ "goto"
+] @keyword
+
+[
+ "while"
+ "for"
+ "do"
+ "continue"
+ "break"
+] @repeat
+
+[
+ "if"
+ "else"
+ "case"
+ "switch"
+] @conditional
+
+"#define" @constant.macro
+[
+ "#if"
+ "#ifdef"
+ "#ifndef"
+ "#else"
+ "#elif"
+ "#endif"
+ (preproc_directive)
+] @keyword
+
+"#include" @include
+
+[
+ "="
+
+ "-"
+ "*"
+ "/"
+ "+"
+ "%"
+
+ "~"
+ "|"
+ "&"
+ "^"
+ "<<"
+ ">>"
+
+ "->"
+
+ "<"
+ "<="
+ ">="
+ ">"
+ "=="
+ "!="
+
+ "!"
+ "&&"
+ "||"
+
+ "-="
+ "+="
+ "*="
+ "/="
+ "%="
+ "|="
+ "&="
+ "^="
+ "--"
+ "++"
+] @operator
+
+[
+ (true)
+ (false)
+] @boolean
+
+[ "." ";" ":" "," ] @punctuation.delimiter
+
+(conditional_expression [ "?" ":" ] @conditional)
+
+
+[ "(" ")" "[" "]" "{" "}"] @punctuation.bracket
+
+(string_literal) @string
+(system_lib_string) @string
+
+(null) @constant.builtin
+(number_literal) @number
+(char_literal) @number
+
+(call_expression
+ function: (identifier) @function)
+(call_expression
+ function: (field_expression
+ field: (field_identifier) @function))
+(function_declarator
+ declarator: (identifier) @function)
+(preproc_function_def
+ name: (identifier) @function.macro)
+[
+ (preproc_arg)
+ (preproc_defined)
+] @function.macro
+; TODO (preproc_arg) @embedded
+
+(field_identifier) @property
+(statement_identifier) @label
+
+[
+(type_identifier)
+(primitive_type)
+(sized_type_specifier)
+(type_descriptor)
+ ] @type
+
+(declaration type: [(identifier) (type_identifier)] @type)
+(cast_expression type: [(identifier) (type_identifier)] @type)
+(sizeof_expression value: (parenthesized_expression (identifier) @type))
+
+((identifier) @constant
+ (#match? @constant "^[A-Z][A-Z0-9_]+$"))
+
+(comment) @comment
+
+;; Parameters
+(parameter_declaration
+ declarator: (identifier) @parameter)
+
+(parameter_declaration
+ declarator: (pointer_declarator) @parameter)
+
+(preproc_params
+ (identifier)) @parameter
+
+(ERROR) @error
diff --git a/runtime/syntax/markdown.vim b/runtime/syntax/markdown.vim
index 1955a7443e..17b61c2fa4 100644
--- a/runtime/syntax/markdown.vim
+++ b/runtime/syntax/markdown.vim
@@ -2,7 +2,7 @@
" Language: Markdown
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" Filenames: *.markdown
-" Last Change: 2016 Aug 29
+" Last Change: 2020 Jan 14
if exists("b:current_syntax")
finish
@@ -18,37 +18,46 @@ unlet! b:current_syntax
if !exists('g:markdown_fenced_languages')
let g:markdown_fenced_languages = []
endif
+let s:done_include = {}
for s:type in map(copy(g:markdown_fenced_languages),'matchstr(v:val,"[^=]*$")')
+ if has_key(s:done_include, matchstr(s:type,'[^.]*'))
+ continue
+ endif
if s:type =~ '\.'
let b:{matchstr(s:type,'[^.]*')}_subtype = matchstr(s:type,'\.\zs.*')
endif
exe 'syn include @markdownHighlight'.substitute(s:type,'\.','','g').' syntax/'.matchstr(s:type,'[^.]*').'.vim'
unlet! b:current_syntax
+ let s:done_include[matchstr(s:type,'[^.]*')] = 1
endfor
unlet! s:type
+unlet! s:done_include
-syn sync minlines=10
+if !exists('g:markdown_minlines')
+ let g:markdown_minlines = 50
+endif
+execute 'syn sync minlines=' . g:markdown_minlines
syn case ignore
-syn match markdownValid '[<>]\c[a-z/$!]\@!'
-syn match markdownValid '&\%(#\=\w*;\)\@!'
+syn match markdownValid '[<>]\c[a-z/$!]\@!' transparent contains=NONE
+syn match markdownValid '&\%(#\=\w*;\)\@!' transparent contains=NONE
syn match markdownLineStart "^[<@]\@!" nextgroup=@markdownBlock,htmlSpecialChar
syn cluster markdownBlock contains=markdownH1,markdownH2,markdownH3,markdownH4,markdownH5,markdownH6,markdownBlockquote,markdownListMarker,markdownOrderedListMarker,markdownCodeBlock,markdownRule
-syn cluster markdownInline contains=markdownLineBreak,markdownLinkText,markdownItalic,markdownBold,markdownCode,markdownEscape,@htmlTop,markdownError
+syn cluster markdownInline contains=markdownLineBreak,markdownLinkText,markdownItalic,markdownBold,markdownCode,markdownEscape,@htmlTop,markdownError,markdownValid
syn match markdownH1 "^.\+\n=\+$" contained contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink
syn match markdownH2 "^.\+\n-\+$" contained contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink
syn match markdownHeadingRule "^[=-]\+$" contained
-syn region markdownH1 matchgroup=markdownHeadingDelimiter start="##\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH2 matchgroup=markdownHeadingDelimiter start="###\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH3 matchgroup=markdownHeadingDelimiter start="####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH4 matchgroup=markdownHeadingDelimiter start="#####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH5 matchgroup=markdownHeadingDelimiter start="######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
-syn region markdownH6 matchgroup=markdownHeadingDelimiter start="#######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH1 matchgroup=markdownH1Delimiter start="##\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH2 matchgroup=markdownH2Delimiter start="###\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH3 matchgroup=markdownH3Delimiter start="####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH4 matchgroup=markdownH4Delimiter start="#####\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH5 matchgroup=markdownH5Delimiter start="######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
+syn region markdownH6 matchgroup=markdownH6Delimiter start="#######\@!" end="#*\s*$" keepend oneline contains=@markdownInline,markdownAutomaticLink contained
syn match markdownBlockquote ">\%(\s\|$\)" contained nextgroup=@markdownBlock
@@ -70,31 +79,40 @@ syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+"+ end=+
syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+'+ end=+'+ keepend contained
syn region markdownUrlTitle matchgroup=markdownUrlTitleDelimiter start=+(+ end=+)+ keepend contained
-syn region markdownLinkText matchgroup=markdownLinkTextDelimiter start="!\=\[\%(\_[^]]*]\%( \=[[(]\)\)\@=" end="\]\%( \=[[(]\)\@=" nextgroup=markdownLink,markdownId skipwhite contains=@markdownInline,markdownLineStart
+syn region markdownLinkText matchgroup=markdownLinkTextDelimiter start="!\=\[\%(\%(\_[^][]\|\[\_[^][]*\]\)*]\%( \=[[(]\)\)\@=" end="\]\%( \=[[(]\)\@=" nextgroup=markdownLink,markdownId skipwhite contains=@markdownInline,markdownLineStart
syn region markdownLink matchgroup=markdownLinkDelimiter start="(" end=")" contains=markdownUrl keepend contained
syn region markdownId matchgroup=markdownIdDelimiter start="\[" end="\]" keepend contained
syn region markdownAutomaticLink matchgroup=markdownUrlDelimiter start="<\%(\w\+:\|[[:alnum:]_+-]\+@\)\@=" end=">" keepend oneline
-let s:concealends = has('conceal') ? ' concealends' : ''
-exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\S\@<=\*\|\*\S\@=" end="\S\@<=\*\|\*\S\@=" keepend contains=markdownLineStart' . s:concealends
-exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\S\@<=_\|_\S\@=" end="\S\@<=_\|_\S\@=" keepend contains=markdownLineStart' . s:concealends
-exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\S\@<=\*\*\|\*\*\S\@=" end="\S\@<=\*\*\|\*\*\S\@=" keepend contains=markdownLineStart,markdownItalic' . s:concealends
-exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\S\@<=__\|__\S\@=" end="\S\@<=__\|__\S\@=" keepend contains=markdownLineStart,markdownItalic' . s:concealends
-exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\S\@<=\*\*\*\|\*\*\*\S\@=" end="\S\@<=\*\*\*\|\*\*\*\S\@=" keepend contains=markdownLineStart' . s:concealends
-exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\S\@<=___\|___\S\@=" end="\S\@<=___\|___\S\@=" keepend contains=markdownLineStart' . s:concealends
+let s:concealends = ''
+if has('conceal') && get(g:, 'markdown_syntax_conceal', 1) == 1
+ let s:concealends = ' concealends'
+endif
+exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\S\@<=\*\|\*\S\@=" end="\S\@<=\*\|\*\S\@=" skip="\\\*" contains=markdownLineStart,@Spell' . s:concealends
+exe 'syn region markdownItalic matchgroup=markdownItalicDelimiter start="\w\@<!_\S\@=" end="\S\@<=_\w\@!" skip="\\_" contains=markdownLineStart,@Spell' . s:concealends
+exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\S\@<=\*\*\|\*\*\S\@=" end="\S\@<=\*\*\|\*\*\S\@=" skip="\\\*" contains=markdownLineStart,markdownItalic,@Spell' . s:concealends
+exe 'syn region markdownBold matchgroup=markdownBoldDelimiter start="\w\@<!__\S\@=" end="\S\@<=__\w\@!" skip="\\_" contains=markdownLineStart,markdownItalic,@Spell' . s:concealends
+exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\S\@<=\*\*\*\|\*\*\*\S\@=" end="\S\@<=\*\*\*\|\*\*\*\S\@=" skip="\\\*" contains=markdownLineStart,@Spell' . s:concealends
+exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start="\w\@<!___\S\@=" end="\S\@<=___\w\@!" skip="\\_" contains=markdownLineStart,@Spell' . s:concealends
syn region markdownCode matchgroup=markdownCodeDelimiter start="`" end="`" keepend contains=markdownLineStart
syn region markdownCode matchgroup=markdownCodeDelimiter start="`` \=" end=" \=``" keepend contains=markdownLineStart
-syn region markdownCode matchgroup=markdownCodeDelimiter start="^\s*```.*$" end="^\s*```\ze\s*$" keepend
+syn region markdownCode matchgroup=markdownCodeDelimiter start="^\s*````*.*$" end="^\s*````*\ze\s*$" keepend
syn match markdownFootnote "\[^[^\]]\+\]"
syn match markdownFootnoteDefinition "^\[^[^\]]\+\]:"
if main_syntax ==# 'markdown'
+ let s:done_include = {}
for s:type in g:markdown_fenced_languages
- exe 'syn region markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\..*','','').' matchgroup=markdownCodeDelimiter start="^\s*```\s*'.matchstr(s:type,'[^=]*').'\>.*$" end="^\s*```\ze\s*$" keepend contains=@markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\.','','g')
+ if has_key(s:done_include, matchstr(s:type,'[^.]*'))
+ continue
+ endif
+ exe 'syn region markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\..*','','').' matchgroup=markdownCodeDelimiter start="^\s*````*\s*\%({.\{-}\.\)\='.matchstr(s:type,'[^=]*').'}\=\S\@!.*$" end="^\s*````*\ze\s*$" keepend contains=@markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\.','','g') . s:concealends
+ let s:done_include[matchstr(s:type,'[^.]*')] = 1
endfor
unlet! s:type
+ unlet! s:done_include
endif
syn match markdownEscape "\\[][\\`*_{}()<>#+.!-]"
@@ -107,6 +125,12 @@ hi def link markdownH4 htmlH4
hi def link markdownH5 htmlH5
hi def link markdownH6 htmlH6
hi def link markdownHeadingRule markdownRule
+hi def link markdownH1Delimiter markdownHeadingDelimiter
+hi def link markdownH2Delimiter markdownHeadingDelimiter
+hi def link markdownH3Delimiter markdownHeadingDelimiter
+hi def link markdownH4Delimiter markdownHeadingDelimiter
+hi def link markdownH5Delimiter markdownHeadingDelimiter
+hi def link markdownH6Delimiter markdownHeadingDelimiter
hi def link markdownHeadingDelimiter Delimiter
hi def link markdownOrderedListMarker markdownListMarker
hi def link markdownListMarker htmlTagName
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 03f52bd162..8287958ab5 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -597,8 +597,11 @@ list_missing_previous_vimpatches_for_patch() {
set -u
local -a missing_unique
+ local stat
while IFS= read -r line; do
- missing_unique+=("$line")
+ local commit="${line%%:*}"
+ stat="$(git -C "${VIM_SOURCE_DIR}" show --format= --shortstat "${commit}")"
+ missing_unique+=("$(printf '%s\n %s' "$line" "$stat")")
done < <(printf '%s\n' "${missing_list[@]}" | sort -u)
msg_err "$(printf '%d missing previous Vim patches:' ${#missing_unique[@]})"
diff --git a/src/clint.py b/src/clint.py
index 8dc41fdb93..9b4128a0c9 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -350,7 +350,7 @@ def IsErrorInSuppressedErrorsList(category, linenum):
category: str, the category of the error.
linenum: int, the current line number.
Returns:
- bool, True iff the error should be suppressed due to presense in
+ bool, True iff the error should be suppressed due to presence in
suppressions file.
"""
return (category, linenum) in _error_suppressions_2
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index c8dd85b39d..cad4c8314f 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -953,6 +953,53 @@ Boolean nvim_buf_is_loaded(Buffer buffer)
return buf && buf->b_ml.ml_mfp != NULL;
}
+/// Deletes the buffer. See |:bwipeout|
+///
+/// @param buffer Buffer handle, or 0 for current buffer
+/// @param opts Optional parameters. Keys:
+/// - force: Force deletion and ignore unsaved changes.
+/// - unload: Unloaded only, do not delete. See |:bunload|
+void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err)
+ FUNC_API_SINCE(7)
+{
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+
+ if (ERROR_SET(err)) {
+ return;
+ }
+
+ bool force = false;
+ bool unload = false;
+ for (size_t i = 0; i < opts.size; i++) {
+ String k = opts.items[i].key;
+ Object v = opts.items[i].value;
+ if (strequal("force", k.data)) {
+ force = api_coerce_to_bool(v, "force", false, err);
+ } else if (strequal("unload", k.data)) {
+ unload = api_coerce_to_bool(v, "unload", false, err);
+ } else {
+ api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ return;
+ }
+ }
+
+ if (ERROR_SET(err)) {
+ return;
+ }
+
+ int result = do_buffer(
+ unload ? DOBUF_UNLOAD : DOBUF_WIPE,
+ DOBUF_FIRST,
+ FORWARD,
+ buf->handle,
+ force);
+
+ if (result == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to unload buffer.");
+ return;
+ }
+}
+
/// Checks if a buffer is valid.
///
/// @note Even if a buffer is valid it may have been unloaded. See |api-buffer|
@@ -1394,7 +1441,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
goto error;
}
} else if (strequal("ephemeral", k.data)) {
- ephemeral = api_is_truthy(*v, "ephemeral", false, err);
+ ephemeral = api_coerce_to_bool(*v, "ephemeral", false, err);
if (ERROR_SET(err)) {
goto error;
}
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 84517c99fc..981d41ae6e 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1619,14 +1619,24 @@ free_exit:
return virt_text;
}
-bool api_is_truthy(Object obj, const char *what, bool nil_truthy, Error *err)
+/// Force obj to bool.
+/// If it fails, returns false and sets err
+/// @param obj The object to coerce to a boolean
+/// @param what The name of the object, used for error message
+/// @param nil_value What to return if the type is nil.
+/// @param err Set if there was an error in converting to a bool
+bool api_coerce_to_bool(
+ Object obj,
+ const char *what,
+ bool nil_value,
+ Error *err)
{
if (obj.type == kObjectTypeBoolean) {
return obj.data.boolean;
} else if (obj.type == kObjectTypeInteger) {
return obj.data.integer; // C semantics: non-zero int is true
} else if (obj.type == kObjectTypeNil) {
- return nil_truthy; // caller decides what NIL (missing retval in lua) means
+ return nil_value; // caller decides what NIL (missing retval in lua) means
} else {
api_set_error(err, kErrorTypeValidation, "%s is not an boolean", what);
return false;
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index ef5e90bf5c..e934d5dc92 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -1,7 +1,7 @@
#ifndef NVIM_API_UI_EVENTS_IN_H
#define NVIM_API_UI_EVENTS_IN_H
-// This file is not compiled, just parsed for definitons
+// This file is not compiled, just parsed for definitions
#ifdef INCLUDE_GENERATED_DECLARATIONS
# error "don't include this file, include nvim/ui.h"
#endif
@@ -44,7 +44,7 @@ void option_set(String name, Object value)
void stop(void)
FUNC_API_NOEXPORT;
-// First revison of the grid protocol, used by default
+// First revision of the grid protocol, used by default
void update_fg(Integer fg)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void update_bg(Integer bg)
@@ -68,7 +68,7 @@ void set_scroll_region(Integer top, Integer bot, Integer left, Integer right)
void scroll(Integer count)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
-// Second revison of the grid protocol, used with ext_linegrid ui option
+// Second revision of the grid protocol, used with ext_linegrid ui option
void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
Integer cterm_fg, Integer cterm_bg)
FUNC_API_SINCE(4) FUNC_API_REMOTE_IMPL;
@@ -91,7 +91,7 @@ void grid_scroll(Integer grid, Integer top, Integer bot,
void grid_destroy(Integer grid)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
-// For perfomance and simplicity, we use the dense screen representation
+// For performance and simplicity, we use the dense screen representation
// in internal code, such as compositor and TUI. The remote_ui module will
// translate this in to the public grid_line format.
void raw_line(Integer grid, Integer row, Integer startcol,
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 4391d997a7..10647c01a4 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -65,7 +65,8 @@ return {
'InsertChange', -- when changing Insert/Replace mode
'InsertCharPre', -- before inserting a char
'InsertEnter', -- when entering Insert mode
- 'InsertLeave', -- when leaving Insert mode
+ 'InsertLeave', -- just after leaving Insert mode
+ 'InsertLeavePre', -- just before leaving Insert mode
'MenuPopup', -- just before popup menu is displayed
'OptionSet', -- after setting any option
'QuickFixCmdPost', -- after :make, :grep etc.
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index ec633dcc26..8f631ae13b 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -5397,13 +5397,11 @@ bool buf_hide(const buf_T *const buf)
char_u *buf_spname(buf_T *buf)
{
if (bt_quickfix(buf)) {
- win_T *win;
- tabpage_T *tp;
+ win_T *win;
+ tabpage_T *tp;
- /*
- * For location list window, w_llist_ref points to the location list.
- * For quickfix window, w_llist_ref is NULL.
- */
+ // For location list window, w_llist_ref points to the location list.
+ // For quickfix window, w_llist_ref is NULL.
if (find_win_for_buf(buf, &win, &tp) && win->w_llist_ref != NULL) {
return (char_u *)_(msg_loclist);
} else {
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 5e5a20e8f2..1223f2bdab 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -91,6 +91,7 @@ typedef struct {
#define BF_READERR 0x40 // got errors while reading the file
#define BF_DUMMY 0x80 // dummy buffer, only used internally
#define BF_PRESERVED 0x100 // ":preserve" was used
+#define BF_SYN_SET 0x200 // 'syntax' option was set
// Mask to check for flags that prevent normal writing
#define BF_WRITE_MASK (BF_NOTEDITED + BF_NEW + BF_READERR)
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 71614363d2..be52750c44 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -142,7 +142,6 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
long xtra)
{
int i;
- int cols;
pos_T *p;
int add;
@@ -170,7 +169,7 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
if (p->lnum != lnum) {
add = true;
} else {
- cols = comp_textwidth(false);
+ int cols = comp_textwidth(false);
if (cols == 0) {
cols = 79;
}
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index f9d5adbc12..fb158f377a 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -509,7 +509,7 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
// Does NOT work for multi-byte characters, c must be <= 255.
// Also doesn't work for the first byte of a multi-byte, "c" must be a
// character!
-static char_u transchar_buf[11];
+static char_u transchar_charbuf[11];
/// Translate a character into a printable one, leaving printable ASCII intact
///
@@ -520,11 +520,17 @@ static char_u transchar_buf[11];
/// @return translated character into a static buffer.
char_u *transchar(int c)
{
+ return transchar_buf(curbuf, c);
+}
+
+char_u *transchar_buf(const buf_T *buf, int c)
+ FUNC_ATTR_NONNULL_ALL
+{
int i = 0;
if (IS_SPECIAL(c)) {
// special key code, display as ~@ char
- transchar_buf[0] = '~';
- transchar_buf[1] = '@';
+ transchar_charbuf[0] = '~';
+ transchar_charbuf[1] = '@';
i = 2;
c = K_SECOND(c);
}
@@ -532,14 +538,14 @@ char_u *transchar(int c)
if ((!chartab_initialized && (((c >= ' ') && (c <= '~'))))
|| ((c <= 0xFF) && vim_isprintc_strict(c))) {
// printable character
- transchar_buf[i] = (char_u)c;
- transchar_buf[i + 1] = NUL;
+ transchar_charbuf[i] = (char_u)c;
+ transchar_charbuf[i + 1] = NUL;
} else if (c <= 0xFF) {
- transchar_nonprint(transchar_buf + i, c);
+ transchar_nonprint(buf, transchar_charbuf + i, c);
} else {
- transchar_hex((char *)transchar_buf + i, c);
+ transchar_hex((char *)transchar_charbuf + i, c);
}
- return transchar_buf;
+ return transchar_charbuf;
}
/// Like transchar(), but called with a byte instead of a character
@@ -548,13 +554,13 @@ char_u *transchar(int c)
///
/// @param[in] c Byte to translate.
///
-/// @return pointer to translated character in transchar_buf.
+/// @return pointer to translated character in transchar_charbuf.
char_u *transchar_byte(const int c)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (c >= 0x80) {
- transchar_nonprint(transchar_buf, c);
- return transchar_buf;
+ transchar_nonprint(curbuf, transchar_charbuf, c);
+ return transchar_charbuf;
}
return transchar(c);
}
@@ -563,16 +569,18 @@ char_u *transchar_byte(const int c)
///
/// @warning Does not work for multi-byte characters, c must be <= 255.
///
-/// @param[out] buf Buffer to store result in, must be able to hold at least
-/// 5 bytes (conversion result + NUL).
+/// @param[in] buf Required to check the file format
+/// @param[out] charbuf Buffer to store result in, must be able to hold
+/// at least 5 bytes (conversion result + NUL).
/// @param[in] c Character to convert. NUL is assumed to be NL according to
/// `:h NL-used-for-NUL`.
-void transchar_nonprint(char_u *buf, int c)
+void transchar_nonprint(const buf_T *buf, char_u *charbuf, int c)
+ FUNC_ATTR_NONNULL_ALL
{
if (c == NL) {
// we use newline in place of a NUL
c = NUL;
- } else if ((c == CAR) && (get_fileformat(curbuf) == EOL_MAC)) {
+ } else if ((c == CAR) && (get_fileformat(buf) == EOL_MAC)) {
// we use CR in place of NL in this case
c = NL;
}
@@ -580,14 +588,14 @@ void transchar_nonprint(char_u *buf, int c)
if (dy_flags & DY_UHEX || c > 0x7f) {
// 'display' has "uhex"
- transchar_hex((char *)buf, c);
+ transchar_hex((char *)charbuf, c);
} else {
// 0x00 - 0x1f and 0x7f
- buf[0] = '^';
+ charbuf[0] = '^';
// DEL displayed as ^?
- buf[1] = (char_u)(c ^ 0x40);
+ charbuf[1] = (char_u)(c ^ 0x40);
- buf[2] = NUL;
+ charbuf[2] = NUL;
}
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index de2346a9d8..b3261cfce6 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -5549,13 +5549,11 @@ void insertchar(
int second_indent // indent for second line if >= 0
)
{
- int textwidth;
char_u *p;
- int fo_ins_blank;
int force_format = flags & INSCHAR_FORMAT;
- textwidth = comp_textwidth(force_format);
- fo_ins_blank = has_format_option(FO_INS_BLANK);
+ const int textwidth = comp_textwidth(force_format);
+ const bool fo_ins_blank = has_format_option(FO_INS_BLANK);
/*
* Try to break the line in two or more pieces when:
@@ -5756,10 +5754,11 @@ internal_format (
int cc;
int save_char = NUL;
bool haveto_redraw = false;
- int fo_ins_blank = has_format_option(FO_INS_BLANK);
- int fo_multibyte = has_format_option(FO_MBYTE_BREAK);
- int fo_white_par = has_format_option(FO_WHITE_PAR);
- int first_line = TRUE;
+ const bool fo_ins_blank = has_format_option(FO_INS_BLANK);
+ const bool fo_multibyte = has_format_option(FO_MBYTE_BREAK);
+ const bool fo_rigor_tw = has_format_option(FO_RIGOROUS_TW);
+ const bool fo_white_par = has_format_option(FO_WHITE_PAR);
+ bool first_line = true;
colnr_T leader_len;
bool no_leader = false;
int do_comments = (flags & INSCHAR_DO_COM);
@@ -5838,6 +5837,7 @@ internal_format (
curwin->w_cursor.col = startcol;
foundcol = 0;
+ int skip_pos = 0;
/*
* Find position to break at.
@@ -5907,7 +5907,11 @@ internal_format (
foundcol = curwin->w_cursor.col;
if (curwin->w_cursor.col <= (colnr_T)wantcol)
break;
- } else if (cc >= 0x100 && fo_multibyte) {
+ } else if ((cc >= 0x100 || !utf_allow_break_before(cc))
+ && fo_multibyte) {
+ int ncc;
+ bool allow_break;
+
// Break after or before a multi-byte character.
if (curwin->w_cursor.col != startcol) {
// Don't break until after the comment leader
@@ -5916,8 +5920,11 @@ internal_format (
}
col = curwin->w_cursor.col;
inc_cursor();
- // Don't change end_foundcol if already set.
- if (foundcol != curwin->w_cursor.col) {
+ ncc = gchar_cursor();
+ allow_break = utf_allow_break(cc, ncc);
+
+ // If we have already checked this position, skip!
+ if (curwin->w_cursor.col != skip_pos && allow_break) {
foundcol = curwin->w_cursor.col;
end_foundcol = foundcol;
if (curwin->w_cursor.col <= (colnr_T)wantcol)
@@ -5929,6 +5936,7 @@ internal_format (
if (curwin->w_cursor.col == 0)
break;
+ ncc = cc;
col = curwin->w_cursor.col;
dec_cursor();
@@ -5937,17 +5945,56 @@ internal_format (
if (WHITECHAR(cc)) {
continue; // break with space
}
- // Don't break until after the comment leader
+ // Don't break until after the comment leader.
if (curwin->w_cursor.col < leader_len) {
break;
}
curwin->w_cursor.col = col;
+ skip_pos = curwin->w_cursor.col;
- foundcol = curwin->w_cursor.col;
- end_foundcol = foundcol;
- if (curwin->w_cursor.col <= (colnr_T)wantcol)
- break;
+ allow_break = utf_allow_break(cc, ncc);
+
+ // Must handle this to respect line break prohibition.
+ if (allow_break) {
+ foundcol = curwin->w_cursor.col;
+ end_foundcol = foundcol;
+ }
+ if (curwin->w_cursor.col <= (colnr_T)wantcol) {
+ const bool ncc_allow_break = utf_allow_break_before(ncc);
+
+ if (allow_break) {
+ break;
+ }
+ if (!ncc_allow_break && !fo_rigor_tw) {
+ // Enable at most 1 punct hang outside of textwidth.
+ if (curwin->w_cursor.col == startcol) {
+ // We are inserting a non-breakable char, postpone
+ // line break check to next insert.
+ end_foundcol = foundcol = 0;
+ break;
+ }
+
+ // Neither cc nor ncc is NUL if we are here, so
+ // it's safe to inc_cursor.
+ col = curwin->w_cursor.col;
+
+ inc_cursor();
+ cc = ncc;
+ ncc = gchar_cursor();
+ // handle insert
+ ncc = (ncc != NUL) ? ncc : c;
+
+ allow_break = utf_allow_break(cc, ncc);
+
+ if (allow_break) {
+ // Break only when we are not at end of line.
+ end_foundcol = foundcol = ncc == NUL? 0 : curwin->w_cursor.col;
+ break;
+ }
+ curwin->w_cursor.col = col;
+ }
+ }
}
if (curwin->w_cursor.col == 0)
break;
@@ -6049,7 +6096,7 @@ internal_format (
}
}
}
- first_line = FALSE;
+ first_line = false;
}
if (State & VREPLACE_FLAG) {
@@ -6236,12 +6283,10 @@ static void check_auto_format(
* Set default to window width (maximum 79) for "gq" operator.
*/
int comp_textwidth(
- int ff // force formatting (for "gq" command)
+ bool ff // force formatting (for "gq" command)
)
{
- int textwidth;
-
- textwidth = curbuf->b_p_tw;
+ int textwidth = curbuf->b_p_tw;
if (textwidth == 0 && curbuf->b_p_wm) {
// The width is the window width minus 'wrapmargin' minus all the
// things that add to the margin.
@@ -7691,6 +7736,10 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
undisplay_dollar();
}
+ if (cmdchar != 'r' && cmdchar != 'v') {
+ ins_apply_autocmds(EVENT_INSERTLEAVEPRE);
+ }
+
// When an autoindent was removed, curswant stays after the
// indent
if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a2490be355..cccf1e50ff 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -2994,7 +2994,6 @@ char_u *get_user_var_name(expand_T *xp, int idx)
static size_t tdone;
static size_t vidx;
static hashitem_T *hi;
- hashtab_T *ht;
if (idx == 0) {
gdone = bdone = wdone = vidx = 0;
@@ -3015,7 +3014,10 @@ char_u *get_user_var_name(expand_T *xp, int idx)
}
// b: variables
- ht = &curbuf->b_vars->dv_hashtab;
+ // In cmdwin, the alternative buffer should be used.
+ hashtab_T *ht = (cmdwin_type != 0 && get_cmdline_type() == NUL)
+ ? &prevwin->w_buffer->b_vars->dv_hashtab
+ : &curbuf->b_vars->dv_hashtab;
if (bdone < ht->ht_used) {
if (bdone++ == 0)
hi = ht->ht_array;
@@ -3027,7 +3029,10 @@ char_u *get_user_var_name(expand_T *xp, int idx)
}
// w: variables
- ht = &curwin->w_vars->dv_hashtab;
+ // In cmdwin, the alternative window should be used.
+ ht = (cmdwin_type != 0 && get_cmdline_type() == NUL)
+ ? &prevwin->w_vars->dv_hashtab
+ : &curwin->w_vars->dv_hashtab;
if (wdone < ht->ht_used) {
if (wdone++ == 0)
hi = ht->ht_array;
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 372c950825..6c316bb1fe 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -275,6 +275,7 @@ return {
rpcrequest={args=varargs(2)},
rpcstart={args={1, 2}},
rpcstop={args=1},
+ rubyeval={args=1},
screenattr={args=2},
screenchar={args=2},
screencol={},
@@ -371,7 +372,7 @@ return {
tolower={args=1},
toupper={args=1},
tr={args=3},
- trim={args={1,2}},
+ trim={args={1,3}},
trunc={args=1, func="float_op_wrapper", data="&trunc"},
type={args=1},
undofile={args=1},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 83ad948a93..d2e9c68965 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -6381,6 +6381,12 @@ static void f_perleval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
script_host_eval("perl", argvars, rettv);
}
+// "rubyeval()" function
+static void f_rubyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ script_host_eval("ruby", argvars, rettv);
+}
+
/*
* "range()" function
*/
@@ -6936,7 +6942,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
ptrdiff_t len = (ptrdiff_t)strlen(p);
- if (len > 0 && after_pathsep(p, p + len)) {
+ if (len > 1 && after_pathsep(p, p + len)) {
has_trailing_pathsep = true;
p[len - 1] = NUL; // The trailing slash breaks readlink().
}
@@ -7668,7 +7674,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
}
retval = do_searchpair(
- (char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, skip,
+ spat, mpat, epat, dir, skip,
flags, match_pos, lnum_stop, time_limit);
theend:
@@ -7712,9 +7718,9 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
long
do_searchpair(
- char_u *spat, // start pattern
- char_u *mpat, // middle pattern
- char_u *epat, // end pattern
+ const char *spat, // start pattern
+ const char *mpat, // middle pattern
+ const char *epat, // end pattern
int dir, // BACKWARD or FORWARD
const typval_T *skip, // skip expression
int flags, // SP_SETPCMARK and other SP_ values
@@ -7722,6 +7728,7 @@ do_searchpair(
linenr_T lnum_stop, // stop at this line if not zero
long time_limit // stop after this many msec
)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 3)
{
char_u *save_cpo;
char_u *pat, *pat2 = NULL, *pat3 = NULL;
@@ -7736,8 +7743,6 @@ do_searchpair(
bool use_skip = false;
int options = SEARCH_KEEP;
proftime_T tm;
- size_t pat2_len;
- size_t pat3_len;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
save_cpo = p_cpo;
@@ -7748,9 +7753,9 @@ do_searchpair(
// Make two search patterns: start/end (pat2, for in nested pairs) and
// start/middle/end (pat3, for the top pair).
- pat2_len = STRLEN(spat) + STRLEN(epat) + 17;
+ const size_t pat2_len = strlen(spat) + strlen(epat) + 17;
pat2 = xmalloc(pat2_len);
- pat3_len = STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25;
+ const size_t pat3_len = strlen(spat) + strlen(mpat) + strlen(epat) + 25;
pat3 = xmalloc(pat3_len);
snprintf((char *)pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
if (*mpat == NUL) {
@@ -8142,15 +8147,17 @@ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// Create quickfix/location list from VimL values
///
/// Used by `setqflist()` and `setloclist()` functions. Accepts invalid
-/// list_arg, action_arg and what_arg arguments in which case errors out,
-/// including VAR_UNKNOWN parameters.
+/// args argument in which case errors out, including VAR_UNKNOWN parameters.
///
/// @param[in,out] wp Window to create location list for. May be NULL in
/// which case quickfix list will be created.
-/// @param[in] list_arg Quickfix list contents.
-/// @param[in] action_arg Action to perform: append to an existing list,
-/// replace its content or create a new one.
-/// @param[in] title_arg New list title. Defaults to caller function name.
+/// @param[in] args [list, action, what]
+/// @param[in] args[0] Quickfix list contents.
+/// @param[in] args[1] Optional. Action to perform:
+/// append to an existing list, replace its content,
+/// or create a new one.
+/// @param[in] args[2] Optional. Quickfix list properties or title.
+/// Defaults to caller function name.
/// @param[out] rettv Return value: 0 in case of success, -1 otherwise.
static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
FUNC_ATTR_NONNULL_ARG(2, 3)
@@ -8160,7 +8167,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
int action = ' ';
static int recursive = 0;
rettv->vval.v_number = -1;
- dict_T *d = NULL;
+ dict_T *what = NULL;
typval_T *list_arg = &args[0];
if (list_arg->v_type != VAR_LIST) {
@@ -8188,18 +8195,18 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
return;
}
- typval_T *title_arg = &args[2];
- if (title_arg->v_type == VAR_UNKNOWN) {
+ typval_T *const what_arg = &args[2];
+ if (what_arg->v_type == VAR_UNKNOWN) {
// Option argument was not given.
goto skip_args;
- } else if (title_arg->v_type == VAR_STRING) {
- title = tv_get_string_chk(title_arg);
+ } else if (what_arg->v_type == VAR_STRING) {
+ title = tv_get_string_chk(what_arg);
if (!title) {
// Type error. Error already printed by tv_get_string_chk().
return;
}
- } else if (title_arg->v_type == VAR_DICT) {
- d = title_arg->vval.v_dict;
+ } else if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL) {
+ what = what_arg->vval.v_dict;
} else {
EMSG(_(e_dictreq));
return;
@@ -8212,7 +8219,7 @@ skip_args:
recursive++;
list_T *const l = list_arg->vval.v_list;
- if (set_errorlist(wp, l, action, (char_u *)title, d) == OK) {
+ if (set_errorlist(wp, l, action, (char_u *)title, what) == OK) {
rettv->vval.v_number = 0;
}
recursive--;
@@ -10824,52 +10831,72 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char_u *prev;
const char_u *p;
int c1;
+ int dir = 0;
rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
if (head == NULL) {
- rettv->vval.v_string = NULL;
return;
}
if (argvars[1].v_type == VAR_STRING) {
mask = (const char_u *)tv_get_string_buf_chk(&argvars[1], buf2);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ bool error = false;
+ // leading or trailing characters to trim
+ dir = (int)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ if (dir < 0 || dir > 2) {
+ emsgf(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ }
}
- while (*head != NUL) {
- c1 = PTR2CHAR(head);
- if (mask == NULL) {
- if (c1 > ' ' && c1 != 0xa0) {
- break;
- }
- } else {
- for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
- if (c1 == PTR2CHAR(p)) {
+ if (dir == 0 || dir == 1) {
+ // Trim leading characters
+ while (*head != NUL) {
+ c1 = PTR2CHAR(head);
+ if (mask == NULL) {
+ if (c1 > ' ' && c1 != 0xa0) {
+ break;
+ }
+ } else {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
+ if (c1 == PTR2CHAR(p)) {
+ break;
+ }
+ }
+ if (*p == NUL) {
break;
}
}
- if (*p == NUL) {
- break;
- }
+ MB_PTR_ADV(head);
}
- MB_PTR_ADV(head);
}
- for (tail = head + STRLEN(head); tail > head; tail = prev) {
- prev = tail;
- MB_PTR_BACK(head, prev);
- c1 = PTR2CHAR(prev);
- if (mask == NULL) {
- if (c1 > ' ' && c1 != 0xa0) {
- break;
- }
- } else {
- for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
- if (c1 == PTR2CHAR(p)) {
+ tail = head + STRLEN(head);
+ if (dir == 0 || dir == 2) {
+ // Trim trailing characters
+ for (; tail > head; tail = prev) {
+ prev = tail;
+ MB_PTR_BACK(head, prev);
+ c1 = PTR2CHAR(prev);
+ if (mask == NULL) {
+ if (c1 > ' ' && c1 != 0xa0) {
+ break;
+ }
+ } else {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
+ if (c1 == PTR2CHAR(p)) {
+ break;
+ }
+ }
+ if (*p == NUL) {
break;
}
- }
- if (*p == NUL) {
- break;
}
}
}
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index e0361048bc..dc94bc698d 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -1052,7 +1052,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
// A Lambda always has the command "return {expr}". It is much faster
// to evaluate {expr} directly.
ex_nesting_level++;
- eval1(&p, rettv, true);
+ (void)eval1(&p, rettv, true);
ex_nesting_level--;
} else {
// call do_cmdline() to execute the lines
@@ -2920,8 +2920,10 @@ void ex_call(exarg_T *eap)
if (!failed || eap->cstack->cs_trylevel > 0) {
// Check for trailing illegal characters and a following command.
if (!ends_excmd(*arg)) {
- emsg_severe = true;
- EMSG(_(e_trailing));
+ if (!failed) {
+ emsg_severe = true;
+ EMSG(_(e_trailing));
+ }
} else {
eap->nextcmd = check_nextcmd(arg);
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index bb4e92efc0..3669cbbd2d 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -135,7 +135,7 @@ void do_ascii(const exarg_T *const eap)
char buf1[20];
if (vim_isprintc_strict(c) && (c < ' ' || c > '~')) {
char_u buf3[7];
- transchar_nonprint(buf3, c);
+ transchar_nonprint(curbuf, buf3, c);
vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3);
} else {
buf1[0] = NUL;
@@ -2240,11 +2240,9 @@ int do_ecmd(
goto theend;
}
- /*
- * if the file was changed we may not be allowed to abandon it
- * - if we are going to re-edit the same file
- * - or if we are the only window on this file and if ECMD_HIDE is FALSE
- */
+ // If the file was changed we may not be allowed to abandon it:
+ // - if we are going to re-edit the same file
+ // - or if we are the only window on this file and if ECMD_HIDE is FALSE
if ( ((!other_file && !(flags & ECMD_OLDBUF))
|| (curbuf->b_nwindows == 1
&& !(flags & (ECMD_HIDE | ECMD_ADDBUF))))
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 3e169f7a4e..503fd8e0d0 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2058,6 +2058,10 @@ void ex_listdo(exarg_T *eap)
// Don't do syntax HL autocommands. Skipping the syntax file is a
// great speed improvement.
save_ei = au_event_disable(",Syntax");
+
+ FOR_ALL_BUFFERS(buf) {
+ buf->b_flags &= ~BF_SYN_SET;
+ }
}
if (eap->cmdidx == CMD_windo
@@ -2252,9 +2256,32 @@ void ex_listdo(exarg_T *eap)
}
if (save_ei != NULL) {
+ buf_T *bnext;
+ aco_save_T aco;
+
au_event_restore(save_ei);
- apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
- curbuf->b_fname, true, curbuf);
+
+ for (buf_T *buf = firstbuf; buf != NULL; buf = bnext) {
+ bnext = buf->b_next;
+ if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET)) {
+ buf->b_flags &= ~BF_SYN_SET;
+
+ // buffer was opened while Syntax autocommands were disabled,
+ // need to trigger them now.
+ if (buf == curbuf) {
+ apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
+ curbuf->b_fname, true, curbuf);
+ } else {
+ aucmd_prepbuf(&aco, buf);
+ apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
+ buf->b_fname, true, buf);
+ aucmd_restbuf(&aco);
+ }
+
+ // start over, in case autocommands messed things up.
+ bnext = firstbuf;
+ }
+ }
}
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index ccaa0b0e52..211791c19d 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -2400,6 +2400,7 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
}
break;
case ADDR_TABS_RELATIVE:
+ case ADDR_OTHER:
*errormsg = (char_u *)_(e_invrange);
return FAIL;
case ADDR_ARGUMENTS:
@@ -5057,16 +5058,18 @@ fail:
static struct {
int expand;
char *name;
+ char *shortname;
} addr_type_complete[] =
{
- { ADDR_ARGUMENTS, "arguments" },
- { ADDR_LINES, "lines" },
- { ADDR_LOADED_BUFFERS, "loaded_buffers" },
- { ADDR_TABS, "tabs" },
- { ADDR_BUFFERS, "buffers" },
- { ADDR_WINDOWS, "windows" },
- { ADDR_QUICKFIX, "quickfix" },
- { -1, NULL }
+ { ADDR_ARGUMENTS, "arguments", "arg" },
+ { ADDR_LINES, "lines", "line" },
+ { ADDR_LOADED_BUFFERS, "loaded_buffers", "load" },
+ { ADDR_TABS, "tabs", "tab" },
+ { ADDR_BUFFERS, "buffers", "buf" },
+ { ADDR_WINDOWS, "windows", "win" },
+ { ADDR_QUICKFIX, "quickfix", "qf" },
+ { ADDR_OTHER, "other", "?" },
+ { -1, NULL, NULL }
};
/*
@@ -5151,7 +5154,7 @@ static void uc_list(char_u *name, size_t name_len)
// Put out the title first time
if (!found) {
MSG_PUTS_TITLE(_("\n Name Args Address "
- "Complete Definition"));
+ "Complete Definition"));
}
found = true;
msg_putchar('\n');
@@ -5237,13 +5240,13 @@ static void uc_list(char_u *name, size_t name_len)
do {
IObuff[len++] = ' ';
- } while (len < 9 - over);
+ } while (len < 8 - over);
// Address Type
for (j = 0; addr_type_complete[j].expand != -1; j++) {
if (addr_type_complete[j].expand != ADDR_LINES
&& addr_type_complete[j].expand == cmd->uc_addr_type) {
- STRCPY(IObuff + len, addr_type_complete[j].name);
+ STRCPY(IObuff + len, addr_type_complete[j].shortname);
len += (int)STRLEN(IObuff + len);
break;
}
@@ -5262,13 +5265,13 @@ static void uc_list(char_u *name, size_t name_len)
do {
IObuff[len++] = ' ';
- } while (len < 24 - over);
+ } while (len < 25 - over);
IObuff[len] = '\0';
msg_outtrans(IObuff);
msg_outtrans_special(cmd->uc_rep, false,
- name_len == 0 ? Columns - 46 : 0);
+ name_len == 0 ? Columns - 47 : 0);
if (p_verbose > 0) {
last_set_msg(cmd->uc_script_ctx);
}
@@ -5397,7 +5400,7 @@ invalid_count:
if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg) == FAIL) {
return FAIL;
}
- if (addr_type_arg != ADDR_LINES) {
+ if (*addr_type_arg != ADDR_LINES) {
*argt |= (ZEROR | NOTADR);
}
} else {
@@ -6926,8 +6929,9 @@ void ex_splitview(exarg_T *eap)
{
win_T *old_curwin = curwin;
char_u *fname = NULL;
-
-
+ const bool use_tab = eap->cmdidx == CMD_tabedit
+ || eap->cmdidx == CMD_tabfind
+ || eap->cmdidx == CMD_tabnew;
/* A ":split" in the quickfix window works like ":new". Don't want two
* quickfix windows. But it's OK when doing ":tab split". */
@@ -6949,9 +6953,7 @@ void ex_splitview(exarg_T *eap)
/*
* Either open new tab page or split the window.
*/
- if (eap->cmdidx == CMD_tabedit
- || eap->cmdidx == CMD_tabfind
- || eap->cmdidx == CMD_tabnew) {
+ if (use_tab) {
if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab : eap->addr_count == 0
? 0 : (int)eap->line2 + 1, eap->arg) != FAIL) {
do_exedit(eap, old_curwin);
@@ -7136,14 +7138,14 @@ static void ex_resize(exarg_T *eap)
n = atol((char *)eap->arg);
if (cmdmod.split & WSP_VERT) {
if (*eap->arg == '-' || *eap->arg == '+') {
- n += curwin->w_width;
+ n += wp->w_width;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very wide
n = Columns;
}
win_setwidth_win(n, wp);
} else {
if (*eap->arg == '-' || *eap->arg == '+') {
- n += curwin->w_height;
+ n += wp->w_height;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very high
n = Rows-1;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index f9ca7bfa42..940f446a7b 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -5193,7 +5193,7 @@ ExpandFromContext (
* obtain strings, one by one. The strings are matched against a regexp
* program. Matching strings are copied into an array, which is returned.
*/
-void ExpandGeneric(
+static void ExpandGeneric(
expand_T *xp,
regmatch_T *regmatch,
int *num_file,
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 1b4a89fb6c..ad856b588a 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -3593,7 +3593,7 @@ restore_backup:
* the backup file our 'original' file.
*/
if (*p_pm && dobackup) {
- char *org = modname((char *)fname, (char *)p_pm, FALSE);
+ char *const org = modname((char *)fname, (char *)p_pm, false);
if (backup != NULL) {
/*
diff --git a/src/nvim/generators/gen_ex_cmds.lua b/src/nvim/generators/gen_ex_cmds.lua
index 075d8ba9cc..849c82f50e 100644
--- a/src/nvim/generators/gen_ex_cmds.lua
+++ b/src/nvim/generators/gen_ex_cmds.lua
@@ -24,8 +24,6 @@ local defsfile = io.open(defsfname, 'w')
local defs = require('ex_cmds')
-local first = true
-
local byte_a = string.byte('a')
local byte_z = string.byte('z')
local a_to_z = byte_z - byte_a + 1
@@ -41,8 +39,7 @@ static const uint16_t cmdidxs1[%u] = {
-- fit in a byte.
local cmdidxs2_out = string.format([[
static const char_u cmdidxs2[%u][%u] = {
-/* a b c d e f g h i j k l m n o p q r s t u v w x y z */
-
+ /* a b c d e f g h i j k l m n o p q r s t u v w x y z */
]], a_to_z, a_to_z)
enumfile:write([[
@@ -50,10 +47,8 @@ typedef enum CMD_index {
]])
defsfile:write(string.format([[
static const int command_count = %u;
-]], #defs))
-defsfile:write(string.format([[
static CommandDefinition cmdnames[%u] = {
-]], #defs))
+]], #defs, #defs))
local cmds, cmdidxs1, cmdidxs2 = {}, {}, {}
for _, cmd in ipairs(defs) do
local enumname = cmd.enum or ('CMD_' .. cmd.command)
@@ -61,11 +56,6 @@ for _, cmd in ipairs(defs) do
if byte_a <= byte_cmd and byte_cmd <= byte_z then
table.insert(cmds, cmd.command)
end
- if first then
- first = false
- else
- defsfile:write(',\n')
- end
enumfile:write(' ' .. enumname .. ',\n')
defsfile:write(string.format([[
[%s] = {
@@ -73,7 +63,8 @@ for _, cmd in ipairs(defs) do
.cmd_func = (ex_func_T)&%s,
.cmd_argt = %uL,
.cmd_addr_type = %i
- }]], enumname, cmd.command, cmd.func, cmd.flags, cmd.addr_type))
+ },
+]], enumname, cmd.command, cmd.func, cmd.flags, cmd.addr_type))
end
for i = #cmds, 1, -1 do
local cmd = cmds[i]
@@ -104,15 +95,14 @@ for i = byte_a, byte_z do
end
cmdidxs2_out = cmdidxs2_out .. ' },\n'
end
-defsfile:write([[
-
-};
-]])
enumfile:write([[
CMD_SIZE,
CMD_USER = -1,
CMD_USER_BUF = -2
} cmdidx_T;
]])
-defsfile:write(cmdidxs1_out .. '};\n')
-defsfile:write(cmdidxs2_out .. '};\n')
+defsfile:write(string.format([[
+};
+%s};
+%s};
+]], cmdidxs1_out, cmdidxs2_out))
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index a8cf496cb9..d80a6219eb 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -141,9 +141,6 @@ local dump_option = function(i, o)
elseif #o.scope == 1 and o.scope[1] == 'window' then
w(' .var=VAR_WIN')
end
- if o.enable_if then
- w('#endif')
- end
if #o.scope == 1 and o.scope[1] == 'global' then
w(' .indir=PV_NONE')
else
@@ -163,6 +160,12 @@ local dump_option = function(i, o)
defines['PV_' .. varname:sub(3):upper()] = pv_name
w(' .indir=' .. pv_name)
end
+ if o.enable_if then
+ w('#else')
+ w(' .var=NULL')
+ w(' .indir=PV_NONE')
+ w('#endif')
+ end
if o.defaults then
if o.defaults.condition then
w(get_cond(o.defaults.condition))
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index cbd9582f8b..456979be00 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -4204,7 +4204,6 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
{
char_u *str = strstart;
int c;
- int modifiers;
// :map xx <Nop>
if (*str == NUL && what == 1) {
@@ -4231,7 +4230,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
* when they are read back.
*/
if (c == K_SPECIAL && what != 2) {
- modifiers = 0x0;
+ int modifiers = 0;
if (str[1] == KS_MODIFIER) {
modifiers = str[2];
str += 3;
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 33d9772bec..5258352e72 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -43,6 +43,7 @@ static struct luaL_Reg parser_meta[] = {
{ "edit", parser_edit },
{ "tree", parser_tree },
{ "set_included_ranges", parser_set_ranges },
+ { "included_ranges", parser_get_ranges },
{ NULL, NULL }
};
@@ -314,6 +315,26 @@ static const char *input_cb(void *payload, uint32_t byte_index,
#undef BUFSIZE
}
+static void push_ranges(lua_State *L,
+ const TSRange *ranges,
+ const unsigned int length)
+{
+ lua_createtable(L, length, 0);
+ for (size_t i = 0; i < length; i++) {
+ lua_createtable(L, 4, 0);
+ lua_pushinteger(L, ranges[i].start_point.row);
+ lua_rawseti(L, -2, 1);
+ lua_pushinteger(L, ranges[i].start_point.column);
+ lua_rawseti(L, -2, 2);
+ lua_pushinteger(L, ranges[i].end_point.row);
+ lua_rawseti(L, -2, 3);
+ lua_pushinteger(L, ranges[i].end_point.column);
+ lua_rawseti(L, -2, 4);
+
+ lua_rawseti(L, -2, i+1);
+ }
+}
+
static int parser_parse(lua_State *L)
{
TSLua_parser *p = parser_check(L);
@@ -363,20 +384,8 @@ static int parser_parse(lua_State *L)
tslua_push_tree(L, p->tree);
- lua_createtable(L, n_ranges, 0);
- for (size_t i = 0; i < n_ranges; i++) {
- lua_createtable(L, 4, 0);
- lua_pushinteger(L, changed[i].start_point.row);
- lua_rawseti(L, -2, 1);
- lua_pushinteger(L, changed[i].start_point.column);
- lua_rawseti(L, -2, 2);
- lua_pushinteger(L, changed[i].end_point.row);
- lua_rawseti(L, -2, 3);
- lua_pushinteger(L, changed[i].end_point.column);
- lua_rawseti(L, -2, 4);
+ push_ranges(L, changed, n_ranges);
- lua_rawseti(L, -2, i+1);
- }
xfree(changed);
return 2;
}
@@ -474,6 +483,21 @@ static int parser_set_ranges(lua_State *L)
return 0;
}
+static int parser_get_ranges(lua_State *L)
+{
+ TSLua_parser *p = parser_check(L);
+ if (!p || !p->parser) {
+ return 0;
+ }
+
+ unsigned int len;
+ const TSRange *ranges = ts_parser_included_ranges(p->parser, &len);
+
+ push_ranges(L, ranges, len);
+
+ return 1;
+}
+
// Tree methods
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index e67be60aa6..ec4f4cbc21 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -512,7 +512,7 @@ int utf_ptr2cells(const char_u *p)
{
int c;
- /* Need to convert to a wide character. */
+ // Need to convert to a character number.
if (*p >= 0x80) {
c = utf_ptr2char(p);
/* An illegal byte is displayed as <xx>. */
@@ -582,7 +582,7 @@ size_t mb_string2cells_len(const char_u *str, size_t size)
return clen;
}
-/// Convert a UTF-8 byte sequence to a wide character
+/// Convert a UTF-8 byte sequence to a character number.
///
/// If the sequence is illegal or truncated by a NUL then the first byte is
/// returned.
@@ -1624,6 +1624,146 @@ int utf_head_off(const char_u *base, const char_u *p)
return (int)(p - q);
}
+// Whether space is NOT allowed before/after 'c'.
+bool utf_eat_space(int cc)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return (cc >= 0x2000 && cc <= 0x206F) // General punctuations
+ || (cc >= 0x2e00 && cc <= 0x2e7f) // Supplemental punctuations
+ || (cc >= 0x3000 && cc <= 0x303f) // CJK symbols and punctuations
+ || (cc >= 0xff01 && cc <= 0xff0f) // Full width ASCII punctuations
+ || (cc >= 0xff1a && cc <= 0xff20) // ..
+ || (cc >= 0xff3b && cc <= 0xff40) // ..
+ || (cc >= 0xff5b && cc <= 0xff65); // ..
+}
+
+// Whether line break is allowed before "cc".
+bool utf_allow_break_before(int cc)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static const int BOL_prohibition_punct[] = {
+ '!',
+ '%',
+ ')',
+ ',',
+ ':',
+ ';',
+ '>',
+ '?',
+ ']',
+ '}',
+ 0x2019, // ’ right single quotation mark
+ 0x201d, // ” right double quotation mark
+ 0x2020, // † dagger
+ 0x2021, // ‡ double dagger
+ 0x2026, // … horizontal ellipsis
+ 0x2030, // ‰ per mille sign
+ 0x2031, // ‱ per then thousand sign
+ 0x203c, // ‼ double exclamation mark
+ 0x2047, // ⁇ double question mark
+ 0x2048, // ⁈ question exclamation mark
+ 0x2049, // ⁉ exclamation question mark
+ 0x2103, // ℃ degree celsius
+ 0x2109, // ℉ degree fahrenheit
+ 0x3001, // 、 ideographic comma
+ 0x3002, // 。 ideographic full stop
+ 0x3009, // 〉 right angle bracket
+ 0x300b, // 》 right double angle bracket
+ 0x300d, // 」 right corner bracket
+ 0x300f, // 』 right white corner bracket
+ 0x3011, // 】 right black lenticular bracket
+ 0x3015, // 〕 right tortoise shell bracket
+ 0x3017, // 〗 right white lenticular bracket
+ 0x3019, // 〙 right white tortoise shell bracket
+ 0x301b, // 〛 right white square bracket
+ 0xff01, // ! fullwidth exclamation mark
+ 0xff09, // ) fullwidth right parenthesis
+ 0xff0c, // , fullwidth comma
+ 0xff0e, // . fullwidth full stop
+ 0xff1a, // : fullwidth colon
+ 0xff1b, // ; fullwidth semicolon
+ 0xff1f, // ? fullwidth question mark
+ 0xff3d, // ] fullwidth right square bracket
+ 0xff5d, // } fullwidth right curly bracket
+ };
+
+ int first = 0;
+ int last = ARRAY_SIZE(BOL_prohibition_punct) - 1;
+
+ while (first < last) {
+ const int mid = (first + last) / 2;
+
+ if (cc == BOL_prohibition_punct[mid]) {
+ return false;
+ } else if (cc > BOL_prohibition_punct[mid]) {
+ first = mid + 1;
+ } else {
+ last = mid - 1;
+ }
+ }
+
+ return cc != BOL_prohibition_punct[first];
+}
+
+// Whether line break is allowed after "cc".
+bool utf_allow_break_after(int cc)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static const int EOL_prohibition_punct[] = {
+ '(',
+ '<',
+ '[',
+ '`',
+ '{',
+ // 0x2014, // — em dash
+ 0x2018, // ‘ left single quotation mark
+ 0x201c, // “ left double quotation mark
+ // 0x2053, // ~ swung dash
+ 0x3008, // 〈 left angle bracket
+ 0x300a, // 《 left double angle bracket
+ 0x300c, // 「 left corner bracket
+ 0x300e, // 『 left white corner bracket
+ 0x3010, // 【 left black lenticular bracket
+ 0x3014, // 〔 left tortoise shell bracket
+ 0x3016, // 〖 left white lenticular bracket
+ 0x3018, // 〘 left white tortoise shell bracket
+ 0x301a, // 〚 left white square bracket
+ 0xff08, // ( fullwidth left parenthesis
+ 0xff3b, // [ fullwidth left square bracket
+ 0xff5b, // { fullwidth left curly bracket
+ };
+
+ int first = 0;
+ int last = ARRAY_SIZE(EOL_prohibition_punct) - 1;
+
+ while (first < last) {
+ const int mid = (first + last)/2;
+
+ if (cc == EOL_prohibition_punct[mid]) {
+ return false;
+ } else if (cc > EOL_prohibition_punct[mid]) {
+ first = mid + 1;
+ } else {
+ last = mid - 1;
+ }
+ }
+
+ return cc != EOL_prohibition_punct[first];
+}
+
+// Whether line break is allowed between "cc" and "ncc".
+bool utf_allow_break(int cc, int ncc)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // don't break between two-letter punctuations
+ if (cc == ncc
+ && (cc == 0x2014 // em dash
+ || cc == 0x2026)) { // horizontal ellipsis
+ return false;
+ }
+ return utf_allow_break_after(cc) && utf_allow_break_before(ncc);
+}
+
/// Copy a character, advancing the pointers
///
/// @param[in,out] fp Source of the character to copy.
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 2a75f13cc2..57ed0d6588 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -1360,7 +1360,7 @@ recover_names (
* Try finding a swap file by simply adding ".swp" to the file name.
*/
if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) {
- char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", TRUE);
+ char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", true);
if (swapname != NULL) {
if (os_path_exists(swapname)) {
files = xmalloc(sizeof(char_u *));
@@ -1638,10 +1638,11 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
// May also add the file name with a dot prepended, for swap file in same
// dir as original file.
if (prepend_dot) {
- names[num_names] = (char_u *)modname((char *)path, ".sw?", TRUE);
- if (names[num_names] == NULL)
+ names[num_names] = (char_u *)modname((char *)path, ".sw?", true);
+ if (names[num_names] == NULL) {
return num_names;
- ++num_names;
+ }
+ num_names++;
}
// Form the normal swap file name pattern by appending ".sw?".
@@ -2422,17 +2423,17 @@ int ml_replace(linenr_T lnum, char_u *line, bool copy)
return ml_replace_buf(curbuf, lnum, line, copy);
}
-/*
- * Replace line lnum, with buffering, in current buffer.
- *
- * If "copy" is TRUE, make a copy of the line, otherwise the line has been
- * copied to allocated memory already.
- *
- * Check: The caller of this function should probably also call
- * changed_lines(), unless update_screen(NOT_VALID) is used.
- *
- * return FAIL for failure, OK otherwise
- */
+// Replace line "lnum", with buffering, in current buffer.
+//
+// If "copy" is true, make a copy of the line, otherwise the line has been
+// copied to allocated memory already.
+// If "copy" is false the "line" may be freed to add text properties!
+// Do not use it after calling ml_replace().
+//
+// Check: The caller of this function should probably also call
+// changed_lines(), unless update_screen(NOT_VALID) is used.
+//
+// return FAIL for failure, OK otherwise
int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy)
{
if (line == NULL) /* just checking... */
@@ -3193,6 +3194,12 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
char_u *fname_res = fname;
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
+
+ // Expand symlink in the file name, so that we put the swap file with the
+ // actual file instead of with the symlink.
+ if (resolve_symlink(fname, fname_buf) == OK) {
+ fname_res = fname_buf;
+ }
#endif
int len = (int)STRLEN(dir_name);
@@ -3201,20 +3208,14 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
&& len > 1
&& s[-1] == s[-2]) { // Ends with '//', Use Full path
r = NULL;
- if ((s = (char_u *)make_percent_swname((char *)dir_name, (char *)fname)) != NULL) {
- r = (char_u *)modname((char *)s, ".swp", FALSE);
+ s = (char_u *)make_percent_swname((char *)dir_name, (char *)fname_res);
+ if (s != NULL) {
+ r = (char_u *)modname((char *)s, ".swp", false);
xfree(s);
}
return r;
}
-#ifdef HAVE_READLINK
- /* Expand symlink in the file name, so that we put the swap file with the
- * actual file instead of with the symlink. */
- if (resolve_symlink(fname, fname_buf) == OK)
- fname_res = fname_buf;
-#endif
-
// Prepend a '.' to the swap file name for the current directory.
r = (char_u *)modname((char *)fname_res, ".swp",
dir_name[0] == '.' && dir_name[1] == NUL);
diff --git a/src/nvim/message.c b/src/nvim/message.c
index e4f47917ec..6cd5616acf 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1621,7 +1621,7 @@ const char *str2special(const char **const sp, const bool replace_spaces,
// Check for an illegal byte.
if (MB_BYTE2LEN((uint8_t)(*str)) > len) {
- transchar_nonprint((char_u *)buf, c);
+ transchar_nonprint(curbuf, (char_u *)buf, c);
*sp = str + 1;
return buf;
}
@@ -1886,6 +1886,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
// wait-return prompt later. Needed when scrolling, resetting
// need_wait_return after some prompt, and then outputting something
// without scrolling
+ // Not needed when only using CR to move the cursor.
bool overflow = false;
if (ui_has(kUIMessages)) {
int count = msg_ext_visible + (msg_ext_overwrite ? 0 : 1);
@@ -1897,7 +1898,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
overflow = msg_scrolled != 0;
}
- if (overflow && !msg_scrolled_ign) {
+ if (overflow && !msg_scrolled_ign && strcmp(str, "\r") != 0) {
need_wait_return = true;
}
msg_didany = true; // remember that something was outputted
@@ -1999,7 +2000,7 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
|| (*s == TAB && msg_col <= 7)
|| (utf_ptr2cells(s) > 1
&& msg_col <= 2))
- : (msg_col + t_col >= Columns - 1
+ : ((*s != '\r' && msg_col + t_col >= Columns - 1)
|| (*s == TAB
&& msg_col + t_col >= ((Columns - 1) & ~7))
|| (utf_ptr2cells(s) > 1
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 6dafbafb3e..1cd9ff2c4d 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -983,7 +983,7 @@ void preserve_exit(void)
FOR_ALL_BUFFERS(buf) {
if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
- mch_errmsg((uint8_t *)"Vim: preserving files...\n");
+ mch_errmsg("Vim: preserving files...\r\n");
ui_flush();
ml_sync_all(false, false, true); // preserve all swap files
break;
@@ -992,7 +992,7 @@ void preserve_exit(void)
ml_close_all(false); // close all memfiles, without deleting
- mch_errmsg("Vim: Finished.\n");
+ mch_errmsg("Vim: Finished.\r\n");
getout(1);
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index a51aa0dc07..1cc400166c 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -6841,7 +6841,7 @@ static void nv_g_cmd(cmdarg_T *cap)
} else {
if (cap->count1 > 1) {
// if it fails, let the cursor still move to the last char
- cursor_down(cap->count1 - 1, false);
+ (void)cursor_down(cap->count1 - 1, false);
}
i = curwin->w_leftcol + curwin->w_width_inner - col_off - 1;
coladvance((colnr_T)i);
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 8329daf5f1..939cde0ba1 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -3833,7 +3833,8 @@ int do_join(size_t count,
&& (!has_format_option(FO_MBYTE_JOIN)
|| (utf_ptr2char(curr) < 0x100 && endcurr1 < 0x100))
&& (!has_format_option(FO_MBYTE_JOIN2)
- || utf_ptr2char(curr) < 0x100 || endcurr1 < 0x100)
+ || (utf_ptr2char(curr) < 0x100 && !utf_eat_space(endcurr1))
+ || (endcurr1 < 0x100 && !utf_eat_space(utf_ptr2char(curr))))
) {
/* don't add a space if the line is ending in a space */
if (endcurr1 == ' ')
@@ -4158,49 +4159,41 @@ format_lines(
int avoid_fex /* don't use 'formatexpr' */
)
{
- int max_len;
- int is_not_par; /* current line not part of parag. */
- int next_is_not_par; /* next line not part of paragraph */
- int is_end_par; /* at end of paragraph */
- int prev_is_end_par = FALSE; /* prev. line not part of parag. */
- int next_is_start_par = FALSE;
- int leader_len = 0; /* leader len of current line */
- int next_leader_len; /* leader len of next line */
- char_u *leader_flags = NULL; /* flags for leader of current line */
- char_u *next_leader_flags; /* flags for leader of next line */
- int do_comments; /* format comments */
- int do_comments_list = 0; /* format comments with 'n' or '2' */
- int advance = TRUE;
- int second_indent = -1; /* indent for second line (comment
- * aware) */
- int do_second_indent;
- int do_number_indent;
- int do_trail_white;
- int first_par_line = TRUE;
+ bool is_not_par; // current line not part of parag.
+ bool next_is_not_par; // next line not part of paragraph
+ bool is_end_par; // at end of paragraph
+ bool prev_is_end_par = false; // prev. line not part of parag.
+ bool next_is_start_par = false;
+ int leader_len = 0; // leader len of current line
+ int next_leader_len; // leader len of next line
+ char_u *leader_flags = NULL; // flags for leader of current line
+ char_u *next_leader_flags; // flags for leader of next line
+ bool advance = true;
+ int second_indent = -1; // indent for second line (comment aware)
+ bool first_par_line = true;
int smd_save;
long count;
- int need_set_indent = TRUE; /* set indent of next paragraph */
- int force_format = FALSE;
- int old_State = State;
-
- /* length of a line to force formatting: 3 * 'tw' */
- max_len = comp_textwidth(TRUE) * 3;
-
- /* check for 'q', '2' and '1' in 'formatoptions' */
- do_comments = has_format_option(FO_Q_COMS);
- do_second_indent = has_format_option(FO_Q_SECOND);
- do_number_indent = has_format_option(FO_Q_NUMBER);
- do_trail_white = has_format_option(FO_WHITE_PAR);
-
- /*
- * Get info about the previous and current line.
- */
- if (curwin->w_cursor.lnum > 1)
- is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1
- , &leader_len, &leader_flags, do_comments
- );
- else
- is_not_par = TRUE;
+ bool need_set_indent = true; // set indent of next paragraph
+ bool force_format = false;
+ const int old_State = State;
+
+ // length of a line to force formatting: 3 * 'tw'
+ const int max_len = comp_textwidth(true) * 3;
+
+ // check for 'q', '2' and '1' in 'formatoptions'
+ const bool do_comments = has_format_option(FO_Q_COMS); // format comments
+ int do_comments_list = 0; // format comments with 'n' or '2'
+ const bool do_second_indent = has_format_option(FO_Q_SECOND);
+ const bool do_number_indent = has_format_option(FO_Q_NUMBER);
+ const bool do_trail_white = has_format_option(FO_WHITE_PAR);
+
+ // Get info about the previous and current line.
+ if (curwin->w_cursor.lnum > 1) {
+ is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1,
+ &leader_len, &leader_flags, do_comments);
+ } else {
+ is_not_par = true;
+ }
next_is_not_par = fmt_check_par(curwin->w_cursor.lnum
, &next_leader_len, &next_leader_flags, do_comments
);
@@ -4225,7 +4218,7 @@ format_lines(
* The last line to be formatted.
*/
if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) {
- next_is_not_par = TRUE;
+ next_is_not_par = true;
next_leader_len = 0;
next_leader_flags = NULL;
} else {
@@ -4236,7 +4229,7 @@ format_lines(
next_is_start_par =
(get_number_indent(curwin->w_cursor.lnum + 1) > 0);
}
- advance = TRUE;
+ advance = true;
is_end_par = (is_not_par || next_is_not_par || next_is_start_par);
if (!is_end_par && do_trail_white)
is_end_par = !ends_in_white(curwin->w_cursor.lnum);
@@ -4287,7 +4280,7 @@ format_lines(
leader_len, leader_flags,
next_leader_len, next_leader_flags)
)
- is_end_par = TRUE;
+ is_end_par = true;
/*
* If we have got to the end of a paragraph, or the line is
@@ -4324,9 +4317,9 @@ format_lines(
* end of the paragraph. */
if (line_count < 0)
break;
- first_par_line = TRUE;
+ first_par_line = true;
}
- force_format = FALSE;
+ force_format = false;
}
/*
@@ -4334,7 +4327,7 @@ format_lines(
* first delete the leader from the second line.
*/
if (!is_end_par) {
- advance = FALSE;
+ advance = false;
curwin->w_cursor.lnum++;
curwin->w_cursor.col = 0;
if (line_count < 0 && u_save_cursor() == FAIL)
@@ -4357,12 +4350,13 @@ format_lines(
beep_flush();
break;
}
- first_par_line = FALSE;
- /* If the line is getting long, format it next time */
- if (STRLEN(get_cursor_line_ptr()) > (size_t)max_len)
- force_format = TRUE;
- else
- force_format = FALSE;
+ first_par_line = false;
+ // If the line is getting long, format it next time
+ if (STRLEN(get_cursor_line_ptr()) > (size_t)max_len) {
+ force_format = true;
+ } else {
+ force_format = false;
+ }
}
}
line_breakcheck();
@@ -4423,11 +4417,10 @@ static int fmt_check_par(linenr_T lnum, int *leader_len, char_u **leader_flags,
int paragraph_start(linenr_T lnum)
{
char_u *p;
- int leader_len = 0; /* leader len of current line */
- char_u *leader_flags = NULL; /* flags for leader of current line */
- int next_leader_len = 0; /* leader len of next line */
- char_u *next_leader_flags = NULL; /* flags for leader of next line */
- int do_comments; /* format comments */
+ int leader_len = 0; // leader len of current line
+ char_u *leader_flags = NULL; // flags for leader of current line
+ int next_leader_len = 0; // leader len of next line
+ char_u *next_leader_flags = NULL; // flags for leader of next line
if (lnum <= 1)
return TRUE; /* start of the file */
@@ -4436,7 +4429,7 @@ int paragraph_start(linenr_T lnum)
if (*p == NUL)
return TRUE; /* after empty line */
- do_comments = has_format_option(FO_Q_COMS);
+ const bool do_comments = has_format_option(FO_Q_COMS); // format comments
if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) {
return true; // after non-paragraph line
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 6ae9378236..4569eb1dda 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -3438,6 +3438,7 @@ ambw_end:
// recursively, to avoid endless recurrence.
apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname,
value_changed || syn_recursive == 1, curbuf);
+ curbuf->b_flags |= BF_SYN_SET;
syn_recursive--;
} else if (varp == &(curbuf->b_p_ft)) {
// 'filetype' is set, trigger the FileType autocommand
@@ -6802,7 +6803,8 @@ static void langmap_set(void)
/// Return true if format option 'x' is in effect.
/// Take care of no formatting when 'paste' is set.
-int has_format_option(int x)
+bool has_format_option(int x)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (p_paste) {
return false;
@@ -7269,7 +7271,8 @@ unsigned int get_bkc_value(buf_T *buf)
}
/// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
-int get_fileformat(buf_T *buf)
+int get_fileformat(const buf_T *buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
int c = *buf->b_p_ff;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index a09811c8fb..6630bda710 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -77,12 +77,13 @@
#define FO_ONE_LETTER '1'
#define FO_WHITE_PAR 'w' // trailing white space continues paragr.
#define FO_AUTO 'a' // automatic formatting
+#define FO_RIGOROUS_TW ']' // respect textwidth rigorously
#define FO_REMOVE_COMS 'j' // remove comment leaders when joining lines
#define FO_PERIOD_ABBR 'p' // don't break a single space after a period
#define DFLT_FO_VI "vt"
#define DFLT_FO_VIM "tcqj"
-#define FO_ALL "tcroq2vlb1mMBn,awjp" // for do_set()
+#define FO_ALL "tcroq2vlb1mMBn,aw]jp" // for do_set()
// characters for the p_cpo option:
#define CPO_ALTREAD 'a' // ":read" sets alternate file name
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index bfe230b521..bc774b8ebc 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -161,8 +161,8 @@ static void deadly_signal(int signum)
WLOG("got signal %d (%s)", signum, signal_name(signum));
- snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\n",
- signal_name(signum));
+ snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n",
+ signal_name(signum));
// Preserve files and exit.
preserve_exit();
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 3beada5bc9..d2d20852aa 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -301,49 +301,49 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed,
if (pum_width < p_pw) {
pum_width = (int)p_pw;
}
- }
- } else if (((cursor_col > p_pw || cursor_col > max_width) && !pum_rl)
- || (pum_rl && (cursor_col < Columns - p_pw
- || cursor_col < Columns - max_width))) {
- // align pum edge with "cursor_col"
- if (pum_rl && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1) {
- pum_col = cursor_col + max_width + pum_scrollbar + 1;
- if (pum_col >= Columns) {
- pum_col = Columns - 1;
- }
- } else if (!pum_rl) {
- if (curwin->w_wincol > Columns - max_width - pum_scrollbar
- && max_width <= p_pw) {
- // use full width to end of the screen
- pum_col = cursor_col - max_width - pum_scrollbar;
- if (pum_col < 0) {
- pum_col = 0;
+ } else if (((cursor_col > p_pw || cursor_col > max_width) && !pum_rl)
+ || (pum_rl && (cursor_col < Columns - p_pw
+ || cursor_col < Columns - max_width))) {
+ // align pum edge with "cursor_col"
+ if (pum_rl && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1) {
+ pum_col = cursor_col + max_width + pum_scrollbar + 1;
+ if (pum_col >= Columns) {
+ pum_col = Columns - 1;
+ }
+ } else if (!pum_rl) {
+ if (curwin->w_wincol > Columns - max_width - pum_scrollbar
+ && max_width <= p_pw) {
+ // use full width to end of the screen
+ pum_col = Columns - max_width - pum_scrollbar;
+ if (pum_col < 0) {
+ pum_col = 0;
+ }
}
}
- }
-
- if (pum_rl) {
- pum_width = pum_col - pum_scrollbar + 1;
- } else {
- pum_width = Columns - pum_col - pum_scrollbar;
- }
- if (pum_width < p_pw) {
- pum_width = (int)p_pw;
if (pum_rl) {
- if (pum_width > pum_col) {
- pum_width = pum_col;
- }
+ pum_width = pum_col - pum_scrollbar + 1;
} else {
- if (pum_width >= Columns - pum_col) {
- pum_width = Columns - pum_col - 1;
- }
+ pum_width = Columns - pum_col - pum_scrollbar;
}
- } else if (pum_width > max_width + pum_kind_width + pum_extra_width + 1
- && pum_width > p_pw) {
- pum_width = max_width + pum_kind_width + pum_extra_width + 1;
+
if (pum_width < p_pw) {
pum_width = (int)p_pw;
+ if (pum_rl) {
+ if (pum_width > pum_col) {
+ pum_width = pum_col;
+ }
+ } else {
+ if (pum_width >= Columns - pum_col) {
+ pum_width = Columns - pum_col - 1;
+ }
+ }
+ } else if (pum_width > max_width + pum_kind_width + pum_extra_width + 1
+ && pum_width > p_pw) {
+ pum_width = max_width + pum_kind_width + pum_extra_width + 1;
+ if (pum_width < p_pw) {
+ pum_width = (int)p_pw;
+ }
}
}
} else if (Columns < def_width) {
@@ -919,11 +919,11 @@ void pum_set_event_info(dict_T *dict)
r = (double)pum_row;
c = (double)pum_col;
}
- tv_dict_add_float(dict, S_LEN("height"), h);
- tv_dict_add_float(dict, S_LEN("width"), w);
- tv_dict_add_float(dict, S_LEN("row"), r);
- tv_dict_add_float(dict, S_LEN("col"), c);
- tv_dict_add_nr(dict, S_LEN("size"), pum_size);
- tv_dict_add_bool(dict, S_LEN("scrollbar"),
- pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
+ (void)tv_dict_add_float(dict, S_LEN("height"), h);
+ (void)tv_dict_add_float(dict, S_LEN("width"), w);
+ (void)tv_dict_add_float(dict, S_LEN("row"), r);
+ (void)tv_dict_add_float(dict, S_LEN("col"), c);
+ (void)tv_dict_add_nr(dict, S_LEN("size"), pum_size);
+ (void)tv_dict_add_bool(dict, S_LEN("scrollbar"),
+ pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index fc2e1a4295..1cd7879dc0 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1092,6 +1092,7 @@ qf_init_ext(
)
FUNC_ATTR_NONNULL_ARG(1)
{
+ qf_list_T *qfl;
qfstate_T state = { 0 };
qffields_T fields = { 0 };
qfline_T *old_last = NULL;
@@ -1115,15 +1116,16 @@ qf_init_ext(
// make place for a new list
qf_new_list(qi, qf_title);
qf_idx = qi->qf_curlist;
+ qfl = qf_get_list(qi, qf_idx);
} else {
// Adding to existing list, use last entry.
adding = true;
- if (!qf_list_empty(qf_get_list(qi, qf_idx) )) {
- old_last = qi->qf_lists[qf_idx].qf_last;
+ qfl = qf_get_list(qi, qf_idx);
+ if (!qf_list_empty(qfl)) {
+ old_last = qfl->qf_last;
}
}
- qf_list_T *qfl = qf_get_list(qi, qf_idx);
// Use the local value of 'errorformat' if it's set.
if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) {
@@ -1665,8 +1667,8 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields)
}
if (!qfprev->qf_col) {
qfprev->qf_col = fields->col;
+ qfprev->qf_viscol = fields->use_viscol;
}
- qfprev->qf_viscol = fields->use_viscol;
if (!qfprev->qf_fnum) {
qfprev->qf_fnum = qf_get_fnum(qfl, qfl->qf_directory,
*fields->namebuf || qfl->qf_directory
@@ -1775,7 +1777,7 @@ static void decr_quickfix_busy(void)
void check_quickfix_busy(void)
{
if (quickfix_busy != 0) {
- EMSGN("quickfix_busy not zero on exit: %ld", (long)quickfix_busy);
+ EMSGN("quickfix_busy not zero on exit: %" PRId64, (int64_t)quickfix_busy);
# ifdef ABORT_ON_INTERNAL_ERROR
abort();
# endif
@@ -2453,12 +2455,13 @@ static void win_set_loclist(win_T *wp, qf_info_T *qi)
qi->qf_refcount++;
}
-/// Find a help window or open one.
-static int jump_to_help_window(qf_info_T *qi, int *opened_window)
+/// Find a help window or open one. If 'newwin' is true, then open a new help
+/// window.
+static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window)
{
win_T *wp = NULL;
- if (cmdmod.tab != 0) {
+ if (cmdmod.tab != 0 || newwin) {
wp = NULL;
} else {
wp = qf_find_help_win();
@@ -2476,8 +2479,10 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
flags |= WSP_TOP;
}
- if (IS_LL_STACK(qi)) {
- flags |= WSP_NEWLOC; // don't copy the location list
+ // If the user asks to open a new window, then copy the location list.
+ // Otherwise, don't copy the location list.
+ if (IS_LL_STACK(qi) && !newwin) {
+ flags |= WSP_NEWLOC;
}
if (win_split(0, flags) == FAIL) {
@@ -2490,8 +2495,10 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
win_setheight((int)p_hh);
}
- if (IS_LL_STACK(qi)) { // not a quickfix list
- // The new window should use the supplied location list
+ // When using location list, the new window should use the supplied
+ // location list. If the user asks to open a new window, then the new
+ // window will get a copy of the location list.
+ if (IS_LL_STACK(qi) && !newwin) {
win_set_loclist(curwin, qi);
}
}
@@ -2652,14 +2659,19 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
// Find a suitable window for opening a file (qf_fnum) from the
// quickfix/location list and jump to it. If the file is already opened in a
-// window, jump to it. Otherwise open a new window to display the file. This is
-// called from either a quickfix or a location list window.
-static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
+// window, jump to it. Otherwise open a new window to display the file. If
+// 'newwin' is true, then always open a new window. This is called from either
+// a quickfix or a location list window.
+static int qf_jump_to_usable_window(int qf_fnum, bool newwin,
+ int *opened_window)
{
win_T *usable_win_ptr = NULL;
bool usable_win = false;
- qf_info_T *ll_ref = curwin->w_llist_ref;
+ // If opening a new window, then don't use the location list referred by
+ // the current window. Otherwise two windows will refer to the same
+ // location list.
+ qf_info_T *ll_ref = newwin ? NULL : curwin->w_llist_ref;
if (ll_ref != NULL) {
// Find a non-quickfix window with this location list
usable_win_ptr = qf_find_win_with_loclist(ll_ref);
@@ -2684,7 +2696,7 @@ static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
// If there is only one window and it is the quickfix window, create a
// new one above the quickfix window.
- if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) {
+ if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win || newwin) {
if (qf_open_new_file_win(ll_ref) != OK) {
return FAIL;
}
@@ -2823,11 +2835,12 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
}
/// Find a usable window for opening a file from the quickfix/location list. If
-/// a window is not found then open a new window.
+/// a window is not found then open a new window. If 'newwin' is true, then open
+/// a new window.
/// Returns OK if successfully jumped or opened a window. Returns FAIL if not
/// able to jump/open a window. Returns NOTDONE if a file is not associated
/// with the entry.
-static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr,
+static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin,
int *opened_window)
{
qf_list_T *qfl = qf_get_curlist(qi);
@@ -2837,7 +2850,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr,
// For ":helpgrep" find a help window or open one.
if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) {
- if (jump_to_help_window(qi, opened_window) == FAIL) {
+ if (jump_to_help_window(qi, newwin, opened_window) == FAIL) {
return FAIL;
}
}
@@ -2861,7 +2874,8 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr,
return NOTDONE;
}
- if (qf_jump_to_usable_window(qf_ptr->qf_fnum, opened_window) == FAIL) {
+ if (qf_jump_to_usable_window(qf_ptr->qf_fnum, newwin, opened_window)
+ == FAIL) {
return FAIL;
}
}
@@ -2924,15 +2938,24 @@ static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
return retval;
}
-/// jump to a quickfix ltne
-/// if dir == FORWARD go "errornr" valid entries forward
-/// if dir == BACKWARD go "errornr" valid entries backward
-/// if dir == FORWARD_FILE go "errornr" valid entries files backward
-/// if dir == BACKWARD_FILE go "errornr" valid entries files backward
-/// else if "errornr" is zero, redisplay the same line
-/// else go to entry "errornr"
+/// Jump to a quickfix line and try to use an existing window.
void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
{
+ qf_jump_newwin(qi, dir, errornr, forceit, false);
+}
+
+// Jump to a quickfix line.
+// If dir == 0 go to entry "errornr".
+// If dir == FORWARD go "errornr" valid entries forward.
+// If dir == BACKWARD go "errornr" valid entries backward.
+// If dir == FORWARD_FILE go "errornr" valid entries files backward.
+// If dir == BACKWARD_FILE go "errornr" valid entries files backward
+// else if "errornr" is zero, redisplay the same line
+// If 'forceit' is true, then can discard changes to the current buffer.
+// If 'newwin' is true, then open the file in a new window.
+static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit,
+ bool newwin)
+{
qf_list_T *qfl;
qfline_T *qf_ptr;
qfline_T *old_qf_ptr;
@@ -2975,7 +2998,7 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
print_message = false;
}
- retval = qf_jump_open_window(qi, qf_ptr, &opened_window);
+ retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
if (retval == FAIL) {
goto failed;
}
@@ -3277,7 +3300,7 @@ void qf_history(exarg_T *eap)
qf_info_T *qi = qf_cmd_get_stack(eap, false);
int i;
- if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi))) {
+ if (qf_stack_empty(qi)) {
MSG(_("No entries"));
} else {
for (i = 0; i < qi->qf_listcount; i++) {
@@ -3445,14 +3468,9 @@ void qf_view_result(bool split)
}
if (split) {
- char cmd[32];
-
- snprintf(cmd, sizeof(cmd), "split +%" PRId64 "%s",
- (int64_t)curwin->w_cursor.lnum,
- IS_LL_WINDOW(curwin) ? "ll" : "cc");
- if (do_cmdline_cmd(cmd) == OK) {
- do_cmdline_cmd("clearjumps");
- }
+ // Open the selected entry in a new window
+ qf_jump_newwin(qi, 0, (int)curwin->w_cursor.lnum, false, true);
+ do_cmdline_cmd("clearjumps");
return;
}
@@ -3483,7 +3501,7 @@ void ex_cwindow(exarg_T *eap)
// it if we have errors; otherwise, leave it closed.
if (qf_stack_empty(qi)
|| qfl->qf_nonevalid
- || qf_list_empty(qf_get_curlist(qi))) {
+ || qf_list_empty(qfl)) {
if (win != NULL) {
ex_cclose(eap);
}
@@ -3536,10 +3554,23 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz,
return OK;
}
+// Set options for the buffer in the quickfix or location list window.
+static void qf_set_cwindow_options(void)
+{
+ // switch off 'swapfile'
+ set_option_value("swf", 0L, NULL, OPT_LOCAL);
+ set_option_value("bt", 0L, "quickfix", OPT_LOCAL);
+ set_option_value("bh", 0L, "wipe", OPT_LOCAL);
+ RESET_BINDING(curwin);
+ curwin->w_p_diff = false;
+ set_option_value("fdm", 0L, "manual", OPT_LOCAL);
+}
+
// Open a new quickfix or location list window, load the quickfix buffer and
// set the appropriate options for the window.
// Returns FAIL if the window could not be opened.
-static int qf_open_new_cwindow(const qf_info_T *qi, int height)
+static int qf_open_new_cwindow(qf_info_T *qi, int height)
+ FUNC_ATTR_NONNULL_ALL
{
win_T *oldwin = curwin;
const tabpage_T *const prevtab = curtab;
@@ -3582,14 +3613,13 @@ static int qf_open_new_cwindow(const qf_info_T *qi, int height)
} else {
// Create a new quickfix buffer
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
+ }
- // switch off 'swapfile'
- set_option_value("swf", 0L, NULL, OPT_LOCAL);
- set_option_value("bt", 0L, "quickfix", OPT_LOCAL);
- set_option_value("bh", 0L, "wipe", OPT_LOCAL);
- RESET_BINDING(curwin);
- curwin->w_p_diff = false;
- set_option_value("fdm", 0L, "manual", OPT_LOCAL);
+ // Set the options for the quickfix buffer/window (if not already done)
+ // Do this even if the quickfix buffer was already present, as an autocmd
+ // might have previously deleted (:bdelete) the quickfix buffer.
+ if (curbuf->b_p_bt[0] != 'q') {
+ qf_set_cwindow_options();
}
// Only set the height when still in the same tab page and there is no
@@ -3778,8 +3808,8 @@ static win_T *qf_find_win(const qf_info_T *qi)
// Find a quickfix buffer.
// Searches in windows opened in all the tabs.
-static buf_T *qf_find_buf(const qf_info_T *qi)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+static buf_T *qf_find_buf(qf_info_T *qi)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
FOR_ALL_TAB_WINDOWS(tp, win) {
if (is_qf_win(win, qi)) {
@@ -4922,7 +4952,7 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid,
/// Search for a pattern in all the lines in a buffer and add the matching lines
/// to a quickfix list.
-static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf,
+static bool vgr_match_buflines(qf_list_T *qfl, char_u *fname, buf_T *buf,
regmmatch_T *regmatch, long *tomatch,
int duplicate_name, int flags)
FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5)
@@ -4936,7 +4966,7 @@ static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf,
// Pass the buffer number so that it gets used even for a
// dummy buffer, unless duplicate_name is set, then the
// buffer will be wiped out below.
- if (qf_add_entry(qf_get_curlist(qi),
+ if (qf_add_entry(qfl,
NULL, // dir
fname,
NULL,
@@ -4997,6 +5027,20 @@ static void vgr_jump_to_match(qf_info_T *qi, int forceit, int *redraw_for_dummy,
}
}
+// Return true if "buf" had an existing swap file, the current swap file does
+// not end in ".swp".
+static bool existing_swapfile(const buf_T *buf)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
+ const char_u *const fname = buf->b_ml.ml_mfp->mf_fname;
+ const size_t len = STRLEN(fname);
+
+ return fname[len - 1] != 'p' || fname[len - 2] != 'w';
+ }
+ return false;
+}
+
// ":vimgrep {pattern} file(s)"
// ":vimgrepadd {pattern} file(s)"
// ":lvimgrep {pattern} file(s)"
@@ -5129,7 +5173,8 @@ void ex_vimgrep(exarg_T *eap)
} else {
// Try for a match in all lines of the buffer.
// For ":1vimgrep" look for first match only.
- found_match = vgr_match_buflines(qi, fname, buf, &regmatch, &tomatch,
+ found_match = vgr_match_buflines(qf_get_curlist(qi),
+ fname, buf, &regmatch, &tomatch,
duplicate_name, flags);
if (using_dummy) {
@@ -5153,7 +5198,9 @@ void ex_vimgrep(exarg_T *eap)
if (!found_match) {
wipe_dummy_buffer(buf, dirname_start);
buf = NULL;
- } else if (buf != first_match_buf || (flags & VGR_NOJUMP)) {
+ } else if (buf != first_match_buf
+ || (flags & VGR_NOJUMP)
+ || existing_swapfile(buf)) {
unload_dummy_buffer(buf, dirname_start);
// Keeping the buffer, remove the dummy flag.
buf->b_flags &= ~BF_DUMMY;
@@ -6119,6 +6166,49 @@ static int qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
return OK;
}
+// Set the current index in the specified quickfix list
+static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl,
+ const dictitem_T *di)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int newidx;
+
+ // If the specified index is '$', then use the last entry
+ if (di->di_tv.v_type == VAR_STRING
+ && di->di_tv.vval.v_string != NULL
+ && STRCMP(di->di_tv.vval.v_string, "$") == 0) {
+ newidx = qfl->qf_count;
+ } else {
+ // Otherwise use the specified index
+ bool denote = false;
+ newidx = (int)tv_get_number_chk(&di->di_tv, &denote);
+ if (denote) {
+ return FAIL;
+ }
+ }
+
+ if (newidx < 1) { // sanity check
+ return FAIL;
+ }
+ if (newidx > qfl->qf_count) {
+ newidx = qfl->qf_count;
+ }
+ const int old_qfidx = qfl->qf_index;
+ qfline_T *const qf_ptr = get_nth_entry(qfl, newidx, &newidx);
+ if (qf_ptr == NULL) {
+ return FAIL;
+ }
+ qfl->qf_ptr = qf_ptr;
+ qfl->qf_index = newidx;
+
+ // If the current list is modified and it is displayed in the quickfix
+ // window, then Update it.
+ if (qi->qf_lists[qi->qf_curlist].qf_id == qfl->qf_id) {
+ qf_win_pos_update(qi, old_qfidx);
+ }
+ return OK;
+}
+
/// Set quickfix/location list properties (title, items, context).
/// Also used to add items from parsing a list of lines.
/// Used by the setqflist() and setloclist() Vim script functions.
@@ -6154,6 +6244,9 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
retval = qf_setprop_context(qfl, di);
}
+ if ((di = tv_dict_find(what, S_LEN("idx"))) != NULL) {
+ retval = qf_setprop_curidx(qi, qfl, di);
+ }
if (retval == OK) {
qf_list_changed(qfl);
@@ -6164,7 +6257,8 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
/// Find the non-location list window with the specified location list stack in
/// the current tabpage.
-static win_T * find_win_with_ll(qf_info_T *qi)
+static win_T *find_win_with_ll(const qf_info_T *qi)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if ((wp->w_llist == qi) && !bt_quickfix(wp->w_buffer)) {
@@ -6223,6 +6317,7 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi)
// Populate the quickfix list with the items supplied in the list
// of dictionaries. "title" will be copied to w:quickfix_title
// "action" is 'a' for add, 'r' for replace. Otherwise create a new list.
+// When "what" is not NULL then only set some properties.
int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
dict_T *what)
{
@@ -6239,6 +6334,12 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
return OK;
}
+ // A dict argument cannot be specified with a non-empty list argument
+ if (list != NULL && tv_list_len(list) != 0 && what != NULL) {
+ EMSG2(_(e_invarg2), _("cannot have both a list and a \"what\" argument"));
+ return FAIL;
+ }
+
incr_quickfix_busy();
if (what != NULL) {
@@ -6538,7 +6639,7 @@ static qf_info_T *hgr_get_ll(bool *new_ll)
// Search for a pattern in a help file.
static void hgr_search_file(
- qf_info_T *qi,
+ qf_list_T *qfl,
char_u *fname,
regmatch_T *p_regmatch)
FUNC_ATTR_NONNULL_ARG(1, 3)
@@ -6560,7 +6661,7 @@ static void hgr_search_file(
line[--l] = NUL;
}
- if (qf_add_entry(qf_get_curlist(qi),
+ if (qf_add_entry(qfl,
NULL, // dir
fname,
NULL,
@@ -6593,7 +6694,7 @@ static void hgr_search_file(
// Search for a pattern in all the help files in the doc directory under
// the given directory.
static void hgr_search_files_in_dir(
- qf_info_T *qi,
+ qf_list_T *qfl,
char_u *dirname,
regmatch_T *p_regmatch,
const char_u *lang)
@@ -6618,7 +6719,7 @@ static void hgr_search_files_in_dir(
continue;
}
- hgr_search_file(qi, fnames[fi], p_regmatch);
+ hgr_search_file(qfl, fnames[fi], p_regmatch);
}
FreeWild(fcount, fnames);
}
@@ -6628,7 +6729,7 @@ static void hgr_search_files_in_dir(
// and add the matches to a quickfix list.
// 'lang' is the language specifier. If supplied, then only matches in the
// specified language are found.
-static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch,
+static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch,
const char_u *lang)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
@@ -6637,7 +6738,7 @@ static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch,
while (*p != NUL && !got_int) {
copy_option_part(&p, NameBuff, MAXPATHL, ",");
- hgr_search_files_in_dir(qi, NameBuff, p_regmatch, lang);
+ hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, lang);
}
}
@@ -6679,12 +6780,12 @@ void ex_helpgrep(exarg_T *eap)
if (regmatch.regprog != NULL) {
// Create a new quickfix list.
qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
+ qf_list_T *const qfl = qf_get_curlist(qi);
- hgr_search_in_rtp(qi, &regmatch, lang);
+ hgr_search_in_rtp(qfl, &regmatch, lang);
vim_regfree(regmatch.regprog);
- qf_list_T *qfl = qf_get_curlist(qi);
qfl->qf_nonevalid = false;
qfl->qf_ptr = qfl->qf_start;
qfl->qf_index = 1;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 1191886888..df0c5ce791 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -176,7 +176,7 @@ static bool provider_invoke(NS ns_id, const char *name, LuaRef ref,
textlock--;
if (!ERROR_SET(&err)
- && api_is_truthy(ret, "provider %s retval", default_true, &err)) {
+ && api_coerce_to_bool(ret, "provider %s retval", default_true, &err)) {
return true;
}
@@ -3634,7 +3634,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
mb_utf8 = false; // don't draw as UTF-8
}
} else if (c != NUL) {
- p_extra = transchar(c);
+ p_extra = transchar_buf(wp->w_buffer, c);
if (n_extra == 0) {
n_extra = byte2cells(c) - 1;
}
diff --git a/src/nvim/search.c b/src/nvim/search.c
index ea2107c5c7..9458e6333f 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -3436,7 +3436,6 @@ current_tagblock(
pos_T start_pos;
pos_T end_pos;
pos_T old_start, old_end;
- char_u *spat, *epat;
char_u *p;
char_u *cp;
int len;
@@ -3490,9 +3489,9 @@ again:
*/
for (long n = 0; n < count; n++) {
if (do_searchpair(
- (char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
- (char_u *)"",
- (char_u *)"</[^>]*>", BACKWARD, NULL, 0,
+ "<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
+ "",
+ "</[^>]*>", BACKWARD, NULL, 0,
NULL, (linenr_T)0, 0L) <= 0) {
curwin->w_cursor = old_pos;
goto theend;
@@ -3514,12 +3513,15 @@ again:
curwin->w_cursor = old_pos;
goto theend;
}
- spat = xmalloc(len + 31);
- epat = xmalloc(len + 9);
- sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
- sprintf((char *)epat, "</%.*s>\\c", len, p);
-
- const int r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
+ const size_t spat_len = len + 39;
+ char *const spat = xmalloc(spat_len);
+ const size_t epat_len = len + 9;
+ char *const epat = xmalloc(epat_len);
+ snprintf(spat, spat_len,
+ "<%.*s\\>\\%%(\\_s\\_[^>]\\{-}\\_[^/]>\\|\\_s\\?>\\)\\c", len, p);
+ snprintf(epat, epat_len, "</%.*s>\\c", len, p);
+
+ const int r = do_searchpair(spat, "", epat, FORWARD, NULL,
0, NULL, (linenr_T)0, 0L);
xfree(spat);
@@ -4097,7 +4099,7 @@ abort_search:
int
current_search(
long count,
- int forward // true for forward, false for backward
+ bool forward // true for forward, false for backward
)
{
bool old_p_ws = p_ws;
@@ -4112,6 +4114,11 @@ current_search(
pos_T pos; // position after the pattern
int result; // result of various function calls
+ // When searching forward and the cursor is at the start of the Visual
+ // area, skip the first search backward, otherwise it doesn't move.
+ const bool skip_first_backward = forward && VIsual_active
+ && lt(curwin->w_cursor, VIsual);
+
orig_pos = pos = curwin->w_cursor;
if (VIsual_active) {
// Searching further will extend the match.
@@ -4129,13 +4136,20 @@ current_search(
return FAIL; // pattern not found
}
- /*
- * The trick is to first search backwards and then search forward again,
- * so that a match at the current cursor position will be correctly
- * captured.
- */
+ // The trick is to first search backwards and then search forward again,
+ // so that a match at the current cursor position will be correctly
+ // captured. When "forward" is false do it the other way around.
for (int i = 0; i < 2; i++) {
- int dir = forward ? i : !i;
+ int dir;
+ if (forward) {
+ if (i == 0 && skip_first_backward) {
+ continue;
+ }
+ dir = i;
+ } else {
+ dir = !i;
+ }
+
int flags = 0;
if (!dir && !zero_width) {
@@ -4182,11 +4196,17 @@ current_search(
VIsual = start_pos;
}
- // put cursor on last character of match
+ // put the cursor after the match
curwin->w_cursor = end_pos;
if (lt(VIsual, end_pos) && forward) {
- dec_cursor();
- } else if (VIsual_active && lt(curwin->w_cursor, VIsual)) {
+ if (skip_first_backward) {
+ // put the cursor on the start of the match
+ curwin->w_cursor = pos;
+ } else {
+ // put the cursor on last character of match
+ dec_cursor();
+ }
+ } else if (VIsual_active && lt(curwin->w_cursor, VIsual) && forward) {
curwin->w_cursor = pos; // put the cursor on the start of the match
}
VIsual_active = true;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index f036d7fe04..1984a357c3 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -396,8 +396,7 @@ size_t spell_check(
mi.mi_word = ptr;
mi.mi_fend = ptr;
if (spell_iswordp(mi.mi_fend, wp)) {
- int prev_upper;
- int this_upper;
+ bool this_upper = false; // init for gcc
if (use_camel_case) {
c = PTR2CHAR(mi.mi_fend);
@@ -407,7 +406,7 @@ size_t spell_check(
do {
MB_PTR_ADV(mi.mi_fend);
if (use_camel_case) {
- prev_upper = this_upper;
+ const bool prev_upper = this_upper;
c = PTR2CHAR(mi.mi_fend);
this_upper = SPELL_ISUPPER(c);
camel_case = !prev_upper && this_upper;
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 765ba2cbb6..b02514143c 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -78,6 +78,9 @@ set encoding=utf-8
let s:test_script_fname = expand('%')
au! SwapExists * call HandleSwapExists()
func HandleSwapExists()
+ if exists('g:ignoreSwapExists')
+ return
+ endif
" Ignore finding a swap file for the test script (the user might be
" editing it and do ":make test_name") and the output file.
" Report finding another swap file and chose 'q' to avoid getting stuck.
diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim
index 9bc037a59f..4f1ddcd7b9 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -56,6 +56,9 @@ endfunc
" Run "cmd". Returns the job if using a job.
func RunCommand(cmd)
+ " Running an external command can occasionally be slow or fail.
+ let g:test_is_flaky = 1
+
let job = 0
if has('job')
let job = job_start(a:cmd, {"stoponexit": "hup"})
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 5668f45dea..7647475427 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -13,7 +13,6 @@ source test_ex_undo.vim
source test_ex_z.vim
source test_execute_func.vim
source test_expand_func.vim
-source test_expr.vim
source test_feedkeys.vim
source test_filter_cmd.vim
source test_filter_map.vim
@@ -50,6 +49,7 @@ source test_tagjump.vim
source test_taglist.vim
source test_true_false.vim
source test_unlet.vim
+source test_version.vim
source test_virtualedit.vim
source test_window_cmd.vim
source test_wnext.vim
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 094bb3ebd1..04a678eeb8 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1897,4 +1897,17 @@ func Test_autocmd_FileReadCmd()
delfunc ReadFileCmd
endfunc
+" Tests for SigUSR1 autocmd event, which is only available on posix systems.
+func Test_autocmd_sigusr1()
+ CheckUnix
+
+ let g:sigusr1_passed = 0
+ au Signal SIGUSR1 let g:sigusr1_passed = 1
+ call system('/bin/kill -s usr1 ' . getpid())
+ call WaitForAssert({-> assert_true(g:sigusr1_passed)})
+
+ au! Signal
+ unlet g:sigusr1_passed
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cjk_linebreak.vim b/src/nvim/testdir/test_cjk_linebreak.vim
new file mode 100644
index 0000000000..dfaa8fa1af
--- /dev/null
+++ b/src/nvim/testdir/test_cjk_linebreak.vim
@@ -0,0 +1,97 @@
+scriptencoding utf-8
+
+func Run_cjk_linebreak_after(rigorous)
+ set textwidth=12
+ for punct in [
+ \ '!', '%', ')', ',', ':', ';', '>', '?', ']', '}', '’', '”', '†', '‡',
+ \ '…', '‰', '‱', '‼', '⁇', '⁈', '⁉', '℃', '℉', '、', '。', '〉', '》',
+ \ '」', '』', '】', '〕', '〗', '〙', '〛', '!', ')', ',', '.', ':',
+ \ ';', '?', ']', '}']
+ call setline('.', '这是一个测试' .. punct.'试试 CJK 行禁则补丁。')
+ normal gqq
+ if a:rigorous
+ call assert_equal('这是一个测', getline(1))
+ else
+ call assert_equal('这是一个测试' .. punct, getline(1))
+ endif
+ %d_
+ endfor
+endfunc
+
+func Test_cjk_linebreak_after()
+ set formatoptions=croqn2mB1j
+ call Run_cjk_linebreak_after(0)
+endfunc
+
+func Test_cjk_linebreak_after_rigorous()
+ set formatoptions=croqn2mB1j]
+ call Run_cjk_linebreak_after(1)
+endfunc
+
+func Run_cjk_linebreak_before()
+ set textwidth=12
+ for punct in [
+ \ '(', '<', '[', '`', '{', '‘', '“', '〈', '《', '「', '『', '【', '〔',
+ \ '〖', '〘', '〚', '(', '[', '{']
+ call setline('.', '这是个测试' .. punct.'试试 CJK 行禁则补丁。')
+ normal gqq
+ call assert_equal('这是个测试', getline(1))
+ %d_
+ endfor
+endfunc
+
+func Test_cjk_linebreak_before()
+ set formatoptions=croqn2mB1j
+ call Run_cjk_linebreak_before()
+endfunc
+
+func Test_cjk_linebreak_before_rigorous()
+ set formatoptions=croqn2mB1j]
+ call Run_cjk_linebreak_before()
+endfunc
+
+func Run_cjk_linebreak_nobetween(rigorous)
+ " …… must not start a line
+ call setline('.', '这是个测试……试试 CJK 行禁则补丁。')
+ set textwidth=12 ambiwidth=double
+ normal gqq
+ if a:rigorous
+ call assert_equal('这是个测', getline(1))
+ else
+ call assert_equal('这是个测试……', getline(1))
+ endif
+ %d_
+
+ call setline('.', '这是一个测试……试试 CJK 行禁则补丁。')
+ set textwidth=12 ambiwidth=double
+ normal gqq
+ call assert_equal('这是一个测', getline(1))
+ %d_
+
+ " but —— can
+ call setline('.', '这是个测试——试试 CJK 行禁则补丁。')
+ set textwidth=12 ambiwidth=double
+ normal gqq
+ call assert_equal('这是个测试', getline(1))
+endfunc
+
+func Test_cjk_linebreak_nobetween()
+ set formatoptions=croqn2mB1j
+ call Run_cjk_linebreak_nobetween(0)
+endfunc
+
+func Test_cjk_linebreak_nobetween_rigorous()
+ set formatoptions=croqn2mB1j]
+ call Run_cjk_linebreak_nobetween(1)
+endfunc
+
+func Test_cjk_linebreak_join_punct()
+ for punct in ['——', '〗', ',', '。', '……']
+ call setline(1, '文本文本' .. punct)
+ call setline(2, 'English')
+ set formatoptions=croqn2mB1j
+ normal ggJ
+ call assert_equal('文本文本' .. punct.'English', getline(1))
+ %d_
+ endfor
+endfunc
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index e853b046dc..c702b44b88 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -185,6 +185,47 @@ func Test_scroll_CursorLineNr_update()
call delete(filename)
endfunc
+" check a long file name does not result in the hit-enter prompt
+func Test_edit_long_file_name()
+ CheckScreendump
+
+ let longName = 'x'->repeat(min([&columns, 255]))
+ call writefile([], longName)
+ let buf = RunVimInTerminal('-N -u NONE ' .. longName, #{rows: 8})
+
+ call VerifyScreenDump(buf, 'Test_long_file_name_1', {})
+
+ call term_sendkeys(buf, ":q\<cr>")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete(longName)
+endfunc
+
+func Test_unprintable_fileformats()
+ CheckScreendump
+
+ call writefile(["unix\r", "two"], 'Xunix.txt')
+ call writefile(["mac\r", "two"], 'Xmac.txt')
+ let lines =<< trim END
+ edit Xunix.txt
+ split Xmac.txt
+ edit ++ff=mac
+ END
+ let filename = 'Xunprintable'
+ call writefile(lines, filename)
+ let buf = RunVimInTerminal('-S '.filename, #{rows: 9, cols: 50})
+ call VerifyScreenDump(buf, 'Test_display_unprintable_01', {})
+ call term_sendkeys(buf, "\<C-W>\<C-W>\<C-L>")
+ call VerifyScreenDump(buf, 'Test_display_unprintable_02', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xunix.txt')
+ call delete('Xmac.txt')
+ call delete(filename)
+endfunc
+
" Test for scrolling that modifies buffer during visual block
func Test_visual_block_scroll()
" See test/functional/legacy/visual_mode_spec.lua
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index d4b1c63741..15c718b243 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -1441,31 +1441,40 @@ endfunc
func Test_edit_InsertLeave()
new
+ au InsertLeavePre * let g:did_au_pre = 1
au InsertLeave * let g:did_au = 1
+ let g:did_au_pre = 0
let g:did_au = 0
call feedkeys("afoo\<Esc>", 'tx')
+ call assert_equal(1, g:did_au_pre)
call assert_equal(1, g:did_au)
call assert_equal('foo', getline(1))
+ let g:did_au_pre = 0
let g:did_au = 0
call feedkeys("Sbar\<C-C>", 'tx')
+ call assert_equal(1, g:did_au_pre)
call assert_equal(0, g:did_au)
call assert_equal('bar', getline(1))
inoremap x xx<Esc>
+ let g:did_au_pre = 0
let g:did_au = 0
call feedkeys("Saax", 'tx')
+ call assert_equal(1, g:did_au_pre)
call assert_equal(1, g:did_au)
call assert_equal('aaxx', getline(1))
inoremap x xx<C-C>
+ let g:did_au_pre = 0
let g:did_au = 0
call feedkeys("Sbbx", 'tx')
+ call assert_equal(1, g:did_au_pre)
call assert_equal(0, g:did_au)
call assert_equal('bbxx', getline(1))
bwipe!
- au! InsertLeave
+ au! InsertLeave InsertLeavePre
iunmap x
endfunc
@@ -1559,3 +1568,23 @@ func Test_edit_is_a_directory()
call delete(dirname, 'rf')
endfunc
+
+func Test_edit_browse()
+ " in the GUI this opens a file picker, we only test the terminal behavior
+ CheckNotGui
+
+ " ":browse xxx" checks for the FileExplorer augroup and assumes editing "."
+ " works then.
+ augroup FileExplorer
+ au!
+ augroup END
+
+ " When the USE_FNAME_CASE is defined this used to cause a crash.
+ browse enew
+ bwipe!
+
+ browse split
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index c7ca682c8c..9f79c1b545 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -532,6 +532,7 @@ let s:filename_case_checks = {
\ }
func CheckItems(checks)
+ set noswapfile
for [ft, names] in items(a:checks)
for i in range(0, len(names) - 1)
new
@@ -548,6 +549,7 @@ func CheckItems(checks)
bwipe!
endfor
endfor
+ set swapfile&
endfunc
func Test_filetype_detection()
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 8fa70a5313..917a5e8eca 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -214,7 +214,7 @@ func Test_strftime()
endif
endfunc
-func Test_resolve()
+func Test_resolve_unix()
if !has('unix')
return
endif
@@ -258,6 +258,8 @@ func Test_resolve()
call assert_equal('Xlink2', resolve('Xlink1'))
call assert_equal('./Xlink2', resolve('./Xlink1'))
call delete('Xlink1')
+
+ call assert_equal('/', resolve('/'))
endfunc
func Test_simplify()
@@ -1083,6 +1085,12 @@ func Test_trim()
call assert_equal("", trim("", ""))
call assert_equal("a", trim("a", ""))
call assert_equal("", trim("", "a"))
+ call assert_equal("vim", trim(" vim ", " ", 0))
+ call assert_equal("vim ", trim(" vim ", " ", 1))
+ call assert_equal(" vim", trim(" vim ", " ", 2))
+ call assert_fails('call trim(" vim ", " ", [])', 'E745:')
+ call assert_fails('call trim(" vim ", " ", -1)', 'E475:')
+ call assert_fails('call trim(" vim ", " ", 3)', 'E475:')
let chars = join(map(range(1, 0x20) + [0xa0], {n -> nr2char(n)}), '')
call assert_equal("x", trim(chars . "x" . chars))
diff --git a/src/nvim/testdir/test_gn.vim b/src/nvim/testdir/test_gn.vim
index d41675be0c..9acec51913 100644
--- a/src/nvim/testdir/test_gn.vim
+++ b/src/nvim/testdir/test_gn.vim
@@ -158,7 +158,32 @@ func Test_gn_command()
set wrapscan&vim
set belloff&vim
-endfu
+endfunc
+
+func Test_gN_repeat()
+ new
+ call setline(1, 'this list is a list with a list of a list.')
+ /list
+ normal $gNgNgNx
+ call assert_equal('list with a list of a list', @")
+ bwipe!
+endfunc
+
+func Test_gN_then_gn()
+ new
+
+ call setline(1, 'this list is a list with a list of a last.')
+ /l.st
+ normal $gNgNgnx
+ call assert_equal('last', @")
+
+ call setline(1, 'this list is a list with a lust of a last.')
+ /l.st
+ normal $gNgNgNgnx
+ call assert_equal('lust of a last', @")
+
+ bwipe!
+endfunc
func Test_gn_multi_line()
new
diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
index 1339a9f25d..b8632b9595 100644
--- a/src/nvim/testdir/test_ins_complete.vim
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -327,7 +327,10 @@ func Test_compl_in_cmdwin()
set wildmenu wildchar=<Tab>
com! -nargs=1 -complete=command GetInput let input = <q-args>
com! -buffer TestCommand echo 'TestCommand'
+ let w:test_winvar = 'winvar'
+ let b:test_bufvar = 'bufvar'
+ " User-defined commands
let input = ''
call feedkeys("q:iGetInput T\<C-x>\<C-v>\<CR>", 'tx!')
call assert_equal('TestCommand', input)
@@ -336,8 +339,29 @@ func Test_compl_in_cmdwin()
call feedkeys("q::GetInput T\<Tab>\<CR>:q\<CR>", 'tx!')
call assert_equal('T', input)
+ com! -nargs=1 -complete=var GetInput let input = <q-args>
+ " Window-local variables
+ let input = ''
+ call feedkeys("q:iGetInput w:test_\<C-x>\<C-v>\<CR>", 'tx!')
+ call assert_equal('w:test_winvar', input)
+
+ let input = ''
+ call feedkeys("q::GetInput w:test_\<Tab>\<CR>:q\<CR>", 'tx!')
+ call assert_equal('w:test_', input)
+
+ " Buffer-local variables
+ let input = ''
+ call feedkeys("q:iGetInput b:test_\<C-x>\<C-v>\<CR>", 'tx!')
+ call assert_equal('b:test_bufvar', input)
+
+ let input = ''
+ call feedkeys("q::GetInput b:test_\<Tab>\<CR>:q\<CR>", 'tx!')
+ call assert_equal('b:test_', input)
+
delcom TestCommand
delcom GetInput
+ unlet w:test_winvar
+ unlet b:test_bufvar
set wildmenu& wildchar&
endfunc
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 7fbf04311d..ca14494248 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -74,6 +74,7 @@ func Test_echomsg()
call assert_equal("\n12345", execute(':echomsg 12345'))
call assert_equal("\n[]", execute(':echomsg []'))
call assert_equal("\n[1, 2, 3]", execute(':echomsg [1, 2, 3]'))
+ call assert_equal("\n[1, 2, []]", execute(':echomsg [1, 2, v:_null_list]'))
call assert_equal("\n{}", execute(':echomsg {}'))
call assert_equal("\n{'a': 1, 'b': 2}", execute(':echomsg {"a": 1, "b": 2}'))
if has('float')
diff --git a/src/nvim/testdir/test_perl.vim b/src/nvim/testdir/test_perl.vim
index 2343f389fa..872194a804 100644
--- a/src/nvim/testdir/test_perl.vim
+++ b/src/nvim/testdir/test_perl.vim
@@ -4,6 +4,7 @@ if !has('perl') || has('win32')
finish
endif
+" FIXME: RunTest don't see any error when Perl abort...
perl $SIG{__WARN__} = sub { die "Unexpected warnings from perl: @_" };
func Test_change_buffer()
@@ -23,11 +24,15 @@ func Test_evaluate_list()
$l = VIM::Eval("l");
$curbuf->Append($curline, $l);
EOF
+ normal j
+ .perldo s|\n|/|g
+ " call assert_equal('abc/def/', getline('$'))
+ call assert_equal('def', getline('$'))
endfunc
funct Test_VIM_Blob()
call assert_equal('0z', perleval('VIM::Blob("")'))
- "call assert_equal('0z31326162', 'VIM::Blob("12ab")'->perleval())
+ call assert_equal('0z31326162', perleval('VIM::Blob("12ab")'))
call assert_equal('0z00010203', perleval('VIM::Blob("\x00\x01\x02\x03")'))
call assert_equal('0z8081FEFF', perleval('VIM::Blob("\x80\x81\xfe\xff")'))
endfunc
@@ -46,7 +51,6 @@ func Test_buffer_Append()
new
perl $curbuf->Append(1, '1')
perl $curbuf->Append(2, '2', '3', '4')
- call assert_equal(['', '1', '2', '3', '4'], getline(1, '$'))
perl @l = ('5' ..'7')
perl $curbuf->Append(0, @l)
call assert_equal(['5', '6', '7', '', '1', '2', '3', '4'], getline(1, '$'))
@@ -114,7 +118,7 @@ func Test_VIM_Windows()
perl $curbuf->Append(0, $winnr, scalar(@winlist))
call assert_equal(['2', '2', ''], getline(1, '$'))
- "" VIM::Windows() with window number argument.
+ " VIM::Windows() with window number argument.
perl (VIM::Windows(VIM::Eval('winnr()')))[0]->Buffer()->Set(1, 'bar')
call assert_equal('bar', getline(1))
bwipe!
@@ -133,10 +137,20 @@ func Test_VIM_Buffers()
bwipe!
endfunc
+func <SID>catch_peval(expr)
+ try
+ call perleval(a:expr)
+ catch
+ return v:exception
+ endtry
+ call assert_report('no exception for `perleval("'.a:expr.'")`')
+ return ''
+endfunc
+
func Test_perleval()
call assert_false(perleval('undef'))
- "" scalar
+ " scalar
call assert_equal(0, perleval('0'))
call assert_equal(2, perleval('2'))
call assert_equal(-2, perleval('-2'))
@@ -146,9 +160,12 @@ func Test_perleval()
call assert_equal(2, perleval('2.5'))
end
+ " sandbox call assert_equal(2, perleval('2'))
+
call assert_equal('abc', perleval('"abc"'))
+ " call assert_equal("abc\ndef", perleval('"abc\0def"'))
- "" ref
+ " ref
call assert_equal([], perleval('[]'))
call assert_equal(['word', 42, [42],{}], perleval('["word", 42, [42], {}]'))
@@ -156,13 +173,19 @@ func Test_perleval()
call assert_equal({'foo': 'bar'}, perleval('{foo => "bar"}'))
perl our %h; our @a;
- let a = perleval('[\%h, \%h, \@a, \@a]')
- echo a
+ let a = perleval('[\(%h, %h, @a, @a)]')
+ " call assert_true((a[0] is a[1]))
call assert_equal(a[0], a[1])
+ " call assert_true((a[2] is a[3]))
call assert_equal(a[2], a[3])
perl undef %h; undef @a;
+ " call assert_true(<SID>catch_peval('{"" , 0}') =~ 'Malformed key Dictionary')
+ " call assert_true(<SID>catch_peval('{"\0" , 0}') =~ 'Malformed key Dictionary')
+ " call assert_true(<SID>catch_peval('{"foo\0bar" , 0}') =~ 'Malformed key Dictionary')
+
call assert_equal('*VIM', perleval('"*VIM"'))
+ " call assert_true(perleval('\\0') =~ 'SCALAR(0x\x\+)')
endfunc
func Test_perldo()
@@ -179,7 +202,7 @@ func Test_perldo()
perldo VIM::DoCommand("%d_")
bwipe!
- "" Check switching to another buffer does not trigger ml_get error.
+ " Check switching to another buffer does not trigger ml_get error.
new
let wincount = winnr('$')
call setline(1, ['one', 'two', 'three'])
@@ -198,6 +221,69 @@ func Test_VIM_package()
call assert_true(&et)
endfunc
+func Test_stdio()
+ throw 'skipped: TODO: '
+ redir =>l:out
+ perl <<EOF
+ VIM::Msg("&VIM::Msg");
+ print "STDOUT";
+ print STDERR "STDERR";
+EOF
+ redir END
+ call assert_equal(['&VIM::Msg', 'STDOUT', 'STDERR'], split(l:out, "\n"))
+endfunc
+
+" Run first to get a clean namespace
+func Test_000_SvREFCNT()
+ throw 'skipped: TODO: '
+ for i in range(8)
+ exec 'new X'.i
+ endfor
+ new t
+ perl <<--perl
+#line 5 "Test_000_SvREFCNT()"
+ my ($b, $w);
+
+ my $num = 0;
+ for ( 0 .. 100 ) {
+ if ( ++$num >= 8 ) { $num = 0 }
+ VIM::DoCommand("buffer X$num");
+ $b = $curbuf;
+ }
+
+ VIM::DoCommand("buffer t");
+
+ $b = $curbuf for 0 .. 100;
+ $w = $curwin for 0 .. 100;
+ () = VIM::Buffers for 0 .. 100;
+ () = VIM::Windows for 0 .. 100;
+
+ VIM::DoCommand('bw! t');
+ if (exists &Internals::SvREFCNT) {
+ my $cb = Internals::SvREFCNT($$b);
+ my $cw = Internals::SvREFCNT($$w);
+ VIM::Eval("assert_equal(2, $cb, 'T1')");
+ VIM::Eval("assert_equal(2, $cw, 'T2')");
+ my $strongref;
+ foreach ( VIM::Buffers, VIM::Windows ) {
+ VIM::DoCommand("%bw!");
+ my $c = Internals::SvREFCNT($_);
+ VIM::Eval("assert_equal(2, $c, 'T3')");
+ $c = Internals::SvREFCNT($$_);
+ next if $c == 2 && !$strongref++;
+ VIM::Eval("assert_equal(1, $c, 'T4')");
+ }
+ $cb = Internals::SvREFCNT($$curbuf);
+ $cw = Internals::SvREFCNT($$curwin);
+ VIM::Eval("assert_equal(3, $cb, 'T5')");
+ VIM::Eval("assert_equal(3, $cw, 'T6')");
+ }
+ VIM::Eval("assert_false($$b)");
+ VIM::Eval("assert_false($$w)");
+--perl
+ %bw!
+endfunc
+
func Test_set_cursor()
" Check that setting the cursor position works.
new
diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim
index 884ada7e88..15745d5619 100644
--- a/src/nvim/testdir/test_put.vim
+++ b/src/nvim/testdir/test_put.vim
@@ -22,12 +22,21 @@ endfunc
func Test_put_char_block2()
new
- let a = [ getreg('a'), getregtype('a') ]
call setreg('a', ' one ', 'v')
call setline(1, ['Line 1', '', 'Line 3', ''])
" visually select the first 3 lines and put register a over it
exe "norm! ggl\<c-v>2j2l\"ap"
- call assert_equal(['L one 1', '', 'L one 3', ''], getline(1,4))
+ call assert_equal(['L one 1', '', 'L one 3', ''], getline(1, 4))
+ " clean up
+ bw!
+endfunc
+
+func Test_put_lines()
+ new
+ let a = [ getreg('a'), getregtype('a') ]
+ call setline(1, ['Line 1', 'Line2', 'Line 3', ''])
+ exe 'norm! gg"add"AddG""p'
+ call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1, '$'))
" clean up
bw!
call setreg('a', a[0], a[1])
@@ -42,21 +51,10 @@ func Test_put_expr()
exec "4norm! \"=\<cr>P"
norm! j0.
norm! j0.
- call assert_equal(['A1','A2','A3','4A','5A','6A'], getline(1,'$'))
+ call assert_equal(['A1','A2','A3','4A','5A','6A'], getline(1, '$'))
bw!
endfunc
-func Test_put_lines()
- new
- let a = [ getreg('a'), getregtype('a') ]
- call setline(1, ['Line 1', 'Line2', 'Line 3', ''])
- exe 'norm! gg"add"AddG""p'
- call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1,'$'))
- " clean up
- bw!
- call setreg('a', a[0], a[1])
-endfunc
-
func Test_put_fails_when_nomodifiable()
new
setlocal nomodifiable
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 4090db2874..cf0af07528 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -1,8 +1,7 @@
" Test for the quickfix commands.
-if !has('quickfix')
- finish
-endif
+source check.vim
+CheckFeature quickfix
set encoding=utf-8
@@ -1916,6 +1915,13 @@ func HistoryTest(cchar)
call g:Xsetlist([], 'f')
let l = split(execute(a:cchar . 'hist'), "\n")
call assert_equal('No entries', l[0])
+
+ " An empty list should still show the stack history
+ call g:Xsetlist([])
+ let res = split(execute(a:cchar . 'hist'), "\n")
+ call assert_equal('> error list 1 of 1; 0 ' . common, res[0])
+
+ call g:Xsetlist([], 'f')
endfunc
func Test_history()
@@ -2166,6 +2172,9 @@ func Xproperty_tests(cchar)
call assert_equal(['Colors'], newl2.context)
call assert_equal('Line10', newl2.items[0].text)
call g:Xsetlist([], 'f')
+
+ " Cannot specify both a non-empty list argument and a dict argument
+ call assert_fails("call g:Xsetlist([{}], ' ', {})", 'E475:')
endfunc
func Test_qf_property()
@@ -2173,6 +2182,56 @@ func Test_qf_property()
call Xproperty_tests('l')
endfunc
+" Test for setting the current index in the location/quickfix list
+func Xtest_setqfidx(cchar)
+ call s:setup_commands(a:cchar)
+
+ Xgetexpr "F1:10:1:Line1\nF2:20:2:Line2\nF3:30:3:Line3"
+ Xgetexpr "F4:10:1:Line1\nF5:20:2:Line2\nF6:30:3:Line3"
+ Xgetexpr "F7:10:1:Line1\nF8:20:2:Line2\nF9:30:3:Line3"
+
+ call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 2})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'idx' : 2})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 3})
+ Xolder 2
+ Xopen
+ call assert_equal(3, line('.'))
+ Xnewer
+ call assert_equal(2, line('.'))
+ Xnewer
+ call assert_equal(2, line('.'))
+ " Update the current index with the quickfix window open
+ wincmd w
+ call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 3})
+ Xopen
+ call assert_equal(3, line('.'))
+ Xclose
+
+ " Set the current index to the last entry
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : '$'})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ " A large value should set the index to the last index
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 1})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 999})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ " Invalid index values
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : -1})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 0})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 'xx'})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call assert_fails("call g:Xsetlist([], 'a', {'nr':1, 'idx':[]})", 'E745:')
+
+ call g:Xsetlist([], 'f')
+ new | only
+endfunc
+
+func Test_setqfidx()
+ call Xtest_setqfidx('c')
+ call Xtest_setqfidx('l')
+endfunc
+
" Tests for the QuickFixCmdPre/QuickFixCmdPost autocommands
func QfAutoCmdHandler(loc, cmd)
call add(g:acmds, a:loc . a:cmd)
@@ -2508,6 +2567,41 @@ func Test_vimgrep_incsearch()
set noincsearch
endfunc
+" Test vimgrep without swap file
+func Test_vimgrep_without_swap_file()
+ let lines =<< trim [SCRIPT]
+ vimgrep grep test_c*
+ call writefile(['done'], 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -n -S Xscript Xscript')
+ call assert_equal(['done'], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+func Test_vimgrep_existing_swapfile()
+ call writefile(['match apple with apple'], 'Xapple')
+ call writefile(['swapfile'], '.Xapple.swp')
+ let g:foundSwap = 0
+ let g:ignoreSwapExists = 1
+ augroup grep
+ au SwapExists * let foundSwap = 1 | let v:swapchoice = 'e'
+ augroup END
+ vimgrep apple Xapple
+ call assert_equal(1, g:foundSwap)
+ call assert_match('.Xapple.swo', swapname(''))
+
+ call delete('Xapple')
+ call delete('Xapple.swp')
+ augroup grep
+ au! SwapExists
+ augroup END
+ unlet g:ignoreSwapExists
+endfunc
+
func XfreeTests(cchar)
call s:setup_commands(a:cchar)
@@ -3869,6 +3963,52 @@ func Test_curswant()
cclose | helpclose
endfunc
+" Test for opening a file from the quickfix window using CTRL-W <Enter>
+" doesn't leave an empty buffer around.
+func Test_splitview()
+ call s:create_test_file('Xtestfile1')
+ call s:create_test_file('Xtestfile2')
+ new | only
+ let last_bufnr = bufnr('Test_sv_1', 1)
+ let l = ['Xtestfile1:2:Line2', 'Xtestfile2:4:Line4']
+ cgetexpr l
+ copen
+ let numbufs = len(getbufinfo())
+ exe "normal \<C-W>\<CR>"
+ copen
+ exe "normal j\<C-W>\<CR>"
+ " Make sure new empty buffers are not created
+ call assert_equal(numbufs, len(getbufinfo()))
+ " Creating a new buffer should use the next available buffer number
+ call assert_equal(last_bufnr + 4, bufnr("Test_sv_2", 1))
+ bwipe Test_sv_1
+ bwipe Test_sv_2
+ new | only
+
+ " When split opening files from location list window, make sure that two
+ " windows doesn't refer to the same location list
+ lgetexpr l
+ let locid = getloclist(0, {'id' : 0}).id
+ lopen
+ exe "normal \<C-W>\<CR>"
+ call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
+ call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
+ new | only
+
+ " When split opening files from a helpgrep location list window, a new help
+ " window should be opend with a copy of the location list.
+ lhelpgrep window
+ let locid = getloclist(0, {'id' : 0}).id
+ lwindow
+ exe "normal j\<C-W>\<CR>"
+ call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
+ call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
+ new | only
+
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+endfunc
+
" Test for parsing entries using visual screen column
func Test_viscol()
enew
@@ -3920,11 +4060,102 @@ func Test_viscol()
cnext
call assert_equal([16, 25], [col('.'), virtcol('.')])
+ " Use screen column number with a multi-line error message
+ enew
+ call writefile(["à test"], 'Xfile1')
+ set efm=%E===\ %f\ ===,%C%l:%v,%Z%m
+ cexpr ["=== Xfile1 ===", "1:3", "errormsg"]
+ call assert_equal('Xfile1', @%)
+ call assert_equal([0, 1, 4, 0], getpos('.'))
+
+ " Repeat previous test with byte offset %c: ensure that fix to issue #7145
+ " does not break this
+ set efm=%E===\ %f\ ===,%C%l:%c,%Z%m
+ cexpr ["=== Xfile1 ===", "1:3", "errormsg"]
+ call assert_equal('Xfile1', @%)
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
enew | only
set efm&
call delete('Xfile1')
endfunc
+" Test for the quickfix window buffer
+func Xqfbuf_test(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Quickfix buffer should be reused across closing and opening a quickfix
+ " window
+ Xexpr "F1:10:Line10"
+ Xopen
+ let qfbnum = bufnr('')
+ Xclose
+ " Even after the quickfix window is closed, the buffer should be loaded
+ call assert_true(bufloaded(qfbnum))
+ Xopen
+ " Buffer should be reused when opening the window again
+ call assert_equal(qfbnum, bufnr(''))
+ Xclose
+
+ if a:cchar == 'l'
+ %bwipe
+ " For a location list, when both the file window and the location list
+ " window for the list are closed, then the buffer should be freed.
+ new | only
+ lexpr "F1:10:Line10"
+ let wid = win_getid()
+ lopen
+ let qfbnum = bufnr('')
+ call assert_match(qfbnum . ' %a- "\[Location List]"', execute('ls'))
+ close
+ " When the location list window is closed, the buffer name should not
+ " change to 'Quickfix List'
+ call assert_match(qfbnum . ' h- "\[Location List]"', execute('ls'))
+ call assert_true(bufloaded(qfbnum))
+
+ " After deleting a location list buffer using ":bdelete", opening the
+ " location list window should mark the buffer as a location list buffer.
+ exe "bdelete " . qfbnum
+ lopen
+ call assert_equal("quickfix", &buftype)
+ call assert_equal(1, getwininfo(win_getid(winnr()))[0].loclist)
+ call assert_equal(wid, getloclist(0, {'filewinid' : 0}).filewinid)
+ call assert_false(&swapfile)
+ lclose
+
+ " When the location list is cleared for the window, the buffer should be
+ " removed
+ call setloclist(0, [], 'f')
+ call assert_false(bufexists(qfbnum))
+
+ " When the location list is freed with the location list window open, the
+ " location list buffer should not be lost. It should be reused when the
+ " location list is again populated.
+ lexpr "F1:10:Line10"
+ lopen
+ let wid = win_getid()
+ let qfbnum = bufnr('')
+ wincmd p
+ call setloclist(0, [], 'f')
+ lexpr "F1:10:Line10"
+ lopen
+ call assert_equal(wid, win_getid())
+ call assert_equal(qfbnum, bufnr(''))
+ lclose
+
+ " When the window with the location list is closed, the buffer should be
+ " removed
+ new | only
+ call assert_false(bufexists(qfbnum))
+ endif
+endfunc
+
+func Test_qfbuf()
+ throw 'skipped: enable after porting patch 8.1.0877'
+ call Xqfbuf_test('c')
+ call Xqfbuf_test('l')
+endfunc
+
" Test to make sure that an empty quickfix buffer is not reused for loading
" a normal buffer.
func Test_empty_qfbuf()
diff --git a/src/nvim/testdir/test_ruby.vim b/src/nvim/testdir/test_ruby.vim
index 64199570a9..07ad8561c3 100644
--- a/src/nvim/testdir/test_ruby.vim
+++ b/src/nvim/testdir/test_ruby.vim
@@ -11,37 +11,6 @@ func Test_ruby_change_buffer()
call assert_equal('1 changed line 1', getline('$'))
endfunc
-func Test_ruby_evaluate_list()
- throw 'skipped: TODO: '
- call setline(line('$'), ['2 line 2'])
- ruby Vim.command("normal /^2\n")
- let l = ["abc", "def"]
- ruby << EOF
- curline = $curbuf.line_number
- l = Vim.evaluate("l");
- $curbuf.append(curline, l.join("\n"))
-EOF
- normal j
- .rubydo $_ = $_.gsub(/\n/, '/')
- call assert_equal('abc/def', getline('$'))
-endfunc
-
-func Test_ruby_evaluate_dict()
- let d = {'a': 'foo', 'b': 123}
- redir => l:out
- ruby d = Vim.evaluate("d"); print d
- redir END
- call assert_equal(['{"a"=>"foo", "b"=>123}'], split(l:out, "\n"))
-endfunc
-
-func Test_ruby_evaluate_special_var()
- let l = [v:true, v:false, v:null]
- redir => l:out
- ruby d = Vim.evaluate("l"); print d
- redir END
- call assert_equal(['[true, false, nil]'], split(l:out, "\n"))
-endfunc
-
func Test_rubydo()
throw 'skipped: TODO: '
" Check deleting lines does not trigger ml_get error.
@@ -56,8 +25,7 @@ func Test_rubydo()
call setline(1, ['one', 'two', 'three'])
rubydo Vim.command("new")
call assert_equal(wincount + 1, winnr('$'))
- bwipe!
- bwipe!
+ %bwipe!
endfunc
func Test_rubyfile()
@@ -75,8 +43,350 @@ func Test_set_cursor()
normal gg
rubydo $curwin.cursor = [1, 5]
call assert_equal([1, 6], [line('.'), col('.')])
+ call assert_equal([1, 5], rubyeval('$curwin.cursor'))
" Check that movement after setting cursor position keeps current column.
normal j
call assert_equal([2, 6], [line('.'), col('.')])
+ call assert_equal([2, 5], rubyeval('$curwin.cursor'))
+
+ " call assert_fails('ruby $curwin.cursor = [1]',
+ " \ 'ArgumentError: array length must be 2')
+ bwipe!
+endfunc
+
+" Test buffer.count and buffer.length (number of lines in buffer)
+func Test_buffer_count()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ call assert_equal(3, rubyeval('$curbuf.count'))
+ call assert_equal(3, rubyeval('$curbuf.length'))
+ bwipe!
+endfunc
+
+" Test buffer.name (buffer name)
+func Test_buffer_name()
+ new Xfoo
+ call assert_equal(expand('%:p'), rubyeval('$curbuf.name'))
+ bwipe
+ call assert_equal('', rubyeval('$curbuf.name'))
+endfunc
+
+" Test buffer.number (number of the buffer).
+func Test_buffer_number()
+ new
+ call assert_equal(bufnr('%'), rubyeval('$curbuf.number'))
+ new
+ call assert_equal(bufnr('%'), rubyeval('$curbuf.number'))
+
+ %bwipe
+endfunc
+
+" Test buffer.delete({n}) (delete line {n})
+func Test_buffer_delete()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ ruby $curbuf.delete(2)
+ call assert_equal(['one', 'three'], getline(1, '$'))
+
+ " call assert_fails('ruby $curbuf.delete(0)', 'IndexError: line number 0 out of range')
+ " call assert_fails('ruby $curbuf.delete(3)', 'IndexError: line number 3 out of range')
+ call assert_fails('ruby $curbuf.delete(3)', 'RuntimeError: Index out of bounds')
+
+ bwipe!
+endfunc
+
+" Test buffer.append({str}, str) (append line {str} after line {n})
+func Test_buffer_append()
+ new
+ ruby $curbuf.append(0, 'one')
+ ruby $curbuf.append(1, 'three')
+ ruby $curbuf.append(1, 'two')
+ ruby $curbuf.append(4, 'four')
+
+ call assert_equal(['one', 'two', 'three', '', 'four'], getline(1, '$'))
+
+ " call assert_fails('ruby $curbuf.append(-1, "x")',
+ " \ 'IndexError: line number -1 out of range')
+ call assert_fails('ruby $curbuf.append(-1, "x")',
+ \ 'ArgumentError: Index out of bounds')
+ call assert_fails('ruby $curbuf.append(6, "x")',
+ \ 'RuntimeError: Index out of bounds')
+
+ bwipe!
+endfunc
+
+" Test buffer.line (get or set the current line)
+func Test_buffer_line()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ call assert_equal('two', rubyeval('$curbuf.line'))
+
+ ruby $curbuf.line = 'TWO'
+ call assert_equal(['one', 'TWO', 'three'], getline(1, '$'))
+
+ bwipe!
+endfunc
+
+" Test buffer.line_number (get current line number)
+func Test_buffer_line_number()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ call assert_equal(2, rubyeval('$curbuf.line_number'))
+
+ bwipe!
+endfunc
+
+func Test_buffer_get()
+ new
+ call setline(1, ['one', 'two'])
+ call assert_equal('one', rubyeval('$curbuf[1]'))
+ call assert_equal('two', rubyeval('$curbuf[2]'))
+
+ " call assert_fails('ruby $curbuf[0]',
+ " \ 'IndexError: line number 0 out of range')
+ call assert_fails('ruby $curbuf[3]',
+ \ 'RuntimeError: Index out of bounds')
+
+ bwipe!
+endfunc
+
+func Test_buffer_set()
+ new
+ call setline(1, ['one', 'two'])
+ ruby $curbuf[2] = 'TWO'
+ ruby $curbuf[1] = 'ONE'
+
+ " call assert_fails('ruby $curbuf[0] = "ZERO"',
+ " \ 'IndexError: line number 0 out of range')
+ " call assert_fails('ruby $curbuf[3] = "THREE"',
+ " \ 'IndexError: line number 3 out of range')
+ call assert_fails('ruby $curbuf[3] = "THREE"',
+ \ 'RuntimeError: Index out of bounds')
+ bwipe!
+endfunc
+
+" Test window.width (get or set window height).
+func Test_window_height()
+ new
+
+ " Test setting window height
+ ruby $curwin.height = 2
+ call assert_equal(2, winheight(0))
+
+ " Test getting window height
+ call assert_equal(2, rubyeval('$curwin.height'))
+
+ bwipe
+endfunc
+
+" Test window.width (get or set window width).
+func Test_window_width()
+ vnew
+
+ " Test setting window width
+ ruby $curwin.width = 2
+ call assert_equal(2, winwidth(0))
+
+ " Test getting window width
+ call assert_equal(2, rubyeval('$curwin.width'))
+
+ bwipe
+endfunc
+
+" Test window.buffer (get buffer object of a window object).
+func Test_window_buffer()
+ new Xfoo1
+ new Xfoo2
+ ruby $b2 = $curwin.buffer
+ ruby $w2 = $curwin
+ wincmd j
+ ruby $b1 = $curwin.buffer
+ ruby $w1 = $curwin
+
+ " call assert_equal(rubyeval('$b1'), rubyeval('$w1.buffer'))
+ " call assert_equal(rubyeval('$b2'), rubyeval('$w2.buffer'))
+ call assert_equal(bufnr('Xfoo1'), rubyeval('$w1.buffer.number'))
+ call assert_equal(bufnr('Xfoo2'), rubyeval('$w2.buffer.number'))
+
+ ruby $b1, $w1, $b2, $w2 = nil
+ %bwipe
+endfunc
+
+" Test Vim::Window.current (get current window object)
+func Test_Vim_window_current()
+ let cw = rubyeval('$curwin.to_s')
+ " call assert_equal(cw, rubyeval('Vim::Window.current'))
+ call assert_match('^#<Neovim::Window:0x\x\+>$', cw)
+endfunc
+
+" Test Vim::Window.count (number of windows)
+func Test_Vim_window_count()
+ new Xfoo1
+ new Xfoo2
+ split
+ call assert_equal(4, rubyeval('Vim::Window.count'))
+ %bwipe
+ call assert_equal(1, rubyeval('Vim::Window.count'))
+endfunc
+
+" Test Vim::Window[n] (get window object of window n)
+func Test_Vim_window_get()
+ new Xfoo1
+ new Xfoo2
+ call assert_match('Xfoo2$', rubyeval('Vim::Window[0].buffer.name'))
+ wincmd j
+ call assert_match('Xfoo1$', rubyeval('Vim::Window[1].buffer.name'))
+ wincmd j
+ call assert_equal('', rubyeval('Vim::Window[2].buffer.name'))
+ %bwipe
+endfunc
+
+" Test Vim::Buffer.current (return the buffer object of current buffer)
+func Test_Vim_buffer_current()
+ let cb = rubyeval('$curbuf.to_s')
+ " call assert_equal(cb, rubyeval('Vim::Buffer.current'))
+ call assert_match('^#<Neovim::Buffer:0x\x\+>$', cb)
+endfunc
+
+" Test Vim::Buffer:.count (return the number of buffers)
+func Test_Vim_buffer_count()
+ new Xfoo1
+ new Xfoo2
+ call assert_equal(3, rubyeval('Vim::Buffer.count'))
+ %bwipe
+ call assert_equal(1, rubyeval('Vim::Buffer.count'))
+endfunc
+
+" Test Vim::buffer[n] (return the buffer object of buffer number n)
+func Test_Vim_buffer_get()
+ new Xfoo1
+ new Xfoo2
+
+ " Index of Vim::Buffer[n] goes from 0 to the number of buffers.
+ call assert_equal('', rubyeval('Vim::Buffer[0].name'))
+ call assert_match('Xfoo1$', rubyeval('Vim::Buffer[1].name'))
+ call assert_match('Xfoo2$', rubyeval('Vim::Buffer[2].name'))
+ call assert_fails('ruby print Vim::Buffer[3].name',
+ \ "NoMethodError: undefined method `name' for nil:NilClass")
+ %bwipe
+endfunc
+
+" Test Vim::command({cmd}) (execute a Ex command))
+" Test Vim::command({cmd})
+func Test_Vim_command()
+ new
+ call setline(1, ['one', 'two', 'three', 'four'])
+ ruby Vim::command('2,3d')
+ call assert_equal(['one', 'four'], getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test Vim::set_option (set a vim option)
+func Test_Vim_set_option()
+ call assert_equal(0, &number)
+ ruby Vim::set_option('number')
+ call assert_equal(1, &number)
+ ruby Vim::set_option('nonumber')
+ call assert_equal(0, &number)
+endfunc
+
+func Test_Vim_evaluate()
+ call assert_equal(123, rubyeval('Vim::evaluate("123")'))
+ " Vim::evaluate("123").class gives Integer or Fixnum depending
+ " on versions of Ruby.
+ call assert_match('^Integer\|Fixnum$', rubyeval('Vim::evaluate("123").class'))
+
+ call assert_equal(1.23, rubyeval('Vim::evaluate("1.23")'))
+ call assert_equal('Float', rubyeval('Vim::evaluate("1.23").class'))
+
+ call assert_equal('foo', rubyeval('Vim::evaluate("\"foo\"")'))
+ call assert_equal('String', rubyeval('Vim::evaluate("\"foo\"").class'))
+
+ call assert_equal([1, 2], rubyeval('Vim::evaluate("[1, 2]")'))
+ call assert_equal('Array', rubyeval('Vim::evaluate("[1, 2]").class'))
+
+ call assert_equal({'1': 2}, rubyeval('Vim::evaluate("{1:2}")'))
+ call assert_equal('Hash', rubyeval('Vim::evaluate("{1:2}").class'))
+
+ call assert_equal(v:null, rubyeval('Vim::evaluate("v:null")'))
+ call assert_equal('NilClass', rubyeval('Vim::evaluate("v:null").class'))
+
+ " call assert_equal(v:null, rubyeval('Vim::evaluate("v:none")'))
+ " call assert_equal('NilClass', rubyeval('Vim::evaluate("v:none").class'))
+
+ call assert_equal(v:true, rubyeval('Vim::evaluate("v:true")'))
+ call assert_equal('TrueClass', rubyeval('Vim::evaluate("v:true").class'))
+ call assert_equal(v:false, rubyeval('Vim::evaluate("v:false")'))
+ call assert_equal('FalseClass',rubyeval('Vim::evaluate("v:false").class'))
+endfunc
+
+func Test_Vim_evaluate_list()
+ call setline(line('$'), ['2 line 2'])
+ ruby Vim.command("normal /^2\n")
+ let l = ["abc", "def"]
+ ruby << EOF
+ curline = $curbuf.line_number
+ l = Vim.evaluate("l");
+ $curbuf.append(curline, l.join("|"))
+EOF
+ normal j
+ .rubydo $_ = $_.gsub(/\|/, '/')
+ call assert_equal('abc/def', getline('$'))
+endfunc
+
+func Test_Vim_evaluate_dict()
+ let d = {'a': 'foo', 'b': 123}
+ redir => l:out
+ ruby d = Vim.evaluate("d"); print d
+ redir END
+ call assert_equal(['{"a"=>"foo", "b"=>123}'], split(l:out, "\n"))
+endfunc
+
+" Test Vim::message({msg}) (display message {msg})
+func Test_Vim_message()
+ throw 'skipped: TODO: '
+ ruby Vim::message('A message')
+ let messages = split(execute('message'), "\n")
+ call assert_equal('A message', messages[-1])
+endfunc
+
+func Test_print()
+ func RubyPrint(expr)
+ return trim(execute('ruby print ' . a:expr))
+ endfunc
+
+ call assert_equal('123', RubyPrint('123'))
+ call assert_equal('1.23', RubyPrint('1.23'))
+ call assert_equal('Hello World!', RubyPrint('"Hello World!"'))
+ call assert_equal('[1, 2]', RubyPrint('[1, 2]'))
+ call assert_equal('{"k1"=>"v1", "k2"=>"v2"}', RubyPrint('({"k1" => "v1", "k2" => "v2"})'))
+ call assert_equal('true', RubyPrint('true'))
+ call assert_equal('false', RubyPrint('false'))
+ call assert_equal('', RubyPrint('nil'))
+ call assert_match('Vim', RubyPrint('Vim'))
+ call assert_match('Module', RubyPrint('Vim.class'))
+
+ delfunc RubyPrint
+endfunc
+
+func Test_p()
+ ruby p 'Just a test'
+ let messages = split(execute('message'), "\n")
+ call assert_equal('"Just a test"', messages[-1])
+
+ " Check return values of p method
+
+ call assert_equal(123, rubyeval('p(123)'))
+ call assert_equal([1, 2, 3], rubyeval('p(1, 2, 3)'))
+
+ " Avoid the "message maintainer" line.
+ let $LANG = ''
+ messages clear
+ call assert_equal(v:true, rubyeval('p() == nil'))
+
+ let messages = split(execute('message'), "\n")
+ call assert_equal(0, len(messages))
endfunc
diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim
index e072e9ed7f..f27920d20f 100644
--- a/src/nvim/testdir/test_swap.vim
+++ b/src/nvim/testdir/test_swap.vim
@@ -1,5 +1,7 @@
" Tests for the swap feature
+source check.vim
+
func s:swapname()
return trim(execute('swapname'))
endfunc
@@ -305,3 +307,61 @@ func Test_swap_recover_ext()
augroup END
augroup! test_swap_recover_ext
endfunc
+
+" Test for selecting 'q' in the attention prompt
+func Test_swap_prompt_splitwin()
+ CheckRunVimInTerminal
+
+ call writefile(['foo bar'], 'Xfile1')
+ edit Xfile1
+ preserve " should help to make sure the swap file exists
+
+ let buf = RunVimInTerminal('', {'rows': 20})
+ call term_sendkeys(buf, ":set nomore\n")
+ call term_sendkeys(buf, ":set noruler\n")
+ call term_sendkeys(buf, ":split Xfile1\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: $', term_getline(buf, 20))})
+ call term_sendkeys(buf, "q")
+ call term_wait(buf)
+ call term_sendkeys(buf, ":\<CR>")
+ call WaitForAssert({-> assert_match('^:$', term_getline(buf, 20))})
+ call term_sendkeys(buf, ":echomsg winnr('$')\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))})
+ call StopVimInTerminal(buf)
+ %bwipe!
+ call delete('Xfile1')
+endfunc
+
+func Test_swap_symlink()
+ if !has("unix")
+ return
+ endif
+
+ call writefile(['text'], 'Xtestfile')
+ silent !ln -s -f Xtestfile Xtestlink
+
+ set dir=.
+
+ " Test that swap file uses the name of the file when editing through a
+ " symbolic link (so that editing the file twice is detected)
+ edit Xtestlink
+ call assert_match('Xtestfile\.swp$', s:swapname())
+ bwipe!
+
+ call mkdir('Xswapdir')
+ exe 'set dir=' . getcwd() . '/Xswapdir//'
+
+ " Check that this also works when 'directory' ends with '//'
+ edit Xtestlink
+ call assert_match('Xtestfile\.swp$', s:swapname())
+ bwipe!
+
+ set dir&
+ call delete('Xtestfile')
+ call delete('Xtestlink')
+ call delete('Xswapdir', 'rf')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 2404f113d9..2617aa3945 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -475,6 +475,40 @@ func Test_bg_detection()
hi Normal ctermbg=NONE
endfunc
+func Test_syntax_hangs()
+ if !has('reltime') || !has('float') || !has('syntax')
+ return
+ endif
+
+ " This pattern takes a long time to match, it should timeout.
+ new
+ call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
+ let start = reltime()
+ set nolazyredraw redrawtime=101
+ syn match Error /\%#=1a*.*X\@<=b*/
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+
+ " second time syntax HL is disabled
+ let start = reltime()
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed < 0.1)
+
+ " after CTRL-L the timeout flag is reset
+ let start = reltime()
+ exe "normal \<C-L>"
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+
+ set redrawtime&
+ bwipe!
+endfunc
+
func Test_synstack_synIDtrans()
new
setfiletype c
@@ -550,38 +584,42 @@ func Test_syn_wrong_z_one()
bwipe!
endfunc
-func Test_syntax_hangs()
- if !has('reltime') || !has('float') || !has('syntax')
- return
- endif
+func Test_syntax_after_bufdo()
+ call writefile(['/* aaa comment */'], 'Xaaa.c')
+ call writefile(['/* bbb comment */'], 'Xbbb.c')
+ call writefile(['/* ccc comment */'], 'Xccc.c')
+ call writefile(['/* ddd comment */'], 'Xddd.c')
+
+ let bnr = bufnr('%')
+ new Xaaa.c
+ badd Xbbb.c
+ badd Xccc.c
+ badd Xddd.c
+ exe "bwipe " . bnr
+ let l = []
+ bufdo call add(l, bufnr('%'))
+ call assert_equal(4, len(l))
- " This pattern takes a long time to match, it should timeout.
- new
- call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
- let start = reltime()
- set nolazyredraw redrawtime=101
- syn match Error /\%#=1a*.*X\@<=b*/
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed > 0.1)
- call assert_true(elapsed < 1.0)
-
- " second time syntax HL is disabled
- let start = reltime()
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed < 0.1)
-
- " after CTRL-L the timeout flag is reset
- let start = reltime()
- exe "normal \<C-L>"
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed > 0.1)
- call assert_true(elapsed < 1.0)
+ syntax on
- set redrawtime&
- bwipe!
+ " This used to only enable syntax HL in the last buffer.
+ bufdo tab split
+ tabrewind
+ for tab in range(1, 4)
+ norm fm
+ call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
+ tabnext
+ endfor
+
+ bwipe! Xaaa.c
+ bwipe! Xbbb.c
+ bwipe! Xccc.c
+ bwipe! Xddd.c
+ syntax off
+ call delete('Xaaa.c')
+ call delete('Xbbb.c')
+ call delete('Xccc.c')
+ call delete('Xddd.c')
endfunc
func Test_syntax_foldlevel()
diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim
index 7863317eb0..f70cc1f70a 100644
--- a/src/nvim/testdir/test_textobjects.vim
+++ b/src/nvim/testdir/test_textobjects.vim
@@ -152,6 +152,36 @@ func Test_string_html_objects()
normal! dit
call assert_equal('-<b></b>', getline('.'))
+ " copy the tag block from leading indentation before the start tag
+ let t = " <b>\ntext\n</b>"
+ $put =t
+ normal! 2kvaty
+ call assert_equal("<b>\ntext\n</b>", @")
+
+ " copy the tag block from the end tag
+ let t = "<title>\nwelcome\n</title>"
+ $put =t
+ normal! $vaty
+ call assert_equal("<title>\nwelcome\n</title>", @")
+
+ " copy the outer tag block from a tag without an end tag
+ let t = "<html>\n<title>welcome\n</html>"
+ $put =t
+ normal! k$vaty
+ call assert_equal("<html>\n<title>welcome\n</html>", @")
+
+ " nested tag that has < in a different line from >
+ let t = "<div><div\n></div></div>"
+ $put =t
+ normal! k0vaty
+ call assert_equal("<div><div\n></div></div>", @")
+
+ " nested tag with attribute that has < in a different line from >
+ let t = "<div><div\nattr=\"attr\"\n></div></div>"
+ $put =t
+ normal! 2k0vaty
+ call assert_equal("<div><div\nattr=\"attr\"\n></div></div>", @")
+
set quoteescape&
enew!
endfunc
diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim
index fdd3a9abeb..0a89066a2b 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -276,7 +276,7 @@ func Test_CmdCompletion()
call assert_equal('"com -nargs=* + 0 1 ?', @:)
call feedkeys(":com -addr=\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"com -addr=arguments buffers lines loaded_buffers quickfix tabs windows', @:)
+ call assert_equal('"com -addr=arguments buffers lines loaded_buffers other quickfix tabs windows', @:)
call feedkeys(":com -complete=co\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com -complete=color command compiler', @:)
@@ -340,3 +340,202 @@ func Test_use_execute_in_completion()
call assert_equal('"DoExec hi', @:)
delcommand DoExec
endfunc
+
+func Test_addr_all()
+ throw 'skipped: requires patch v8.1.0341 to pass'
+ command! -addr=lines DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(line('$'), g:a2)
+
+ command! -addr=arguments DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ args one two three
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(3, g:a2)
+
+ command! -addr=buffers DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ for low in range(1, bufnr('$'))
+ if buflisted(low)
+ break
+ endif
+ endfor
+ call assert_equal(low, g:a1)
+ call assert_equal(bufnr('$'), g:a2)
+
+ command! -addr=loaded_buffers DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ for low in range(1, bufnr('$'))
+ if bufloaded(low)
+ break
+ endif
+ endfor
+ call assert_equal(low, g:a1)
+ for up in range(bufnr('$'), 1, -1)
+ if bufloaded(up)
+ break
+ endif
+ endfor
+ call assert_equal(up, g:a2)
+
+ command! -addr=windows DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ new
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(winnr('$'), g:a2)
+ bwipe
+
+ command! -addr=tabs DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ tabnew
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(len(gettabinfo()), g:a2)
+ bwipe
+
+ command! -addr=other DoSomething echo 'nothing'
+ DoSomething
+ call assert_fails('%DoSomething')
+
+ delcommand DoSomething
+endfunc
+
+func Test_command_list()
+ command! DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 :",
+ \ execute('command DoCmd'))
+
+ " Test with various -range= and -count= argument values.
+ command! -range DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . :",
+ \ execute('command DoCmd'))
+ command! -range=% DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 % :",
+ \ execute('command! DoCmd'))
+ command! -range=2 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 2 :",
+ \ execute('command DoCmd'))
+ command! -count=2 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 2c :",
+ \ execute('command DoCmd'))
+
+ " Test with various -addr= argument values.
+ command! -addr=lines DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . :",
+ \ execute('command DoCmd'))
+ command! -addr=arguments DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . arg :",
+ \ execute('command DoCmd'))
+ command! -addr=buffers DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . buf :",
+ \ execute('command DoCmd'))
+ command! -addr=loaded_buffers DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . load :",
+ \ execute('command DoCmd'))
+ command! -addr=windows DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . win :",
+ \ execute('command DoCmd'))
+ command! -addr=tabs DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . tab :",
+ \ execute('command DoCmd'))
+ command! -addr=other DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 . ? :",
+ \ execute('command DoCmd'))
+
+ " Test with various -complete= argument values (non-exhaustive list)
+ command! -complete=arglist DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 arglist :",
+ \ execute('command DoCmd'))
+ command! -complete=augroup DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 augroup :",
+ \ execute('command DoCmd'))
+ command! -complete=custom,CustomComplete DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 custom :",
+ \ execute('command DoCmd'))
+ command! -complete=customlist,CustomComplete DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 customlist :",
+ \ execute('command DoCmd'))
+
+ " Test with various -narg= argument values.
+ command! -nargs=0 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 :",
+ \ execute('command DoCmd'))
+ command! -nargs=1 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 1 :",
+ \ execute('command DoCmd'))
+ command! -nargs=* DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd * :",
+ \ execute('command DoCmd'))
+ command! -nargs=? DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd ? :",
+ \ execute('command DoCmd'))
+ command! -nargs=+ DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd + :",
+ \ execute('command DoCmd'))
+
+ " Test with other arguments.
+ command! -bang DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n! DoCmd 0 :",
+ \ execute('command DoCmd'))
+ command! -bar DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n| DoCmd 0 :",
+ \ execute('command DoCmd'))
+ command! -register DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n\" DoCmd 0 :",
+ \ execute('command DoCmd'))
+ command! -buffer DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\nb DoCmd 0 :"
+ \ .. "\n\" DoCmd 0 :",
+ \ execute('command DoCmd'))
+ comclear
+
+ " Test with many args.
+ command! -bang -bar -register -buffer -nargs=+ -complete=environment -addr=windows -count=3 DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n!\"b|DoCmd + 3c win environment :",
+ \ execute('command DoCmd'))
+ comclear
+
+ " Test with special characters in command definition.
+ command! DoCmd :<cr><tab><c-d>
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd 0 :<CR><Tab><C-D>",
+ \ execute('command DoCmd'))
+
+ " Test output in verbose mode.
+ command! DoCmd :
+ call assert_match("^\n"
+ \ .. " Name Args Address Complete Definition\n"
+ \ .. " DoCmd 0 :\n"
+ \ .. "\tLast set from .*/test_usercommands.vim line \\d\\+$",
+ \ execute('verbose command DoCmd'))
+
+ comclear
+ call assert_equal("\nNo user-defined commands found", execute(':command Xxx'))
+ call assert_equal("\nNo user-defined commands found", execute('command'))
+endfunc
diff --git a/src/nvim/testdir/test_version.vim b/src/nvim/testdir/test_version.vim
new file mode 100644
index 0000000000..46cf34979f
--- /dev/null
+++ b/src/nvim/testdir/test_version.vim
@@ -0,0 +1,12 @@
+" Test :version Ex command
+
+func Test_version()
+ " version should always return the same string.
+ let v1 = execute('version')
+ let v2 = execute('version')
+ call assert_equal(v1, v2)
+
+ call assert_match("^\n\nNVIM v[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+.*", v1)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 9f47ee2904..500e3ff088 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -879,6 +879,10 @@ func Test_window_resize()
exe other_winnr .. 'resize 10'
call assert_equal(10, winheight(other_winnr))
call assert_equal(&lines - 10 - 3, winheight(0))
+ exe other_winnr .. 'resize +1'
+ exe other_winnr .. 'resize +1'
+ call assert_equal(12, winheight(other_winnr))
+ call assert_equal(&lines - 10 - 3 -2, winheight(0))
%bwipe!
endfunc
diff --git a/src/nvim/window.c b/src/nvim/window.c
index e53570edd8..4931221e7a 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -2578,9 +2578,10 @@ int win_close(win_T *win, bool free_buf)
return OK;
}
- /* Free independent synblock before the buffer is freed. */
- if (win->w_buffer != NULL)
+ // Free independent synblock before the buffer is freed.
+ if (win->w_buffer != NULL) {
reset_synblock(win);
+ }
/*
* Close the link to the buffer.
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index da7515f012..8ed642b43e 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -534,6 +534,26 @@ describe('api/buf', function()
end)
end)
+ describe('nvim_buf_delete', function()
+ it('allows for just deleting', function()
+ nvim('command', 'new')
+ local b = nvim('get_current_buf')
+ ok(buffer('is_valid', b))
+ nvim('buf_delete', b, {})
+ ok(not buffer('is_loaded', b))
+ ok(not buffer('is_valid', b))
+ end)
+
+ it('allows for just unloading', function()
+ nvim('command', 'new')
+ local b = nvim('get_current_buf')
+ ok(buffer('is_valid', b))
+ nvim('buf_delete', b, { unload = true })
+ ok(not buffer('is_loaded', b))
+ ok(buffer('is_valid', b))
+ end)
+ end)
+
describe('nvim_buf_get_mark', function()
it('works', function()
curbuf('set_lines', -1, -1, true, {'a', 'bit of', 'text'})
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 72e810e3e4..0b52d06df9 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -449,19 +449,19 @@ describe('API', function()
end)
it('reports errors', function()
- eq([[Error loading lua: [string "<nvim>"]:1: '=' expected near '+']],
+ eq([[Error loading lua: [string "<nvim>"]:0: '=' expected near '+']],
pcall_err(meths.exec_lua, 'a+*b', {}))
- eq([[Error loading lua: [string "<nvim>"]:1: unexpected symbol near '1']],
+ eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol near '1']],
pcall_err(meths.exec_lua, '1+2', {}))
- eq([[Error loading lua: [string "<nvim>"]:1: unexpected symbol]],
+ eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol]],
pcall_err(meths.exec_lua, 'aa=bb\0', {}))
- eq([[Error executing lua: [string "<nvim>"]:1: attempt to call global 'bork' (a nil value)]],
+ eq([[Error executing lua: [string "<nvim>"]:0: attempt to call global 'bork' (a nil value)]],
pcall_err(meths.exec_lua, 'bork()', {}))
- eq('Error executing lua: [string "<nvim>"]:1: did\nthe\nfail',
+ eq('Error executing lua: [string "<nvim>"]:0: did\nthe\nfail',
pcall_err(meths.exec_lua, 'error("did\\nthe\\nfail")', {}))
end)
@@ -605,7 +605,7 @@ describe('API', function()
end)
it('vim.paste() failure', function()
nvim('exec_lua', 'vim.paste = (function(lines, phase) error("fake fail") end)', {})
- eq([[Error executing lua: [string "<nvim>"]:1: fake fail]],
+ eq([[Error executing lua: [string "<nvim>"]:0: fake fail]],
pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1))
end)
end)
@@ -1252,7 +1252,7 @@ describe('API', function()
{0:~ }|
{1:very fail} |
]])
- helpers.wait()
+ helpers.poke_eventloop()
-- shows up to &cmdheight lines
nvim_async('err_write', 'more fail\ntoo fail\n')
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 8c7c3208c0..7471f50dbd 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -3,7 +3,7 @@ local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
ok, feed, insert, eval = helpers.clear, helpers.nvim, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local curwinmeths = helpers.curwinmeths
local funcs = helpers.funcs
local request = helpers.request
@@ -82,7 +82,7 @@ describe('API/win', function()
insert("epilogue")
local win = curwin()
feed('gg')
- wait() -- let nvim process the 'gg' command
+ poke_eventloop() -- let nvim process the 'gg' command
-- cursor position is at beginning
eq({1, 0}, window('get_cursor', win))
@@ -128,7 +128,7 @@ describe('API/win', function()
insert("second line")
feed('gg')
- wait() -- let nvim process the 'gg' command
+ poke_eventloop() -- let nvim process the 'gg' command
-- cursor position is at beginning
local win = curwin()
@@ -139,7 +139,7 @@ describe('API/win', function()
-- move down a line
feed('j')
- wait() -- let nvim process the 'j' command
+ poke_eventloop() -- let nvim process the 'j' command
-- cursor is still in column 5
eq({2, 5}, window('get_cursor', win))
diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua
index 80c65e4544..230b7f8e01 100644
--- a/test/functional/core/exit_spec.lua
+++ b/test/functional/core/exit_spec.lua
@@ -8,7 +8,7 @@ local run = helpers.run
local funcs = helpers.funcs
local nvim_prog = helpers.nvim_prog
local redir_exec = helpers.redir_exec
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('v:exiting', function()
local cid
@@ -52,7 +52,7 @@ describe(':cquit', function()
local function test_cq(cmdline, exit_code, redir_msg)
if redir_msg then
eq('\n' .. redir_msg, redir_exec(cmdline))
- wait()
+ poke_eventloop()
eq(2, eval("1+1")) -- Still alive?
else
funcs.system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline})
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 1155f12ffc..6d1182478a 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -11,7 +11,7 @@ local os_kill = helpers.os_kill
local retry = helpers.retry
local meths = helpers.meths
local NIL = helpers.NIL
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local iswin = helpers.iswin
local get_pathsep = helpers.get_pathsep
local pathroot = helpers.pathroot
@@ -428,7 +428,7 @@ describe('jobs', function()
\ }
let job = jobstart(['cat', '-'], g:callbacks)
]])
- wait()
+ poke_eventloop()
source([[
function! g:JobHandler(job_id, data, event)
endfunction
diff --git a/test/functional/eval/interrupt_spec.lua b/test/functional/eval/interrupt_spec.lua
index 7f4ca95317..05b1f4ff57 100644
--- a/test/functional/eval/interrupt_spec.lua
+++ b/test/functional/eval/interrupt_spec.lua
@@ -4,7 +4,7 @@ local command = helpers.command
local meths = helpers.meths
local clear = helpers.clear
local sleep = helpers.sleep
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local feed = helpers.feed
local eq = helpers.eq
@@ -39,7 +39,7 @@ describe('List support code', function()
feed(':let t_rt = reltime()<CR>:let t_bl = copy(bl)<CR>')
sleep(min_dur / 16 * 1000)
feed('<C-c>')
- wait()
+ poke_eventloop()
command('let t_dur = reltimestr(reltime(t_rt))')
local t_dur = tonumber(meths.get_var('t_dur'))
if t_dur >= dur / 8 then
@@ -50,7 +50,7 @@ describe('List support code', function()
feed(':let t_rt = reltime()<CR>:let t_j = join(bl)<CR>')
sleep(min_dur / 16 * 1000)
feed('<C-c>')
- wait()
+ poke_eventloop()
command('let t_dur = reltimestr(reltime(t_rt))')
local t_dur = tonumber(meths.get_var('t_dur'))
print(('t_dur: %g'):format(t_dur))
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index 802c3f68c6..003ab64dd4 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -3,7 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command
-local feed, wait = helpers.feed, helpers.wait
+local feed, poke_eventloop = helpers.feed, helpers.poke_eventloop
local ok = helpers.ok
local eval = helpers.eval
@@ -90,7 +90,7 @@ describe(':browse oldfiles', function()
feed_command('edit testfile2')
filename2 = buf.get_name()
feed_command('wshada')
- wait()
+ poke_eventloop()
_clear()
-- Ensure nvim is out of "Press ENTER..." prompt.
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index dca7f35923..a30eb748d0 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -125,6 +125,26 @@ function tests.basic_check_capabilities()
}
end
+function tests.capabilities_for_client_supports_method()
+ skeleton {
+ on_init = function(params)
+ local expected_capabilities = protocol.make_client_capabilities()
+ assert_eq(params.capabilities, expected_capabilities)
+ return {
+ capabilities = {
+ textDocumentSync = protocol.TextDocumentSyncKind.Full;
+ completionProvider = true;
+ hoverProvider = true;
+ definitionProvider = false;
+ referencesProvider = false;
+ }
+ }
+ end;
+ body = function()
+ end;
+ }
+end
+
function tests.basic_finish()
skeleton {
on_init = function(params)
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 99cbf30c7c..0bd378d832 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -554,9 +554,9 @@ function module.curbuf(method, ...)
return module.buffer(method, 0, ...)
end
-function module.wait()
- -- Execute 'nvim_eval' (a deferred function) to block
- -- until all pending input is processed.
+function module.poke_eventloop()
+ -- Execute 'nvim_eval' (a deferred function) to
+ -- force at least one main_loop iteration
session:request('nvim_eval', '1')
end
@@ -566,7 +566,7 @@ end
--@see buf_lines()
function module.curbuf_contents()
- module.wait() -- Before inspecting the buffer, process all input.
+ module.poke_eventloop() -- Before inspecting the buffer, do whatever.
return table.concat(module.curbuf('get_lines', 0, -1, true), '\n')
end
diff --git a/test/functional/legacy/005_bufleave_delete_buffer_spec.lua b/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
index 8b92c877a6..8e977aa73e 100644
--- a/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
+++ b/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
@@ -4,7 +4,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('test5', function()
setup(clear)
@@ -34,7 +34,7 @@ describe('test5', function()
command('bwipe')
feed('G?this is a<cr>')
feed('othis is some more text<esc>')
- wait()
+ poke_eventloop()
-- Append some text to this file.
@@ -45,7 +45,7 @@ describe('test5', function()
command('bwipe!')
-- Append an extra line to the output register.
feed('ithis is another test line<esc>:yank A<cr>')
- wait()
+ poke_eventloop()
-- Output results
command('%d')
diff --git a/test/functional/legacy/006_argument_list_spec.lua b/test/functional/legacy/006_argument_list_spec.lua
index 9f75a91fa8..d269bf8ec9 100644
--- a/test/functional/legacy/006_argument_list_spec.lua
+++ b/test/functional/legacy/006_argument_list_spec.lua
@@ -4,7 +4,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, dedent, eq = helpers.command, helpers.dedent, helpers.eq
local curbuf_contents = helpers.curbuf_contents
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('argument list', function()
setup(clear)
@@ -17,7 +17,7 @@ describe('argument list', function()
this is a test
this is a test
end of test file Xxx]])
- wait()
+ poke_eventloop()
command('au BufReadPost Xxx2 next Xxx2 Xxx1')
command('/^start of')
@@ -30,7 +30,7 @@ describe('argument list', function()
-- Write test file Xxx3
feed('$r3:.,/end of/w! Xxx3<cr>')
- wait()
+ poke_eventloop()
-- Redefine arglist; go to Xxx1
command('next! Xxx1 Xxx2 Xxx3')
@@ -43,7 +43,7 @@ describe('argument list', function()
-- Append contents of last window (Xxx1)
feed('')
- wait()
+ poke_eventloop()
command('%yank A')
-- should now be in Xxx2
diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua
index cec4f93737..48dd24db9e 100644
--- a/test/functional/legacy/012_directory_spec.lua
+++ b/test/functional/legacy/012_directory_spec.lua
@@ -8,7 +8,7 @@ local lfs = require('lfs')
local eq = helpers.eq
local neq = helpers.neq
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local funcs = helpers.funcs
local meths = helpers.meths
local clear = helpers.clear
@@ -64,7 +64,7 @@ describe("'directory' option", function()
eq(nil, lfs.attributes('.Xtest1.swp'))
command('edit! Xtest1')
- wait()
+ poke_eventloop()
eq('Xtest1', funcs.buffer_name('%'))
-- Verify that the swapfile exists. In the legacy test this was done by
-- reading the output from :!ls.
@@ -72,7 +72,7 @@ describe("'directory' option", function()
meths.set_option('directory', './Xtest2,.')
command('edit Xtest1')
- wait()
+ poke_eventloop()
-- swapfile should no longer exist in CWD.
eq(nil, lfs.attributes('.Xtest1.swp'))
@@ -82,7 +82,7 @@ describe("'directory' option", function()
meths.set_option('directory', 'Xtest.je')
command('edit Xtest2/Xtest3')
eq(true, curbufmeths.get_option('swapfile'))
- wait()
+ poke_eventloop()
eq({ "Xtest3" }, ls_dir_sorted("Xtest2"))
eq({ "Xtest3.swp" }, ls_dir_sorted("Xtest.je"))
diff --git a/test/functional/legacy/023_edit_arguments_spec.lua b/test/functional/legacy/023_edit_arguments_spec.lua
index e705397a2b..f59d192c1e 100644
--- a/test/functional/legacy/023_edit_arguments_spec.lua
+++ b/test/functional/legacy/023_edit_arguments_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, insert = helpers.clear, helpers.insert
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe(':edit', function()
setup(clear)
@@ -13,7 +13,7 @@ describe(':edit', function()
The result should be in Xfile1: "fooPIPEbar", in Xfile2: "fooSLASHbar"
foo|bar
foo/bar]])
- wait()
+ poke_eventloop()
-- Prepare some test files
command('$-1w! Xfile1')
diff --git a/test/functional/legacy/030_fileformats_spec.lua b/test/functional/legacy/030_fileformats_spec.lua
index 2fd51602d8..15dbd05cf5 100644
--- a/test/functional/legacy/030_fileformats_spec.lua
+++ b/test/functional/legacy/030_fileformats_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local feed, clear, command = helpers.feed, helpers.clear, helpers.command
local eq, write_file = helpers.eq, helpers.write_file
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('fileformats option', function()
setup(function()
@@ -107,7 +107,7 @@ describe('fileformats option', function()
command('bwipe XXDosMac')
command('e! XXEol')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt54')
command('bwipeout! XXEol')
command('set fileformats=dos,mac')
@@ -116,7 +116,7 @@ describe('fileformats option', function()
command('bwipe XXUxDs')
command('e! XXUxMac')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt62')
command('bwipeout! XXUxMac')
command('e! XXUxDsMc')
@@ -124,7 +124,7 @@ describe('fileformats option', function()
command('bwipe XXUxDsMc')
command('e! XXMacEol')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt64')
command('bwipeout! XXMacEol')
@@ -135,7 +135,7 @@ describe('fileformats option', function()
command('bwipe XXUxDsMc')
command('e! XXEol')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt72')
command('bwipeout! XXEol')
command('set fileformats=mac,dos,unix')
@@ -144,7 +144,7 @@ describe('fileformats option', function()
command('bwipe XXUxDsMc')
command('e! XXEol')
feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>')
- wait()
+ poke_eventloop()
command('w! XXtt82')
command('bwipeout! XXEol')
-- Try with 'binary' set.
@@ -165,7 +165,7 @@ describe('fileformats option', function()
-- char was.
command('set fileformat=unix nobin')
feed('ggdGaEND<esc>')
- wait()
+ poke_eventloop()
command('w >>XXtt01')
command('w >>XXtt02')
command('w >>XXtt11')
@@ -204,52 +204,52 @@ describe('fileformats option', function()
command('$r XXtt01')
command('$r XXtt02')
feed('Go1<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt11')
command('$r XXtt12')
command('$r XXtt13')
feed('Go2<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt21')
command('$r XXtt22')
command('$r XXtt23')
feed('Go3<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt31')
command('$r XXtt32')
command('$r XXtt33')
feed('Go4<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt41')
command('$r XXtt42')
command('$r XXtt43')
feed('Go5<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt51')
command('$r XXtt52')
command('$r XXtt53')
command('$r XXtt54')
feed('Go6<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt61')
command('$r XXtt62')
command('$r XXtt63')
command('$r XXtt64')
feed('Go7<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt71')
command('$r XXtt72')
feed('Go8<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt81')
command('$r XXtt82')
feed('Go9<esc>')
- wait()
+ poke_eventloop()
command('$r XXtt91')
command('$r XXtt92')
command('$r XXtt93')
feed('Go10<esc>')
- wait()
+ poke_eventloop()
command('$r XXUnix')
command('set nobinary ff&')
diff --git a/test/functional/legacy/033_lisp_indent_spec.lua b/test/functional/legacy/033_lisp_indent_spec.lua
index 5132333a5c..b27de6c16d 100644
--- a/test/functional/legacy/033_lisp_indent_spec.lua
+++ b/test/functional/legacy/033_lisp_indent_spec.lua
@@ -4,7 +4,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('lisp indent', function()
setup(clear)
@@ -39,7 +39,7 @@ describe('lisp indent', function()
command('set lisp')
command('/^(defun')
feed('=G:/^(defun/,$yank A<cr>')
- wait()
+ poke_eventloop()
-- Put @a and clean empty line
command('%d')
diff --git a/test/functional/legacy/036_regexp_character_classes_spec.lua b/test/functional/legacy/036_regexp_character_classes_spec.lua
index 38e8145d1c..6f66efcb67 100644
--- a/test/functional/legacy/036_regexp_character_classes_spec.lua
+++ b/test/functional/legacy/036_regexp_character_classes_spec.lua
@@ -15,7 +15,7 @@ end
local function diff(text, nodedent)
local fname = helpers.tmpname()
command('w! '..fname)
- helpers.wait()
+ helpers.poke_eventloop()
local data = io.open(fname):read('*all')
if nodedent then
helpers.eq(text, data)
diff --git a/test/functional/legacy/045_folding_spec.lua b/test/functional/legacy/045_folding_spec.lua
index 1e5239ceac..7d7856fd37 100644
--- a/test/functional/legacy/045_folding_spec.lua
+++ b/test/functional/legacy/045_folding_spec.lua
@@ -59,7 +59,7 @@ describe('folding', function()
feed('kYpj')
feed_command('call append("$", foldlevel("."))')
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect([[
dd {{{ |
ee {{{ }}} |
@@ -88,7 +88,7 @@ describe('folding', function()
feed_command('call append("$", foldlevel(2))')
feed('zR')
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect([[
aa |
bb |
diff --git a/test/functional/legacy/051_highlight_spec.lua b/test/functional/legacy/051_highlight_spec.lua
index 0c9c9621ee..d3f2897493 100644
--- a/test/functional/legacy/051_highlight_spec.lua
+++ b/test/functional/legacy/051_highlight_spec.lua
@@ -5,7 +5,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, feed = helpers.clear, helpers.feed
local expect = helpers.expect
local eq = helpers.eq
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local exc_exec = helpers.exc_exec
local feed_command = helpers.feed_command
@@ -34,7 +34,7 @@ describe(':highlight', function()
-- More --^ |
]])
feed('q')
- wait() -- wait until we're back to normal
+ poke_eventloop() -- wait until we're back to normal
feed_command('hi Search')
feed_command('hi Normal')
diff --git a/test/functional/legacy/057_sort_spec.lua b/test/functional/legacy/057_sort_spec.lua
index bdc2c9779c..328d6f6fa0 100644
--- a/test/functional/legacy/057_sort_spec.lua
+++ b/test/functional/legacy/057_sort_spec.lua
@@ -2,8 +2,8 @@
local helpers = require('test.functional.helpers')(after_each)
-local insert, command, clear, expect, eq, wait = helpers.insert,
- helpers.command, helpers.clear, helpers.expect, helpers.eq, helpers.wait
+local insert, command, clear, expect, eq, poke_eventloop = helpers.insert,
+ helpers.command, helpers.clear, helpers.expect, helpers.eq, helpers.poke_eventloop
local exc_exec = helpers.exc_exec
describe(':sort', function()
@@ -27,7 +27,7 @@ describe(':sort', function()
it('alphabetical', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort')
expect([[
@@ -67,7 +67,7 @@ describe(':sort', function()
b321
b321b
]])
- wait()
+ poke_eventloop()
command('sort n')
expect([[
abc
@@ -92,7 +92,7 @@ describe(':sort', function()
it('hexadecimal', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort x')
expect([[
@@ -114,7 +114,7 @@ describe(':sort', function()
it('alphabetical, unique', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort u')
expect([[
@@ -135,7 +135,7 @@ describe(':sort', function()
it('alphabetical, reverse', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort!')
expect([[
c321d
@@ -157,7 +157,7 @@ describe(':sort', function()
it('numerical, reverse', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort! n')
expect([[
b322b
@@ -179,7 +179,7 @@ describe(':sort', function()
it('unique, reverse', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort! u')
expect([[
c321d
@@ -200,7 +200,7 @@ describe(':sort', function()
it('octal', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort o')
expect([[
abc
@@ -222,7 +222,7 @@ describe(':sort', function()
it('reverse, hexadecimal', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort! x')
expect([[
c321d
@@ -244,7 +244,7 @@ describe(':sort', function()
it('alphabetical, skip first character', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/./')
expect([[
a
@@ -266,7 +266,7 @@ describe(':sort', function()
it('alphabetical, skip first 2 characters', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/../')
expect([[
ab
@@ -288,7 +288,7 @@ describe(':sort', function()
it('alphabetical, unique, skip first 2 characters', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/../u')
expect([[
ab
@@ -309,7 +309,7 @@ describe(':sort', function()
it('numerical, skip first character', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/./n')
expect([[
abc
@@ -331,7 +331,7 @@ describe(':sort', function()
it('alphabetical, sort on first character', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/./r')
expect([[
@@ -353,7 +353,7 @@ describe(':sort', function()
it('alphabetical, sort on first 2 characters', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/../r')
expect([[
a
@@ -375,7 +375,7 @@ describe(':sort', function()
it('numerical, sort on first character', function()
insert(text)
- wait()
+ poke_eventloop()
command('sort/./rn')
expect([[
abc
@@ -397,7 +397,7 @@ describe(':sort', function()
it('alphabetical, skip past first digit', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d/]])
expect([[
abc
@@ -419,7 +419,7 @@ describe(':sort', function()
it('alphabetical, sort on first digit', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d/r]])
expect([[
abc
@@ -441,7 +441,7 @@ describe(':sort', function()
it('numerical, skip past first digit', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d/n]])
expect([[
abc
@@ -463,7 +463,7 @@ describe(':sort', function()
it('numerical, sort on first digit', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d/rn]])
expect([[
abc
@@ -485,7 +485,7 @@ describe(':sort', function()
it('alphabetical, skip past first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/]])
expect([[
abc
@@ -507,7 +507,7 @@ describe(':sort', function()
it('numerical, skip past first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/n]])
expect([[
abc
@@ -529,7 +529,7 @@ describe(':sort', function()
it('hexadecimal, skip past first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/x]])
expect([[
abc
@@ -551,7 +551,7 @@ describe(':sort', function()
it('alpha, on first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/r]])
expect([[
abc
@@ -573,7 +573,7 @@ describe(':sort', function()
it('numeric, on first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/rn]])
expect([[
abc
@@ -595,7 +595,7 @@ describe(':sort', function()
it('hexadecimal, on first 2 digits', function()
insert(text)
- wait()
+ poke_eventloop()
command([[sort/\d\d/rx]])
expect([[
abc
@@ -638,7 +638,7 @@ describe(':sort', function()
0b100010
0b100100
0b100010]])
- wait()
+ poke_eventloop()
command([[sort b]])
expect([[
0b000000
@@ -673,7 +673,7 @@ describe(':sort', function()
0b101010
0b000000
b0b111000]])
- wait()
+ poke_eventloop()
command([[sort b]])
expect([[
0b000000
@@ -700,7 +700,7 @@ describe(':sort', function()
1.15e-6
-1.1e3
-1.01e3]])
- wait()
+ poke_eventloop()
command([[sort f]])
expect([[
-1.1e3
diff --git a/test/functional/legacy/074_global_var_in_viminfo_spec.lua b/test/functional/legacy/074_global_var_in_viminfo_spec.lua
index f7f074c61a..445d742c1f 100644
--- a/test/functional/legacy/074_global_var_in_viminfo_spec.lua
+++ b/test/functional/legacy/074_global_var_in_viminfo_spec.lua
@@ -2,9 +2,9 @@
local helpers = require('test.functional.helpers')(after_each)
local lfs = require('lfs')
-local clear, command, eq, neq, eval, wait =
+local clear, command, eq, neq, eval, poke_eventloop =
helpers.clear, helpers.command, helpers.eq, helpers.neq, helpers.eval,
- helpers.wait
+ helpers.poke_eventloop
describe('storing global variables in ShaDa files', function()
local tempname = 'Xtest-functional-legacy-074'
@@ -36,7 +36,7 @@ describe('storing global variables in ShaDa files', function()
eq(test_list, eval('MY_GLOBAL_LIST'))
command('wsh! ' .. tempname)
- wait()
+ poke_eventloop()
-- Assert that the shada file exists.
neq(nil, lfs.attributes(tempname))
diff --git a/test/functional/legacy/075_maparg_spec.lua b/test/functional/legacy/075_maparg_spec.lua
index ee2b041b51..ad6c190104 100644
--- a/test/functional/legacy/075_maparg_spec.lua
+++ b/test/functional/legacy/075_maparg_spec.lua
@@ -4,7 +4,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed = helpers.clear, helpers.feed
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('maparg()', function()
setup(clear)
@@ -25,7 +25,7 @@ describe('maparg()', function()
command('map abc y<S-char-114>y')
command([[call append('$', maparg('abc'))]])
feed('Go<esc>:<cr>')
- wait()
+ poke_eventloop()
-- Outside of the range, minimum
command('inoremap <Char-0x1040> a')
diff --git a/test/functional/legacy/107_adjust_window_and_contents_spec.lua b/test/functional/legacy/107_adjust_window_and_contents_spec.lua
index 239f60341a..841eeef0af 100644
--- a/test/functional/legacy/107_adjust_window_and_contents_spec.lua
+++ b/test/functional/legacy/107_adjust_window_and_contents_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local clear = helpers.clear
local insert = helpers.insert
local command = helpers.command
@@ -16,7 +16,7 @@ describe('107', function()
screen:attach()
insert('start:')
- wait()
+ poke_eventloop()
command('new')
command('call setline(1, range(1,256))')
command('let r=[]')
diff --git a/test/functional/legacy/autoformat_join_spec.lua b/test/functional/legacy/autoformat_join_spec.lua
index 84d661c190..22b1c258fe 100644
--- a/test/functional/legacy/autoformat_join_spec.lua
+++ b/test/functional/legacy/autoformat_join_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, expect = helpers.command, helpers.expect
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('autoformat join', function()
setup(clear)
@@ -21,7 +21,7 @@ Results:]])
feed('gg')
feed('0gqj<cr>')
- wait()
+ poke_eventloop()
command([[let a=string(getpos("'[")).'/'.string(getpos("']"))]])
command("g/^This line/;'}-join")
diff --git a/test/functional/legacy/close_count_spec.lua b/test/functional/legacy/close_count_spec.lua
index 9b932e2ef0..60ae155fbf 100644
--- a/test/functional/legacy/close_count_spec.lua
+++ b/test/functional/legacy/close_count_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local eval = helpers.eval
local feed = helpers.feed
local clear = helpers.clear
@@ -110,23 +110,23 @@ describe('close_count', function()
command('for i in range(5)|new|endfor')
command('4wincmd w')
feed('<C-W>c<cr>')
- wait()
+ poke_eventloop()
command('let buffers = []')
command('windo call add(buffers, bufnr("%"))')
eq({25, 24, 23, 21, 1}, eval('buffers'))
feed('1<C-W>c<cr>')
- wait()
+ poke_eventloop()
command('let buffers = []')
command('windo call add(buffers, bufnr("%"))')
eq({24, 23, 21, 1}, eval('buffers'))
feed('9<C-W>c<cr>')
- wait()
+ poke_eventloop()
command('let buffers = []')
command('windo call add(buffers, bufnr("%"))')
eq({24, 23, 21}, eval('buffers'))
command('1wincmd w')
feed('2<C-W>c<cr>')
- wait()
+ poke_eventloop()
command('let buffers = []')
command('windo call add(buffers, bufnr("%"))')
eq({24, 21}, eval('buffers'))
diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index aafcda67dc..3fbbe96947 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local feed = helpers.feed
local feed_command = helpers.feed_command
@@ -18,7 +18,7 @@ describe('display', function()
})
feed_command([[call setline(1, repeat('a', 21))]])
- wait()
+ poke_eventloop()
feed('O')
screen:expect([[
^ |
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index 4198ea8bfe..ee9bd29fc4 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -4,7 +4,7 @@ local helpers = require('test.functional.helpers')(after_each)
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, command, expect = helpers.clear, helpers.command, helpers.expect
local eq, eval, write_file = helpers.eq, helpers.eval, helpers.write_file
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local exc_exec = helpers.exc_exec
local dedent = helpers.dedent
@@ -71,7 +71,7 @@ describe('eval', function()
command([[call SetReg('I', 'abcI')]])
feed('Go{{{1 Appending single lines with setreg()<esc>')
- wait()
+ poke_eventloop()
command([[call SetReg('A', 'abcAc', 'c')]])
command([[call SetReg('A', 'abcAl', 'l')]])
command([[call SetReg('A', 'abcAc2','c')]])
@@ -700,13 +700,13 @@ describe('eval', function()
start:]])
command('/^012345678')
feed('6l')
- wait()
+ poke_eventloop()
command('let sp = getcurpos()')
feed('0')
- wait()
+ poke_eventloop()
command("call setpos('.', sp)")
feed('jyl')
- wait()
+ poke_eventloop()
command('$put')
expect([[
012345678
diff --git a/test/functional/legacy/mapping_spec.lua b/test/functional/legacy/mapping_spec.lua
index 56a5652184..92a757ca85 100644
--- a/test/functional/legacy/mapping_spec.lua
+++ b/test/functional/legacy/mapping_spec.lua
@@ -2,7 +2,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local feed_command, expect, wait = helpers.feed_command, helpers.expect, helpers.wait
+local feed_command, expect, poke_eventloop = helpers.feed_command, helpers.expect, helpers.poke_eventloop
describe('mapping', function()
before_each(clear)
@@ -29,9 +29,9 @@ describe('mapping', function()
feed_command('cunmap <c-c>')
feed('GA<cr>')
feed('TEST2: CTRL-C |')
- wait()
+ poke_eventloop()
feed('<c-c>A|<cr><esc>')
- wait()
+ poke_eventloop()
feed_command('unmap <c-c>')
feed_command('unmap! <c-c>')
@@ -46,7 +46,7 @@ describe('mapping', function()
feed('GV')
-- XXX: For some reason the mapping is only triggered
-- when <C-c> is in a separate feed command.
- wait()
+ poke_eventloop()
feed('<c-c>')
feed_command('vunmap <c-c>')
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index 251e6a5ea4..fb0bacc2d2 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -7,7 +7,7 @@ local iswin = helpers.iswin
local retry = helpers.retry
local ok = helpers.ok
local source = helpers.source
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local uname = helpers.uname
local load_adjust = helpers.load_adjust
@@ -102,7 +102,7 @@ describe('memory usage', function()
call s:f(0)
endfor
]])
- wait()
+ poke_eventloop()
local after = monitor_memory_usage(pid)
-- Estimate the limit of max usage as 2x initial usage.
-- The lower limit can fluctuate a bit, use 97%.
@@ -147,11 +147,11 @@ describe('memory usage', function()
call s:f()
endfor
]])
- wait()
+ poke_eventloop()
local after = monitor_memory_usage(pid)
for _ = 1, 3 do
feed_command('so '..fname)
- wait()
+ poke_eventloop()
end
local last = monitor_memory_usage(pid)
-- The usage may be a bit less than the last value, use 80%.
diff --git a/test/functional/legacy/search_mbyte_spec.lua b/test/functional/legacy/search_mbyte_spec.lua
index a365f79cdf..ef7e41aa30 100644
--- a/test/functional/legacy/search_mbyte_spec.lua
+++ b/test/functional/legacy/search_mbyte_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local clear = helpers.clear
local insert = helpers.insert
local expect = helpers.expect
@@ -15,7 +15,7 @@ describe('search_mbyte', function()
Test bce:
A]=])
- wait()
+ poke_eventloop()
command('/^Test bce:/+1')
command([[$put =search('A', 'bce', line('.'))]])
diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua
index bb039a585c..4ed08881de 100644
--- a/test/functional/legacy/search_spec.lua
+++ b/test/functional/legacy/search_spec.lua
@@ -6,7 +6,7 @@ local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
local funcs = helpers.funcs
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('search cmdline', function()
local screen
@@ -483,9 +483,9 @@ describe('search cmdline', function()
-- "interactive". This mimics Vim's test_override("char_avail").
-- (See legacy test: test_search.vim)
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 the first |
@@ -496,11 +496,11 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 ^the first |
@@ -511,13 +511,13 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<c-g>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 the first |
@@ -528,9 +528,9 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 ^the first |
@@ -541,11 +541,11 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 the first |
@@ -556,13 +556,13 @@ describe('search cmdline', function()
command('$')
feed('?the')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<c-t>')
- wait()
+ poke_eventloop()
feed('<cr>')
screen:expect([[
1 the first |
diff --git a/test/functional/legacy/utf8_spec.lua b/test/functional/legacy/utf8_spec.lua
index 5b93f25b24..8b5fc02d11 100644
--- a/test/functional/legacy/utf8_spec.lua
+++ b/test/functional/legacy/utf8_spec.lua
@@ -5,7 +5,7 @@ local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, expect = helpers.command, helpers.expect
local eq, eval = helpers.eq, helpers.eval
local source = helpers.source
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('utf8', function()
before_each(clear)
@@ -18,7 +18,7 @@ describe('utf8', function()
-- Visual block Insert adjusts for multi-byte char
feed('gg0l<C-V>jjIx<Esc>')
- wait()
+ poke_eventloop()
command('let r = getline(1, "$")')
command('bwipeout!')
diff --git a/test/functional/legacy/wordcount_spec.lua b/test/functional/legacy/wordcount_spec.lua
index 0c8bd2cdcc..826743b0ca 100644
--- a/test/functional/legacy/wordcount_spec.lua
+++ b/test/functional/legacy/wordcount_spec.lua
@@ -4,7 +4,7 @@ local helpers = require('test.functional.helpers')(after_each)
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, command = helpers.clear, helpers.command
local eq, eval = helpers.eq, helpers.eval
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('wordcount', function()
before_each(clear)
@@ -14,7 +14,7 @@ describe('wordcount', function()
insert([=[
RESULT test:]=])
- wait()
+ poke_eventloop()
command('new')
source([=[
@@ -127,7 +127,7 @@ describe('wordcount', function()
-- -- Start visual mode quickly and select complete buffer.
command('0')
feed('V2jy<cr>')
- wait()
+ poke_eventloop()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
@@ -144,7 +144,7 @@ describe('wordcount', function()
-- Start visual mode quickly and select complete buffer.
command('0')
feed('v$y<cr>')
- wait()
+ poke_eventloop()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
@@ -161,7 +161,7 @@ describe('wordcount', function()
-- Start visual mode quickly and select complete buffer.
command('2')
feed('0v$y<cr>')
- wait()
+ poke_eventloop()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index cbc3aee557..f2a1b7dede 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -43,7 +43,7 @@ describe(':lua command', function()
eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false))
end)
it('throws catchable errors', function()
- eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:1: unexpected symbol near ')']],
+ eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:0: unexpected symbol near ')']],
pcall_err(command, 'lua ()'))
eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]],
exc_exec('lua error("TEST")'))
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index 75966393b1..2ec48777fd 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -477,14 +477,14 @@ describe('v:lua', function()
eq(NIL, eval('v:lua.mymod.noisy("eval")'))
eq("hey eval", meths.get_current_line())
- eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:10: attempt to call global 'nonexistent' (a nil value)",
+ eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
pcall_err(eval, 'v:lua.mymod.crashy()'))
end)
it('works in :call', function()
command(":call v:lua.mymod.noisy('command')")
eq("hey command", meths.get_current_line())
- eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:10: attempt to call global 'nonexistent' (a nil value)",
+ eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
pcall_err(command, 'call v:lua.mymod.crashy()'))
end)
diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua
index 74ae6cde2b..3526b64395 100644
--- a/test/functional/lua/treesitter_spec.lua
+++ b/test/functional/lua/treesitter_spec.lua
@@ -15,17 +15,16 @@ before_each(clear)
describe('treesitter API', function()
-- error tests not requiring a parser library
it('handles missing language', function()
- eq("Error executing lua: .../language.lua: no parser for 'borklang' language, see :help treesitter-parsers",
+ eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')"))
-- actual message depends on platform
matches("Error executing lua: Failed to load parser: uv_dlopen: .+",
pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')"))
- eq("Error executing lua: .../language.lua: no parser for 'borklang' language, see :help treesitter-parsers",
+ eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')"))
end)
-
end)
describe('treesitter API with C parser', function()
@@ -186,6 +185,16 @@ void ui_refresh(void)
(field_expression argument: (identifier) @fieldarg)
]]
+ it("supports runtime queries", function()
+ if not check_parser() then return end
+
+ local ret = exec_lua [[
+ return require"vim.treesitter.query".get_query("c", "highlights").captures[1]
+ ]]
+
+ eq('variable', ret)
+ end)
+
it('support query and iter by capture', function()
if not check_parser() then return end
@@ -420,9 +429,10 @@ static int nlua_schedule(lua_State *const lstate)
]]}
exec_lua([[
+ local parser = vim.treesitter.get_parser(0, "c")
local highlighter = vim.treesitter.highlighter
local query = ...
- test_hl = highlighter.new(query, 0, "c")
+ test_hl = highlighter.new(parser, query)
]], hl_query)
screen:expect{grid=[[
{2:/// Schedule Lua callback on main loop's event queue} |
@@ -559,6 +569,72 @@ static int nlua_schedule(lua_State *const lstate)
]]}
end)
+ it("supports highlighting with custom parser", function()
+ if not check_parser() then return end
+
+ local screen = Screen.new(65, 18)
+ screen:attach()
+ screen:set_default_attr_ids({ {bold = true, foreground = Screen.colors.SeaGreen4} })
+
+ insert(test_text)
+
+ screen:expect{ grid= [[
+ int width = INT_MAX, height = INT_MAX; |
+ bool ext_widgets[kUIExtCount]; |
+ for (UIExtension i = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool inclusive = ui_override(); |
+ for (size_t i = 0; i < ui_count; i++) { |
+ UI *ui = uis[i]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]] }
+
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+ query = vim.treesitter.parse_query("c", "(declaration) @decl")
+
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse():root(), 0, 0, 19) do
+ table.insert(nodes, node)
+ end
+
+ parser:set_included_ranges(nodes)
+
+ local hl = vim.treesitter.highlighter.new(parser, "(identifier) @type")
+ ]])
+
+ screen:expect{ grid = [[
+ int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; |
+ bool {1:ext_widgets}[{1:kUIExtCount}]; |
+ for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool {1:inclusive} = {1:ui_override}(); |
+ for (size_t {1:i} = 0; i < ui_count; i++) { |
+ UI *{1:ui} = {1:uis}[{1:i}]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]] }
+ end)
+
it('inspects language', function()
if not check_parser() then return end
@@ -604,23 +680,29 @@ static int nlua_schedule(lua_State *const lstate)
insert(test_text)
- local res = exec_lua([[
+ local res = exec_lua [[
parser = vim.treesitter.get_parser(0, "c")
return { parser:parse():root():range() }
- ]])
+ ]]
eq({0, 0, 19, 0}, res)
-- The following sets the included ranges for the current parser
-- As stated here, this only includes the function (thus the whole buffer, without the last line)
- local res2 = exec_lua([[
+ local res2 = exec_lua [[
local root = parser:parse():root()
parser:set_included_ranges({root:child(0)})
parser.valid = false
return { parser:parse():root():range() }
- ]])
+ ]]
eq({0, 0, 18, 1}, res2)
+
+ local range = exec_lua [[
+ return parser:included_ranges()
+ ]]
+
+ eq(range, { { 0, 0, 18, 1 } })
end)
it("allows to set complex ranges", function()
if not check_parser() then return end
@@ -628,7 +710,7 @@ static int nlua_schedule(lua_State *const lstate)
insert(test_text)
- local res = exec_lua([[
+ local res = exec_lua [[
parser = vim.treesitter.get_parser(0, "c")
query = vim.treesitter.parse_query("c", "(declaration) @decl")
@@ -646,7 +728,7 @@ static int nlua_schedule(lua_State *const lstate)
table.insert(res, { root:named_child(i):range() })
end
return res
- ]])
+ ]]
eq({
{ 2, 2, 2, 40 },
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 63e48a18ca..1cbf6b21e3 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -4,13 +4,14 @@ local Screen = require('test.functional.ui.screen')
local funcs = helpers.funcs
local meths = helpers.meths
+local dedent = helpers.dedent
local command = helpers.command
local clear = helpers.clear
local eq = helpers.eq
local ok = helpers.ok
local eval = helpers.eval
local feed = helpers.feed
-local pcall_err = helpers.pcall_err
+local pcall_err_withfile = helpers.pcall_err_withfile
local exec_lua = helpers.exec_lua
local matches = helpers.matches
local source = helpers.source
@@ -128,8 +129,8 @@ describe('lua stdlib', function()
eq(false, funcs.luaeval('vim.startswith("123", "2")'))
eq(false, funcs.luaeval('vim.startswith("123", "1234")'))
- eq("string", type(pcall_err(funcs.luaeval, 'vim.startswith("123", nil)')))
- eq("string", type(pcall_err(funcs.luaeval, 'vim.startswith(nil, "123")')))
+ eq("string", type(pcall_err_withfile(funcs.luaeval, 'vim.startswith("123", nil)')))
+ eq("string", type(pcall_err_withfile(funcs.luaeval, 'vim.startswith(nil, "123")')))
end)
it('vim.endswith', function()
@@ -142,8 +143,8 @@ describe('lua stdlib', function()
eq(false, funcs.luaeval('vim.endswith("123", "2")'))
eq(false, funcs.luaeval('vim.endswith("123", "1234")'))
- eq("string", type(pcall_err(funcs.luaeval, 'vim.endswith("123", nil)')))
- eq("string", type(pcall_err(funcs.luaeval, 'vim.endswith(nil, "123")')))
+ eq("string", type(pcall_err_withfile(funcs.luaeval, 'vim.endswith("123", nil)')))
+ eq("string", type(pcall_err_withfile(funcs.luaeval, 'vim.endswith(nil, "123")')))
end)
it("vim.str_utfindex/str_byteindex", function()
@@ -182,10 +183,10 @@ describe('lua stdlib', function()
eq({"yy","xx"}, exec_lua("return test_table"))
-- Validates args.
- eq('Error executing lua: vim.schedule: expected function',
- pcall_err(exec_lua, "vim.schedule('stringly')"))
- eq('Error executing lua: vim.schedule: expected function',
- pcall_err(exec_lua, "vim.schedule()"))
+ eq('.../helpers.lua:0: Error executing lua: vim.schedule: expected function',
+ pcall_err_withfile(exec_lua, "vim.schedule('stringly')"))
+ eq('.../helpers.lua:0: Error executing lua: vim.schedule: expected function',
+ pcall_err_withfile(exec_lua, "vim.schedule()"))
exec_lua([[
vim.schedule(function()
@@ -257,17 +258,29 @@ describe('lua stdlib', function()
}
for _, t in ipairs(loops) do
- matches(".*Infinite loop detected", pcall_err(split, t[1], t[2]))
+ matches(".*Infinite loop detected", pcall_err_withfile(split, t[1], t[2]))
end
-- Validates args.
eq(true, pcall(split, 'string', 'string'))
- eq('Error executing lua: .../shared.lua: s: expected string, got number',
- pcall_err(split, 1, 'string'))
- eq('Error executing lua: .../shared.lua: sep: expected string, got number',
- pcall_err(split, 'string', 1))
- eq('Error executing lua: .../shared.lua: plain: expected boolean, got number',
- pcall_err(split, 'string', 'string', 1))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: s: expected string, got number
+ stack traceback:
+ shared.lua:0: in function 'gsplit'
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(split, 1, 'string'))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: sep: expected string, got number
+ stack traceback:
+ shared.lua:0: in function 'gsplit'
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(split, 'string', 1))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: plain: expected boolean, got number
+ stack traceback:
+ shared.lua:0: in function 'gsplit'
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(split, 'string', 'string', 1))
end)
it('vim.trim', function()
@@ -287,8 +300,11 @@ describe('lua stdlib', function()
end
-- Validates args.
- eq('Error executing lua: .../shared.lua: s: expected string, got number',
- pcall_err(trim, 2))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: s: expected string, got number
+ stack traceback:
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(trim, 2))
end)
it('vim.inspect', function()
@@ -353,8 +369,8 @@ describe('lua stdlib', function()
return t1.f() ~= t2.f()
]]))
- eq('Error executing lua: .../shared.lua: Cannot deepcopy object of type thread',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: Cannot deepcopy object of type thread',
+ pcall_err_withfile(exec_lua, [[
local thread = coroutine.create(function () return 0 end)
local t = {thr = thread}
vim.deepcopy(t)
@@ -366,8 +382,11 @@ describe('lua stdlib', function()
eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]]))
-- Validates args.
- eq('Error executing lua: .../shared.lua: s: expected string, got number',
- pcall_err(exec_lua, [[return vim.pesc(2)]]))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: s: expected string, got number
+ stack traceback:
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(exec_lua, [[return vim.pesc(2)]]))
end)
it('vim.tbl_keys', function()
@@ -491,20 +510,20 @@ describe('lua stdlib', function()
return c.x.a == 1 and c.x.b == 2 and c.x.c == nil and count == 1
]]))
- eq('Error executing lua: .../shared.lua: invalid "behavior": nil',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: invalid "behavior": nil',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_extend()
]])
)
- eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: wrong number of arguments (given 1, expected at least 3)',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_extend("keep")
]])
)
- eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: wrong number of arguments (given 2, expected at least 3)',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_extend("keep", {})
]])
)
@@ -579,20 +598,20 @@ describe('lua stdlib', function()
return vim.tbl_islist(c) and count == 0
]]))
- eq('Error executing lua: .../shared.lua: invalid "behavior": nil',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: invalid "behavior": nil',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_deep_extend()
]])
)
- eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: wrong number of arguments (given 1, expected at least 3)',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_deep_extend("keep")
]])
)
- eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)',
- pcall_err(exec_lua, [[
+ eq('.../helpers.lua:0: Error executing lua: shared.lua:0: wrong number of arguments (given 2, expected at least 3)',
+ pcall_err_withfile(exec_lua, [[
return vim.tbl_deep_extend("keep", {})
]])
)
@@ -624,8 +643,11 @@ describe('lua stdlib', function()
it('vim.list_extend', function()
eq({1,2,3}, exec_lua [[ return vim.list_extend({1}, {2,3}) ]])
- eq('Error executing lua: .../shared.lua: src: expected table, got nil',
- pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]]))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: shared.lua:0: src: expected table, got nil
+ stack traceback:
+ shared.lua:0: in function <shared.lua:0>]]),
+ pcall_err_withfile(exec_lua, [[ return vim.list_extend({1}, nil) ]]))
eq({1,2}, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]])
eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]])
eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1) ]])
@@ -648,8 +670,8 @@ describe('lua stdlib', function()
assert(vim.deep_equal(a, { A = 1; [1] = 'A'; }))
vim.tbl_add_reverse_lookup(a)
]]
- matches('Error executing lua: .../shared.lua: The reverse lookup found an existing value for "[1A]" while processing key "[1A]"',
- pcall_err(exec_lua, code))
+ matches('.../helpers.lua:0: Error executing lua: shared.lua:0: The reverse lookup found an existing value for "[1A]" while processing key "[1A]"',
+ pcall_err_withfile(exec_lua, code))
end)
it('vim.call, vim.fn', function()
@@ -820,34 +842,77 @@ describe('lua stdlib', function()
exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
- eq("Error executing lua: .../shared.lua: 1: expected table, got number",
- pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
- eq("Error executing lua: .../shared.lua: invalid type name: x",
- pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
- eq("Error executing lua: .../shared.lua: invalid type name: 1",
- pcall_err(exec_lua, "vim.validate{ arg1={ 1, 1 }}"))
- eq("Error executing lua: .../shared.lua: invalid type name: nil",
- pcall_err(exec_lua, "vim.validate{ arg1={ 1 }}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: opt[1]: expected table, got number
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ 1, 'x' }"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: invalid type name: x
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: invalid type name: 1
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ 1, 1 }}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: invalid type name: nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ 1 }}"))
-- Validated parameters are required by default.
- eq("Error executing lua: .../shared.lua: arg1: expected string, got nil",
- pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected string, got nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ nil, 's' }}"))
-- Explicitly required.
- eq("Error executing lua: .../shared.lua: arg1: expected string, got nil",
- pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}"))
-
- eq("Error executing lua: .../shared.lua: arg1: expected table, got number",
- pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}"))
- eq("Error executing lua: .../shared.lua: arg2: expected string, got number",
- pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}"))
- eq("Error executing lua: .../shared.lua: arg2: expected string, got nil",
- pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
- eq("Error executing lua: .../shared.lua: arg2: expected string, got nil",
- pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
- eq("Error executing lua: .../shared.lua: arg1: expected even number, got 3",
- pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}"))
- eq("Error executing lua: .../shared.lua: arg1: expected ?, got 3",
- pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected string, got nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{ arg1={ nil, 's', false }}"))
+
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected table, got number
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={1, 't'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg2: expected string, got number
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg2: expected string, got nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg2: expected string, got nil
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected even number, got 3
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}"))
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected ?, got 3
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}"))
+
+ -- Pass an additional message back.
+ eq(dedent([[
+ .../helpers.lua:0: Error executing lua: [string "<nvim>"]:0: arg1: expected ?, got 3. Info: TEST_MSG
+ stack traceback:
+ [string "<nvim>"]:0: in main chunk]]),
+ pcall_err_withfile(exec_lua, "vim.validate{arg1={3, function(a) return a == 1, 'TEST_MSG' end}}"))
end)
it('vim.is_callable', function()
@@ -992,10 +1057,10 @@ describe('lua stdlib', function()
]]
eq('', funcs.luaeval "vim.bo.filetype")
eq(true, funcs.luaeval "vim.bo[BUF].modifiable")
- matches("^Error executing lua: .*: Invalid option name: 'nosuchopt'$",
- pcall_err(exec_lua, 'return vim.bo.nosuchopt'))
- matches("^Error executing lua: .*: Expected lua string$",
- pcall_err(exec_lua, 'return vim.bo[0][0].autoread'))
+ matches("^.../helpers.lua:0: Error executing lua: .*: Invalid option name: 'nosuchopt'$",
+ pcall_err_withfile(exec_lua, 'return vim.bo.nosuchopt'))
+ matches("^.../helpers.lua:0: Error executing lua: .*: Expected lua string$",
+ pcall_err_withfile(exec_lua, 'return vim.bo[0][0].autoread'))
end)
it('vim.wo', function()
@@ -1011,10 +1076,10 @@ describe('lua stdlib', function()
eq(0, funcs.luaeval "vim.wo.cole")
eq(0, funcs.luaeval "vim.wo[0].cole")
eq(0, funcs.luaeval "vim.wo[1001].cole")
- matches("^Error executing lua: .*: Invalid option name: 'notanopt'$",
- pcall_err(exec_lua, 'return vim.wo.notanopt'))
- matches("^Error executing lua: .*: Expected lua string$",
- pcall_err(exec_lua, 'return vim.wo[0][0].list'))
+ matches("^.../helpers.lua:0: Error executing lua: .*: Invalid option name: 'notanopt'$",
+ pcall_err_withfile(exec_lua, 'return vim.wo.notanopt'))
+ matches("^.../helpers.lua:0: Error executing lua: .*: Expected lua string$",
+ pcall_err_withfile(exec_lua, 'return vim.wo[0][0].list'))
eq(2, funcs.luaeval "vim.wo[1000].cole")
exec_lua [[
vim.wo[1000].cole = 0
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index f514f4ea6f..067a13ce68 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -270,6 +270,70 @@ describe('LSP', function()
test_name = "basic_check_capabilities";
on_init = function(client)
client.stop()
+ local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ eq(full_kind, client.resolved_capabilities().text_document_did_change)
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ on_callback = function(...)
+ eq(table.remove(expected_callbacks), {...}, "expected callback")
+ end;
+ }
+ end)
+
+ it('client.supports_methods() should validate capabilities', function()
+ local expected_callbacks = {
+ {NIL, "shutdown", {}, 1};
+ }
+ test_rpc_server {
+ test_name = "capabilities_for_client_supports_method";
+ on_init = function(client)
+ client.stop()
+ local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ eq(full_kind, client.resolved_capabilities().text_document_did_change)
+ eq(true, client.resolved_capabilities().completion)
+ eq(true, client.resolved_capabilities().hover)
+ eq(false, client.resolved_capabilities().goto_definition)
+ eq(false, client.resolved_capabilities().rename)
+
+ -- known methods for resolved capabilities
+ eq(true, client.supports_method("textDocument/hover"))
+ eq(false, client.supports_method("textDocument/definition"))
+
+ -- unknown methods are assumed to be supported.
+ eq(true, client.supports_method("unknown-method"))
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ on_callback = function(...)
+ eq(table.remove(expected_callbacks), {...}, "expected callback")
+ end;
+ }
+ end)
+
+ it('should call unsupported_method when trying to call an unsupported method', function()
+ local expected_callbacks = {
+ {NIL, "shutdown", {}, 1};
+ }
+ test_rpc_server {
+ test_name = "capabilities_for_client_supports_method";
+ on_setup = function()
+ exec_lua([=[
+ vim.lsp._unsupported_method = function(method)
+ vim.lsp._last_unsupported_method = method
+ return 'fake-error'
+ end
+ vim.lsp.buf.hover()
+ ]=])
+ end;
+ on_init = function(client)
+ client.stop()
+ local method = exec_lua("return vim.lsp._last_unsupported_method")
+ eq("textDocument/hover", method)
end;
on_exit = function(code, signal)
eq(0, code, "exit code", fake_lsp_logfile)
@@ -747,8 +811,16 @@ describe('LSP', function()
end)
it('should invalid cmd argument', function()
- eq('Error executing lua: .../shared.lua: cmd: expected list, got nvim', pcall_err(_cmd_parts, "nvim"))
- eq('Error executing lua: .../shared.lua: cmd argument: expected string, got number', pcall_err(_cmd_parts, {"nvim", 1}))
+ eq(dedent([[
+ Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim
+ stack traceback:
+ .../lsp.lua:0: in function .../lsp.lua:0>]]),
+ pcall_err(_cmd_parts, 'nvim'))
+ eq(dedent([[
+ Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number
+ stack traceback:
+ .../lsp.lua:0: in function .../lsp.lua:0>]]),
+ pcall_err(_cmd_parts, {'nvim', 1}))
end)
end)
end)
diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua
index bb7d23ede6..2729d8dfa2 100644
--- a/test/functional/provider/ruby_spec.lua
+++ b/test/functional/provider/ruby_spec.lua
@@ -5,6 +5,7 @@ local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq = helpers.eq
local eval = helpers.eval
+local exc_exec = helpers.exc_exec
local expect = helpers.expect
local feed = helpers.feed
local feed_command = helpers.feed_command
@@ -109,3 +110,24 @@ describe('ruby provider', function()
eq(2, eval('1+1')) -- Still alive?
end)
end)
+
+describe('rubyeval()', function()
+ it('evaluates ruby objects', function()
+ eq({1, 2, {['key'] = 'val'}}, funcs.rubyeval('[1, 2, {key: "val"}]'))
+ end)
+
+ it('returns nil for empty strings', function()
+ eq(helpers.NIL, funcs.rubyeval(''))
+ end)
+
+ it('errors out when given non-string', function()
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(10)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:_null_dict)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:_null_list)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(0.0)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(function("tr"))'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:true)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:false)'))
+ eq('Vim(call):E474: Invalid argument', exc_exec('call rubyeval(v:null)'))
+ end)
+end)
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 6372cd935e..8e171d31aa 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local eval, feed_command, source = helpers.eval, helpers.feed_command, helpers.source
local eq, neq = helpers.eq, helpers.neq
local write_file = helpers.write_file
@@ -13,7 +13,7 @@ describe(':terminal buffer', function()
before_each(function()
clear()
feed_command('set modifiable swapfile undolevels=20')
- wait()
+ poke_eventloop()
screen = thelpers.screen_setup()
end)
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index ef12438ecc..8d70ebf679 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -70,7 +70,7 @@ describe(':terminal cursor', function()
:set number |
]])
feed('i')
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect([[
{7: 1 }tty ready |
{7: 2 }rows: 6, cols: 46 |
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 138befd978..4b512605e1 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local clear, wait, nvim = helpers.clear, helpers.wait, helpers.nvim
+local clear, poke_eventloop, nvim = helpers.clear, helpers.poke_eventloop, helpers.nvim
local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq
local feed = helpers.feed
local feed_command, eval = helpers.feed_command, helpers.eval
@@ -29,7 +29,7 @@ describe(':terminal', function()
-- Invoke a command that emits frequent terminal activity.
feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 9999 !terminal_output!<cr>]])
feed([[<C-\><C-N>]])
- wait()
+ poke_eventloop()
-- Wait for some terminal activity.
retry(nil, 4000, function()
ok(funcs.line('$') > 6)
@@ -60,7 +60,7 @@ describe(':terminal', function()
feed_command([[terminal while true; do echo foo; sleep .1; done]])
end
feed([[<C-\><C-N>M]]) -- move cursor away from last line
- wait()
+ poke_eventloop()
eq(3, eval("line('$')")) -- window height
eq(2, eval("line('.')")) -- cursor is in the middle
feed_command('vsplit')
@@ -76,11 +76,11 @@ describe(':terminal', function()
-- Create a new line (in the shell). For a normal buffer this
-- increments the jumplist; for a terminal-buffer it should not. #3723
feed('i')
- wait()
+ poke_eventloop()
feed('<CR><CR><CR><CR>')
- wait()
+ poke_eventloop()
feed([[<C-\><C-N>]])
- wait()
+ poke_eventloop()
-- Wait for >=1 lines to be created.
retry(nil, 4000, function()
ok(funcs.line('$') > lines_before)
@@ -210,7 +210,7 @@ describe(':terminal (with fake shell)', function()
it('ignores writes if the backing stream closes', function()
terminal_with_fake_shell()
feed('iiXXXXXXX')
- wait()
+ poke_eventloop()
-- Race: Though the shell exited (and streams were closed by SIGCHLD
-- handler), :terminal cleanup is pending on the main-loop.
-- This write should be ignored (not crash, #5445).
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 1df8df6f6e..77fdba7fc4 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -6,7 +6,7 @@ local feed, nvim_dir, feed_command = helpers.feed, helpers.nvim_dir, helpers.fee
local iswin = helpers.iswin
local eval = helpers.eval
local command = helpers.command
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local retry = helpers.retry
local curbufmeths = helpers.curbufmeths
local nvim = helpers.nvim
@@ -347,7 +347,7 @@ describe(':terminal prints more lines than the screen height and exits', functio
local screen = Screen.new(30, 7)
screen:attach({rgb=false})
feed_command('call termopen(["'..nvim_dir..'/tty-test", "10"]) | startinsert')
- wait()
+ poke_eventloop()
screen:expect([[
line6 |
line7 |
@@ -423,7 +423,7 @@ describe("'scrollback' option", function()
retry(nil, nil, function() expect_lines(33, 2) end)
curbufmeths.set_option('scrollback', 10)
- wait()
+ poke_eventloop()
retry(nil, nil, function() expect_lines(16) end)
curbufmeths.set_option('scrollback', 10000)
retry(nil, nil, function() expect_lines(16) end)
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
index f1c828d17e..9f278fd157 100644
--- a/test/functional/terminal/window_spec.lua
+++ b/test/functional/terminal/window_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local feed_data = thelpers.feed_data
local feed, clear = helpers.feed, helpers.clear
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local iswin = helpers.iswin
local command = helpers.command
local retry = helpers.retry
@@ -127,7 +127,7 @@ describe(':terminal window', function()
it('wont show any folds', function()
feed([[<C-\><C-N>ggvGzf]])
- wait()
+ poke_eventloop()
screen:expect([[
^tty ready |
line1 |
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 11fe861de8..eec8eb93d4 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -59,7 +59,7 @@ describe('floatwin', function()
end)
it('closed immediately by autocmd #11383', function()
- eq('Error executing lua: [string "<nvim>"]:4: Window was closed immediately',
+ eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately',
pcall_err(exec_lua, [[
local a = vim.api
local function crashes(contents)
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 16c5477ee4..712c1f377a 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -14,7 +14,7 @@ local neq = helpers.neq
local ok = helpers.ok
local retry = helpers.retry
local source = helpers.source
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
local nvim = helpers.nvim
local sleep = helpers.sleep
local nvim_dir = helpers.nvim_dir
@@ -114,7 +114,7 @@ describe(":substitute, inccommand=split interactivity", function()
it("no preview if invoked by a script", function()
source('%s/tw/MO/g')
- wait()
+ poke_eventloop()
eq(1, eval("bufnr('$')"))
-- sanity check: assert the buffer state
expect(default_text:gsub("tw", "MO"))
@@ -123,10 +123,10 @@ describe(":substitute, inccommand=split interactivity", function()
it("no preview if invoked by feedkeys()", function()
-- in a script...
source([[:call feedkeys(":%s/tw/MO/g\<CR>")]])
- wait()
+ poke_eventloop()
-- or interactively...
feed([[:call feedkeys(":%s/tw/MO/g\<CR>")<CR>]])
- wait()
+ poke_eventloop()
eq(1, eval("bufnr('$')"))
-- sanity check: assert the buffer state
expect(default_text:gsub("tw", "MO"))
@@ -194,7 +194,7 @@ describe(":substitute, 'inccommand' preserves", function()
-- Start typing an incomplete :substitute command.
feed([[:%s/e/YYYY/g]])
- wait()
+ poke_eventloop()
-- Cancel the :substitute.
feed([[<C-\><C-N>]])
@@ -230,7 +230,7 @@ describe(":substitute, 'inccommand' preserves", function()
-- Start typing an incomplete :substitute command.
feed([[:%s/e/YYYY/g]])
- wait()
+ poke_eventloop()
-- Cancel the :substitute.
feed([[<C-\><C-N>]])
@@ -251,7 +251,7 @@ describe(":substitute, 'inccommand' preserves", function()
some text 1
some text 2]])
feed(":%s/e/XXX/")
- wait()
+ poke_eventloop()
eq(expected_tick, eval("b:changedtick"))
end)
@@ -1128,15 +1128,15 @@ describe(":substitute, inccommand=split", function()
feed(":%s/tw/Xo/g")
-- Delete and re-type the g a few times.
feed("<BS>")
- wait()
+ poke_eventloop()
feed("g")
- wait()
+ poke_eventloop()
feed("<BS>")
- wait()
+ poke_eventloop()
feed("g")
- wait()
+ poke_eventloop()
feed("<CR>")
- wait()
+ poke_eventloop()
feed(":vs tmp<enter>")
eq(3, helpers.call('bufnr', '$'))
end)
@@ -1171,7 +1171,7 @@ describe(":substitute, inccommand=split", function()
feed_command("silent edit! test/functional/fixtures/bigfile_oneline.txt")
-- Start :substitute with a slow pattern.
feed([[:%s/B.*N/x]])
- wait()
+ poke_eventloop()
-- Assert that 'inccommand' is DISABLED in cmdline mode.
eq("", eval("&inccommand"))
@@ -1360,7 +1360,7 @@ describe("inccommand=nosplit", function()
feed("<Esc>")
command("set icm=nosplit")
feed(":%s/tw/OKOK")
- wait()
+ poke_eventloop()
screen:expect([[
Inc substitution on |
{12:OKOK}o lines |
@@ -2592,7 +2592,7 @@ describe(":substitute", function()
feed("<C-c>")
feed('gg')
- wait()
+ poke_eventloop()
feed([[:%s/\(some\)\@<lt>!thing/one/]])
screen:expect([[
something |
@@ -2613,7 +2613,7 @@ describe(":substitute", function()
]])
feed([[<C-c>]])
- wait()
+ poke_eventloop()
feed([[:%s/some\(thing\)\@=/every/]])
screen:expect([[
{12:every}thing |
@@ -2634,7 +2634,7 @@ describe(":substitute", function()
]])
feed([[<C-c>]])
- wait()
+ poke_eventloop()
feed([[:%s/some\(thing\)\@!/every/]])
screen:expect([[
something |
@@ -2718,7 +2718,7 @@ it(':substitute with inccommand during :terminal activity', function()
feed('gg')
feed(':%s/foo/ZZZ')
sleep(20) -- Allow some terminal activity.
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect_unchanged()
end)
end)
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index d857b57a31..a741136111 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -546,7 +546,7 @@ describe('ui/mouse/input', function()
:tabprevious |
]])
feed('<LeftMouse><10,0><LeftRelease>') -- go to second tab
- helpers.wait()
+ helpers.poke_eventloop()
feed('<LeftMouse><0,1>')
screen:expect([[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index e4d1187dea..6601c2d68e 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -4,7 +4,7 @@ local clear = helpers.clear
local feed, command, insert = helpers.feed, helpers.command, helpers.insert
local eq = helpers.eq
local meths = helpers.meths
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('ext_multigrid', function()
@@ -1846,8 +1846,8 @@ describe('ext_multigrid', function()
meths.input_mouse('left', 'press', '', 1,6, 20)
-- TODO(bfredl): "batching" input_mouse is formally not supported yet.
-- Normally it should work fine in async context when nvim is not blocked,
- -- but add a wait be sure.
- wait()
+ -- but add a poke_eventloop be sure.
+ poke_eventloop()
meths.input_mouse('left', 'drag', '', 1, 4, 20)
screen:expect{grid=[[
## grid 1
@@ -1921,7 +1921,7 @@ describe('ext_multigrid', function()
]]}
meths.input_mouse('left', 'press', '', 1,8, 26)
- wait()
+ poke_eventloop()
meths.input_mouse('left', 'drag', '', 1, 6, 30)
screen:expect{grid=[[
## grid 1
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index c1c5d1ce2e..3f984ff943 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -1213,10 +1213,10 @@ describe('builtin popupmenu', function()
funcs.complete(29, {'word', 'choice', 'text', 'thing'})
screen:expect([[
some long prefix before the ^ |
- {n:word }{1: }|
- {n:choice }{1: }|
- {n:text }{1: }|
- {n:thing }{1: }|
+ {1:~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{n: text }|
+ {1:~ }{n: thing }|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -1261,10 +1261,10 @@ describe('builtin popupmenu', function()
feed('<c-p>')
screen:expect([[
some long prefix before the text|
- {n:^word }{1: }|
- {n:choice }{1: }|
- {s:text }{1: }|
- {n:thing }{1: }|
+ {1:^~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{s: text }|
+ {1:~ }{n: thing }|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -1341,10 +1341,10 @@ describe('builtin popupmenu', function()
screen:expect([[
some long prefix |
before the text^ |
- {1:~ }{n: word }|
- {1:~ }{n: choice }|
- {1:~ }{s: text }|
- {1:~ }{n: thing }|
+ {1:~ }{n: word }{1: }|
+ {1:~ }{n: choice }{1: }|
+ {1:~ }{s: text }{1: }|
+ {1:~ }{n: thing }{1: }|
{1:~ }|
{2:-- INSERT --} |
]])
@@ -1358,10 +1358,10 @@ describe('builtin popupmenu', function()
funcs.complete(29, {'word', 'choice', 'text', 'thing'})
screen:expect([[
some long prefix before the ^ |
- {n:word }{1: }|
- {n:choice }{1: }|
- {n:text }{1: }|
- {n:thing }{1: }|
+ {1:~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{n: text }|
+ {1:~ }{n: thing }|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -2168,8 +2168,8 @@ describe('builtin popupmenu', function()
funcs.complete(29, {'word', 'choice', 'text', 'thing'})
screen:expect([[
some long prefix before the ^ |
- {n:word }{c: }{1: }|
- {n:choice }{s: }{1: }|
+ {1:~ }{n: word }{c: }|
+ {1:~ }{n: choice}{s: }|
{1:~ }|
{1:~ }|
{1:~ }|
@@ -2187,10 +2187,10 @@ describe('builtin popupmenu', function()
funcs.complete(29, {'word', 'choice', 'text', 'thing'})
screen:expect([[
some long prefix before the ^ |
- {n:word }{1: }|
- {n:choice }{1: }|
- {n:text }{1: }|
- {n:thing }{1: }|
+ {1:~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{n: text }|
+ {1:~ }{n: thing }|
{1:~ }|
{1:~ }|
{2:-- INSERT --} |
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 635ce7392b..222275eb4d 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -158,7 +158,7 @@ describe('search highlighting', function()
bar foo baz
]])
feed('/foo')
- helpers.wait()
+ helpers.poke_eventloop()
screen:expect_unchanged()
end)
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index 9d4cb325d9..01fc50289d 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -6,7 +6,7 @@ local feed_command, source, expect = helpers.feed_command, helpers.source, helpe
local curbufmeths = helpers.curbufmeths
local command = helpers.command
local meths = helpers.meths
-local wait = helpers.wait
+local poke_eventloop = helpers.poke_eventloop
describe('completion', function()
local screen
@@ -737,8 +737,8 @@ describe('completion', function()
-- Does not indent when "ind" is typed.
feed("in<C-X><C-N>")
-- Completion list is generated incorrectly if we send everything at once
- -- via nvim_input(). So wait() before sending <BS>. #8480
- wait()
+ -- via nvim_input(). So poke_eventloop() before sending <BS>. #8480
+ poke_eventloop()
feed("<BS>d")
screen:expect([[
@@ -778,7 +778,7 @@ describe('completion', function()
]])
-- Works for unindenting too.
feed("ounin<C-X><C-N>")
- helpers.wait()
+ helpers.poke_eventloop()
feed("<BS>d")
screen:expect([[
inc uninc indent unindent |
@@ -1000,65 +1000,65 @@ describe('completion', function()
command('let g:foo = []')
feed('o')
- wait()
+ poke_eventloop()
feed('<esc>')
eq({'I'}, eval('g:foo'))
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
eq({'I', 'I'}, eval('g:foo'))
feed('<esc>')
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
eq({'I', 'I', 'P'}, eval('g:foo'))
feed('<esc>')
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
eq({'I', 'I', 'P', 'P'}, eval('g:foo'))
feed('<esc>')
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
eq({'I', 'I', 'P', 'P', 'P'}, eval('g:foo'))
feed('<esc>')
command('let g:foo = []')
feed('S')
- wait()
+ poke_eventloop()
feed('f')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
- wait()
+ poke_eventloop()
feed('<C-N>')
eq({'I', 'I', 'P', 'P', 'P', 'P'}, eval('g:foo'))
feed('<esc>')
diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/viml/errorlist_spec.lua
index c5390cbd12..9acc61e398 100644
--- a/test/functional/viml/errorlist_spec.lua
+++ b/test/functional/viml/errorlist_spec.lua
@@ -27,7 +27,7 @@ describe('setqflist()', function()
setqflist({''}, 'r', 'foo')
command('copen')
eq('foo', get_cur_win_var('quickfix_title'))
- setqflist({''}, 'r', {['title'] = 'qf_title'})
+ setqflist({}, 'r', {['title'] = 'qf_title'})
eq('qf_title', get_cur_win_var('quickfix_title'))
end)
diff --git a/test/helpers.lua b/test/helpers.lua
index 5acd2ea0bd..68f0c92244 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -116,8 +116,12 @@ function module.assert_log(pat, logfile)
pat, nrlines, logfile, logtail))
end
--- Invokes `fn` and returns the error string (may truncate full paths), or
--- raises an error if `fn` succeeds.
+-- Invokes `fn` and returns the error string (with truncated paths), or raises
+-- an error if `fn` succeeds.
+--
+-- Replaces line/column numbers with zero:
+-- shared.lua:0: in function 'gsplit'
+-- shared.lua:0: in function <shared.lua:0>'
--
-- Usage:
-- -- Match exact string.
@@ -125,29 +129,36 @@ end
-- -- Match Lua pattern.
-- matches('e[or]+$', pcall_err(function(a, b) error('some error') end, 'arg1', 'arg2'))
--
-function module.pcall_err(fn, ...)
+function module.pcall_err_withfile(fn, ...)
assert(type(fn) == 'function')
local status, rv = pcall(fn, ...)
if status == true then
error('expected failure, but got success')
end
- -- From this:
- -- /home/foo/neovim/runtime/lua/vim/shared.lua:186: Expected string, got number
- -- to this:
- -- Expected string, got number
- local errmsg = tostring(rv):gsub('^[^:]+:%d+: ', '')
- -- From this:
- -- Error executing lua: /very/long/foo.lua:186: Expected string, got number
- -- to this:
- -- Error executing lua: .../foo.lua:186: Expected string, got number
- errmsg = errmsg:gsub([[lua: [a-zA-Z]?:?[^:]-[/\]([^:/\]+):%d+: ]], 'lua: .../%1: ')
- -- Compiled modules will not have a path and will just be a name like
- -- shared.lua:186, so strip the number.
- errmsg = errmsg:gsub([[lua: ([^:/\ ]+):%d+: ]], 'lua: .../%1: ')
- -- ^ Windows drive-letter (C:)
+ -- From:
+ -- C:/long/path/foo.lua:186: Expected string, got number
+ -- to:
+ -- .../foo.lua:0: Expected string, got number
+ local errmsg = tostring(rv):gsub('[^%s]-[/\\]([^%s:/\\]+):%d+', '.../%1:0')
+ -- Scrub numbers in paths/stacktraces:
+ -- shared.lua:0: in function 'gsplit'
+ -- shared.lua:0: in function <shared.lua:0>'
+ errmsg = errmsg:gsub('([^%s]):%d+', '%1:0')
+ -- Scrub tab chars:
+ errmsg = errmsg:gsub('\t', ' ')
+ -- In Lua 5.1, we sometimes get a "(tail call): ?" on the last line.
+ -- We remove this so that the tests are not lua dependent.
+ errmsg = errmsg:gsub('%s*%(tail call%): %?', '')
+
return errmsg
end
+function module.pcall_err(fn, ...)
+ local errmsg = module.pcall_err_withfile(fn, ...)
+
+ return errmsg:gsub('.../helpers.lua:0: ', '')
+end
+
-- initial_path: directory to recurse into
-- re: include pattern (string)
-- exc_re: exclude pattern(s) (string or table)
diff --git a/test/symbolic/klee/nvim/charset.c b/test/symbolic/klee/nvim/charset.c
index 95853a6834..f9bc3fabc4 100644
--- a/test/symbolic/klee/nvim/charset.c
+++ b/test/symbolic/klee/nvim/charset.c
@@ -69,7 +69,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
&& !STRING_ENDED(ptr + 1)
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
pre = ptr[1];
- // Detect hexadecimal: 0x or 0X follwed by hex digit
+ // Detect hexadecimal: 0x or 0X followed by hex digit
if ((what & STR2NR_HEX)
&& !STRING_ENDED(ptr + 2)
&& (pre == 'X' || pre == 'x')
@@ -77,7 +77,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
ptr += 2;
goto vim_str2nr_hex;
}
- // Detect binary: 0b or 0B follwed by 0 or 1
+ // Detect binary: 0b or 0B followed by 0 or 1
if ((what & STR2NR_BIN)
&& !STRING_ENDED(ptr + 2)
&& (pre == 'B' || pre == 'b')