aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRom Grk <romgrk.cc@gmail.com>2020-11-03 03:11:08 -0500
committerRom Grk <romgrk.cc@gmail.com>2020-11-03 03:11:08 -0500
commit13e0ca3e194a438383b8451e19090355aa6c29dc (patch)
tree0ac33ef5ac829b7c74dd15f34b17540c3186c356
parentc7c865214655f7d88fde85ed4947f07319c14182 (diff)
parent5b5848f2fb1f4b7995bb8a59d94b6766d2182070 (diff)
downloadrneovim-13e0ca3e194a438383b8451e19090355aa6c29dc.tar.gz
rneovim-13e0ca3e194a438383b8451e19090355aa6c29dc.tar.bz2
rneovim-13e0ca3e194a438383b8451e19090355aa6c29dc.zip
Merge branch 'master' into add-scroll-events
-rw-r--r--ci/build.ps111
-rwxr-xr-xci/install.sh2
-rw-r--r--runtime/autoload/provider/clipboard.vim8
-rw-r--r--runtime/doc/api.txt11
-rw-r--r--runtime/doc/autocmd.txt9
-rw-r--r--runtime/doc/change.txt4
-rw-r--r--runtime/doc/eval.txt12
-rw-r--r--runtime/doc/if_ruby.txt9
-rw-r--r--runtime/doc/indent.txt8
-rw-r--r--runtime/doc/lsp.txt4
-rw-r--r--runtime/doc/options.txt22
-rw-r--r--runtime/doc/treesitter.txt9
-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.lua27
-rw-r--r--runtime/lua/vim/lsp/rpc.lua19
-rw-r--r--runtime/lua/vim/lsp/util.lua17
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua2
-rw-r--r--runtime/lua/vim/treesitter/query.lua2
-rw-r--r--runtime/syntax/markdown.vim66
-rwxr-xr-xscripts/vim-patch.sh12
-rw-r--r--src/nvim/api/buffer.c49
-rw-r--r--src/nvim/api/private/helpers.c38
-rw-r--r--src/nvim/api/private/helpers.h3
-rw-r--r--src/nvim/api/vim.c114
-rw-r--r--src/nvim/api/window.c4
-rw-r--r--src/nvim/auevents.lua3
-rw-r--r--src/nvim/buffer.c235
-rw-r--r--src/nvim/buffer_defs.h32
-rw-r--r--src/nvim/change.c9
-rw-r--r--src/nvim/cursor.c2
-rw-r--r--src/nvim/diff.c4
-rw-r--r--src/nvim/edit.c112
-rw-r--r--src/nvim/eval.c11
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/funcs.c47
-rw-r--r--src/nvim/eval/userfunc.c8
-rw-r--r--src/nvim/ex_cmds.c6
-rw-r--r--src/nvim/ex_cmds2.c3
-rw-r--r--src/nvim/ex_docmd.c69
-rw-r--r--src/nvim/ex_getln.c21
-rw-r--r--src/nvim/ex_session.c6
-rw-r--r--src/nvim/extmark_defs.h5
-rw-r--r--src/nvim/fold.c2
-rw-r--r--src/nvim/generators/gen_options.lua9
-rw-r--r--src/nvim/globals.h10
-rw-r--r--src/nvim/hashtab.h1
-rw-r--r--src/nvim/highlight.c213
-rw-r--r--src/nvim/highlight_defs.h15
-rw-r--r--src/nvim/indent.c17
-rw-r--r--src/nvim/indent_c.c16
-rw-r--r--src/nvim/lua/executor.c27
-rw-r--r--src/nvim/lua/treesitter.c32
-rw-r--r--src/nvim/lua/vim.lua93
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/map.c18
-rw-r--r--src/nvim/map.h2
-rw-r--r--src/nvim/mbyte.c140
-rw-r--r--src/nvim/menu.c2
-rw-r--r--src/nvim/message.c4
-rw-r--r--src/nvim/mouse.c6
-rw-r--r--src/nvim/move.c41
-rw-r--r--src/nvim/msgpack_rpc/channel.c6
-rw-r--r--src/nvim/normal.c22
-rw-r--r--src/nvim/ops.c115
-rw-r--r--src/nvim/option.c42
-rw-r--r--src/nvim/option_defs.h10
-rw-r--r--src/nvim/options.lua9
-rw-r--r--src/nvim/os/os_defs.h5
-rw-r--r--src/nvim/popupmnu.c86
-rw-r--r--src/nvim/quickfix.c3
-rw-r--r--src/nvim/screen.c67
-rw-r--r--src/nvim/search.c2
-rw-r--r--src/nvim/spell.c4
-rw-r--r--src/nvim/spell_defs.h1
-rw-r--r--src/nvim/spellfile.c35
-rw-r--r--src/nvim/syntax.c94
-rw-r--r--src/nvim/tag.c2
-rw-r--r--src/nvim/terminal.c4
-rw-r--r--src/nvim/testdir/test_autocmd.vim13
-rw-r--r--src/nvim/testdir/test_cindent.vim36
-rw-r--r--src/nvim/testdir/test_cjk_linebreak.vim97
-rw-r--r--src/nvim/testdir/test_cmdline.vim21
-rw-r--r--src/nvim/testdir/test_edit.vim18
-rw-r--r--src/nvim/testdir/test_filetype.vim2
-rw-r--r--src/nvim/testdir/test_ins_complete.vim86
-rw-r--r--src/nvim/testdir/test_listdict.vim4
-rw-r--r--src/nvim/testdir/test_messages.vim24
-rw-r--r--src/nvim/testdir/test_mksession.vim13
-rw-r--r--src/nvim/testdir/test_options.vim1
-rw-r--r--src/nvim/testdir/test_quickfix.vim4
-rw-r--r--src/nvim/testdir/test_registers.vim69
-rw-r--r--src/nvim/testdir/test_ruby.vim197
-rw-r--r--src/nvim/testdir/test_statusline.vim15
-rw-r--r--src/nvim/tui/tui.c17
-rw-r--r--src/nvim/types.h2
-rw-r--r--src/nvim/ui_compositor.c1
-rw-r--r--src/nvim/undo.c2
-rw-r--r--src/nvim/vim.h1
-rw-r--r--src/nvim/window.c68
-rw-r--r--test/functional/api/buffer_spec.lua20
-rw-r--r--test/functional/core/startup_spec.lua22
-rw-r--r--test/functional/eval/null_spec.lua2
-rw-r--r--test/functional/ex_cmds/packadd_spec.lua74
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua20
-rw-r--r--test/functional/fixtures/pack/foo/opt/bonus/autoload/bonus.vim3
-rw-r--r--test/functional/fixtures/pack/foo/opt/bonus/lua/bonus.lua1
-rw-r--r--test/functional/fixtures/pack/foo/start/bar/autoload/bar.vim3
-rw-r--r--test/functional/fixtures/pack/foo/start/bar/lua/bar.lua1
-rw-r--r--test/functional/helpers.lua8
-rw-r--r--test/functional/legacy/055_list_and_dict_types_spec.lua4
-rw-r--r--test/functional/legacy/cmdline_spec.lua66
-rw-r--r--test/functional/lua/overrides_spec.lua115
-rw-r--r--test/functional/lua/treesitter_spec.lua22
-rw-r--r--test/functional/plugin/lsp_spec.lua70
-rw-r--r--test/functional/provider/ruby_spec.lua22
-rw-r--r--test/functional/ui/cmdline_spec.lua32
-rw-r--r--test/functional/ui/decorations_spec.lua142
-rw-r--r--test/functional/ui/popupmenu_spec.lua44
-rw-r--r--test/functional/ui/screen.lua4
-rw-r--r--test/unit/buffer_spec.lua40
-rw-r--r--third-party/cmake/GetBinaryDeps.cmake1
124 files changed, 2627 insertions, 1158 deletions
diff --git a/ci/build.ps1 b/ci/build.ps1
index 36570be7ae..dbc43aecf3 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -91,7 +91,14 @@ if ($compiler -eq 'MINGW') {
& C:\msys64\usr\bin\mkdir -p /var/cache/pacman/pkg
# Build third-party dependencies
- C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Su" ; exitIfFailed
+ C:\msys64\usr\bin\bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz" ; exitIfFailed
+ C:\msys64\usr\bin\bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig" ; exitIfFailed
+ C:\msys64\usr\bin\bash -lc "pacman-key --verify msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig" ; exitIfFailed
+ C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -U msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz" ; exitIfFailed
+ # If there are still processes using msys-2.0.dll, after the base system update is finished, it will wait for input from the user.
+ # To prevent this, we will terminate all processes that use msys-2.0.dll.
+ Get-Process | Where-Object { $_.path -like 'C:\msys64*' } | Stop-Process
+ C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Syu" ; exitIfFailed
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S $mingwPackages" ; exitIfFailed
}
elseif ($compiler -eq 'MSVC') {
@@ -116,7 +123,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/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 275d18a5a9..c2195fa02d 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -91,19 +91,19 @@ function! provider#clipboard#Executable() abort
let s:paste['*'] = s:paste['+']
let s:cache_enabled = 0
return 'pbcopy'
- elseif exists('$WAYLAND_DISPLAY') && executable('wl-copy') && executable('wl-paste')
+ elseif !empty($WAYLAND_DISPLAY) && executable('wl-copy') && executable('wl-paste')
let s:copy['+'] = ['wl-copy', '--foreground', '--type', 'text/plain']
let s:paste['+'] = ['wl-paste', '--no-newline']
let s:copy['*'] = ['wl-copy', '--foreground', '--primary', '--type', 'text/plain']
let s:paste['*'] = ['wl-paste', '--no-newline', '--primary']
return 'wl-copy'
- elseif exists('$DISPLAY') && executable('xclip')
+ elseif !empty($DISPLAY) && executable('xclip')
let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard']
let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard']
let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary']
let s:paste['*'] = ['xclip', '-o', '-selection', 'primary']
return 'xclip'
- elseif exists('$DISPLAY') && executable('xsel') && s:cmd_ok('xsel -o -b')
+ elseif !empty($DISPLAY) && executable('xsel') && s:cmd_ok('xsel -o -b')
let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b']
let s:paste['+'] = ['xsel', '-o', '-b']
let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p']
@@ -132,7 +132,7 @@ function! provider#clipboard#Executable() abort
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
return 'win32yank'
- elseif exists('$TMUX') && executable('tmux')
+ elseif !empty($TMUX) && executable('tmux')
let s:copy['+'] = ['tmux', 'load-buffer', '-']
let s:paste['+'] = ['tmux', 'save-buffer', '-']
let s:copy['*'] = s:copy['+']
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 083128ab80..0c726ddd86 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1783,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.
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 75cdc71039..66d15d446a 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 a710ef5d14..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}...])
@@ -7070,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
diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt
index 87047712f3..c8d2409549 100644
--- a/runtime/doc/if_ruby.txt
+++ b/runtime/doc/if_ruby.txt
@@ -185,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/indent.txt b/runtime/doc/indent.txt
index 1df0331239..f2278f8453 100644
--- a/runtime/doc/indent.txt
+++ b/runtime/doc/indent.txt
@@ -566,9 +566,15 @@ The examples below assume a 'shiftwidth' of 4.
with "#" does not work.
+ PN When N is non-zero recognize C pragmas, and indent them like any
+ other code; does not concern other preprocessor directives.
+ When N is zero (default): don't recognize C pragmas, treating
+ them like every other preprocessor directive.
+
+
The defaults, spelled out in full, are:
cinoptions=>s,e0,n0,f0,{0,}0,^0,L-1,:s,=s,l0,b0,gs,hs,N0,E0,ps,ts,is,+s,
- c3,C0,/0,(2s,us,U0,w0,W0,k0,m0,j0,J0,)20,*70,#0
+ c3,C0,/0,(2s,us,U0,w0,W0,k0,m0,j0,J0,)20,*70,#0,P0
Vim puts a line in column 1 if:
- It starts with '#' (preprocessor directives), if 'cinkeys' contains '#0'.
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 5a61017b1d..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
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index beb5e9f4c2..b83d2c4484 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1386,6 +1386,21 @@ A jump table for the options with a short description can be found at |Q_op|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
+ *'completeslash'* *'csl'*
+'completeslash' 'csl' string (default: "")
+ local to buffer
+ {not in Vi} {only for MS-Windows}
+ When this option is set it overrules 'shellslash' for completion:
+ - When this option is set to "slash", a forward slash is used for path
+ completion in insert mode. This is useful when editing HTML tag, or
+ Makefile with 'noshellslash' on Windows.
+ - When this option is set to "backslash", backslash is used. This is
+ useful when editing a batch file with 'shellslash' set on Windows.
+ - When this option is empty, same character is used as for
+ 'shellslash'.
+ For Insert mode completion the buffer-local value is used. For
+ command line completion the global value is used.
+
*'completeopt'* *'cot'*
'completeopt' 'cot' string (default: "menu,preview")
global
@@ -2903,6 +2918,8 @@ A jump table for the options with a short description can be found at |Q_op|.
*'go-c'*
'c' Use console dialogs instead of popup dialogs for simple
choices.
+ *'go-d'*
+ 'd' Use dark theme variant if available.
*'go-e'*
'e' Add tab pages when indicated with 'showtabline'.
'guitablabel' can be used to change the text in the labels.
@@ -5289,7 +5306,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'shellslash' only works when a backslash can be used as a path
separator. To test if this is so use: >
if exists('+shellslash')
-<
+< Also see 'completeslash'.
+
*'shelltemp'* *'stmp'* *'noshelltemp'* *'nostmp'*
'shelltemp' 'stmp' boolean (Vim default on, Vi default off)
global
@@ -5779,7 +5797,7 @@ A jump table for the options with a short description can be found at |Q_op|.
normal text. Each status line item is of the form:
%-0{minwid}.{maxwid}{item}
All fields except the {item} are optional. A single percent sign can
- be given as "%%". Up to 80 items can be specified. *E541*
+ be given as "%%".
When the option starts with "%!" then it is used as an expression,
evaluated and the result is used as the option value. Example: >
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 7f644486f7..aaf13d1640 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -136,6 +136,15 @@ tsnode:has_error() *tsnode:has_error()*
tsnode:sexpr() *tsnode:sexpr()*
Get an S-expression representing the node as a string.
+tsnode:id() *tsnode:id()*
+ Get an unique identier for the node inside its own tree.
+
+ No guarantees are made about this identifer's internal representation,
+ except for being a primitive lua type with value equality (so not a table).
+ Presently it is a (non-printable) string.
+
+ NB: the id is not guaranteed to be unique for nodes from different trees.
+
tsnode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
*tsnode:descendant_for_range()*
Get the smallest node within this node that spans the given range of
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..1a0015e2db 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..70862320c5 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -632,15 +632,18 @@ function protocol.make_client_capabilities()
codeActionLiteralSupport = {
codeActionKind = {
- valueSet = {};
+ valueSet = vim.tbl_values(protocol.CodeActionKind);
};
};
};
completion = {
dynamicRegistration = false;
completionItem = {
+ -- Until we can actually expand snippet, move cursor and allow for true snippet experience,
+ -- this should be disabled out of the box.
+ -- However, users can turn this back on if they have a snippet plugin.
+ snippetSupport = false;
- snippetSupport = true;
commitCharactersSupport = false;
preselectSupport = false;
deprecatedSupport = false;
@@ -703,6 +706,10 @@ function protocol.make_client_capabilities()
};
hierarchicalDocumentSymbolSupport = true;
};
+ rename = {
+ dynamicRegistration = false;
+ prepareSupport = true;
+ };
};
workspace = {
symbol = {
@@ -914,6 +921,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,14 +931,21 @@ 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
- elseif type(server_capabilities.codeActionProvider) == 'boolean' then
+ elseif type(server_capabilities.codeActionProvider) == 'boolean'
+ or type(server_capabilities.codeActionProvider) == 'table' then
general_properties.code_action = server_capabilities.codeActionProvider
- elseif type(server_capabilities.codeActionProvider) == 'table' then
- -- TODO(ashkan) support CodeActionKind
- general_properties.code_action = false
else
error("The server sent invalid codeActionProvider")
end
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 749a51fecc..17c411f952 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -42,13 +42,28 @@ local function is_dir(filename)
end
local NIL = vim.NIL
+
+--@private
+local recursive_convert_NIL
+recursive_convert_NIL = function(v, tbl_processed)
+ if v == NIL then
+ return nil
+ elseif not tbl_processed[v] and type(v) == 'table' then
+ tbl_processed[v] = true
+ return vim.tbl_map(function(x)
+ return recursive_convert_NIL(x, tbl_processed)
+ end, v)
+ end
+
+ return v
+end
+
--@private
--- Returns its argument, but converts `vim.NIL` to Lua `nil`.
--@param v (any) Argument
--@returns (any)
local function convert_NIL(v)
- if v == NIL then return nil end
- return v
+ return recursive_convert_NIL(v, {})
end
--@private
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index b5f171a985..9ed19b938d 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -214,13 +214,16 @@ end
function M.apply_text_document_edit(text_document_edit)
local text_document = text_document_edit.textDocument
local bufnr = vim.uri_to_bufnr(text_document.uri)
- if text_document.version then
- -- `VersionedTextDocumentIdentifier`s version may be null https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier
- if text_document.version ~= vim.NIL and M.buf_versions[bufnr] ~= nil and M.buf_versions[bufnr] > text_document.version then
- print("Buffer ", text_document.uri, " newer than edits.")
- return
- end
+
+ -- `VersionedTextDocumentIdentifier`s version may be null
+ -- https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier
+ if text_document.version
+ and M.buf_versions[bufnr]
+ and M.buf_versions[bufnr] > text_document.version then
+ print("Buffer ", text_document.uri, " newer than edits.")
+ return
end
+
M.apply_text_edits(text_document_edit.edits, bufnr)
end
@@ -532,7 +535,7 @@ function M.convert_signature_help_to_markdown_lines(signature_help)
}
--]=]
-- TODO highlight parameter
- if parameter.documentation and parameter.documentation ~= vim.NIL then
+ if parameter.documentation then
M.convert_input_to_markdown_lines(parameter.documentation, contents)
end
end
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index decde08019..6714bb6354 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -157,7 +157,7 @@ local function on_line_impl(self, buf, line)
a.nvim_buf_set_extmark(buf, ns, start_row, start_col,
{ end_line = end_row, end_col = end_col,
hl_group = hl,
- ephemeral = true
+ ephemeral = true,
})
end
if start_row > line then
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 2903c5905c..cc7dc2656d 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -25,7 +25,7 @@ local function filter_files(file_list)
end
end
- return { main, unpack(after) }
+ return main and { main, unpack(after) } or after
end
local function runtime_query_path(lang, query_name)
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 8287958ab5..551b8fb691 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -211,6 +211,18 @@ preprocess_patch() {
LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
+ # Rename evalfunc.c to eval/funcs.c
+ LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/evalfunc\.c/\1\/eval\/funcs\.c/g' \
+ "$file" > "$file".tmp && mv "$file".tmp "$file"
+
+ # Rename userfunc.c to eval/userfunc.c
+ LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/userfunc\.c/\1\/eval\/userfunc\.c/g' \
+ "$file" > "$file".tmp && mv "$file".tmp "$file"
+
+ # Rename session.c to ex_session.c
+ LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/session\(\.[ch]\)/\1\/ex_session\2/g' \
+ "$file" > "$file".tmp && mv "$file".tmp "$file"
+
# Rename test_urls.vim to check_urls.vim
LC_ALL=C sed -e 's@\( [ab]\)/runtime/doc/test\(_urls.vim\)@\1/scripts/check\2@g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index c8dd85b39d..4569ebc713 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_object_to_bool(v, "force", false, err);
+ } else if (strequal("unload", k.data)) {
+ unload = api_object_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_object_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..a9b1676879 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1619,14 +1619,21 @@ 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_object_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;
@@ -1644,3 +1651,30 @@ const char *describe_ns(NS ns_id)
})
return "(UNKNOWN PLUGIN)";
}
+
+DecorationProvider *get_provider(NS ns_id, bool force)
+{
+ ssize_t i;
+ for (i = 0; i < (ssize_t)kv_size(decoration_providers); i++) {
+ DecorationProvider *item = &kv_A(decoration_providers, i);
+ if (item->ns_id == ns_id) {
+ return item;
+ } else if (item->ns_id > ns_id) {
+ break;
+ }
+ }
+
+ if (!force) {
+ return NULL;
+ }
+
+ for (ssize_t j = (ssize_t)kv_size(decoration_providers)-1; j >= i; j++) {
+ // allocates if needed:
+ (void)kv_a(decoration_providers, (size_t)j+1);
+ kv_A(decoration_providers, (size_t)j+1) = kv_A(decoration_providers, j);
+ }
+ DecorationProvider *item = &kv_a(decoration_providers, (size_t)i);
+ *item = DECORATION_PROVIDER_INIT(ns_id);
+
+ return item;
+}
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index df3a263dcf..7c6f07402b 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -52,7 +52,8 @@
.type = kObjectTypeLuaRef, \
.data.luaref = r })
-#define NIL ((Object) {.type = kObjectTypeNil})
+#define NIL ((Object)OBJECT_INIT)
+#define NULL_STRING ((String)STRING_INIT)
#define PUT(dict, k, v) \
kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v }))
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 876b052a8e..725847886a 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -199,6 +199,69 @@ Integer nvim_get_hl_id_by_name(String name)
return syn_check_group((const char_u *)name.data, (int)name.size);
}
+Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
+{
+ if (ns_id == 0) {
+ return get_global_hl_defs();
+ }
+ abort();
+}
+
+/// Set a highlight group.
+///
+/// @param ns_id number of namespace for this highlight
+/// @param name highlight group name, like ErrorMsg
+/// @param val highlight definiton map, like |nvim_get_hl_by_name|.
+/// @param[out] err Error details, if any
+///
+/// TODO: ns_id = 0, should modify :highlight namespace
+/// TODO val should take update vs reset flag
+void nvim_set_hl(Integer ns_id, String name, Dictionary val, Error *err)
+ FUNC_API_SINCE(7)
+{
+ int hl_id = syn_check_group( (char_u *)(name.data), (int)name.size);
+ int link_id = -1;
+
+ HlAttrs attrs = dict2hlattrs(val, true, &link_id, err);
+ if (!ERROR_SET(err)) {
+ ns_hl_def((NS)ns_id, hl_id, attrs, link_id);
+ }
+}
+
+/// Set active namespace for highlights.
+///
+/// NB: this function can be called from async contexts, but the
+/// semantics are not yet well-defined. To start with
+/// |nvim_set_decoration_provider| on_win and on_line callbacks
+/// are explicitly allowed to change the namespace during a redraw cycle.
+///
+/// @param ns_id the namespace to activate
+/// @param[out] err Error details, if any
+void nvim_set_hl_ns(Integer ns_id, Error *err)
+ FUNC_API_SINCE(7)
+ FUNC_API_FAST
+{
+ if (ns_id >= 0) {
+ ns_hl_active = (NS)ns_id;
+ }
+
+ // TODO(bfredl): this is a little bit hackish. Eventually we want a standard
+ // event path for redraws caused by "fast" events. This could tie in with
+ // better throttling of async events causing redraws, such as non-batched
+ // nvim_buf_set_extmark calls from async contexts.
+ if (!updating_screen && !ns_hl_changed) {
+ multiqueue_put(main_loop.events, on_redraw_event, 0);
+ }
+ ns_hl_changed = true;
+}
+
+static void on_redraw_event(void **argv)
+ FUNC_API_NOEXPORT
+{
+ redraw_all_later(NOT_VALID);
+}
+
+
/// Sends input-keys to Nvim, subject to various quirks controlled by `mode`
/// flags. This is a blocking call, unlike |nvim_input()|.
///
@@ -678,7 +741,11 @@ Integer nvim_strwidth(String text, Error *err)
ArrayOf(String) nvim_list_runtime_paths(void)
FUNC_API_SINCE(1)
{
+ // TODO(bfredl): this should just work:
+ // return nvim_get_runtime_file(NULL_STRING, true);
+
Array rv = ARRAY_DICT_INIT;
+
char_u *rtp = p_rtp;
if (*rtp == NUL) {
@@ -725,22 +792,29 @@ ArrayOf(String) nvim_list_runtime_paths(void)
/// @param name pattern of files to search for
/// @param all whether to return all matches or only the first
/// @return list of absolute paths to the found files
-ArrayOf(String) nvim_get_runtime_file(String name, Boolean all)
+ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Error *err)
FUNC_API_SINCE(7)
{
Array rv = ARRAY_DICT_INIT;
- if (!name.data) {
+
+ // TODO(bfredl):
+ if (name.size == 0) {
+ api_set_error(err, kErrorTypeValidation, "not yet implemented");
return rv;
}
+
int flags = DIP_START | (all ? DIP_ALL : 0);
- do_in_runtimepath((char_u *)name.data, flags, find_runtime_cb, &rv);
+ do_in_runtimepath(name.size ? (char_u *)name.data : NULL,
+ flags, find_runtime_cb, &rv);
return rv;
}
static void find_runtime_cb(char_u *fname, void *cookie)
{
Array *rv = (Array *)cookie;
- ADD(*rv, STRING_OBJ(cstr_to_string((char *)fname)));
+ if (fname != NULL) {
+ ADD(*rv, STRING_OBJ(cstr_to_string((char *)fname)));
+ }
}
String nvim__get_lib_dir(void)
@@ -1477,7 +1551,7 @@ void nvim_unsubscribe(uint64_t channel_id, String event)
Integer nvim_get_color_by_name(String name)
FUNC_API_SINCE(1)
{
- return name_to_color((char_u *)name.data);
+ return name_to_color(name.data);
}
/// Returns a map of color names and RGB values.
@@ -2610,33 +2684,6 @@ void nvim__screenshot(String path)
ui_call_screenshot(path);
}
-static DecorationProvider *get_provider(NS ns_id, bool force)
-{
- ssize_t i;
- for (i = 0; i < (ssize_t)kv_size(decoration_providers); i++) {
- DecorationProvider *item = &kv_A(decoration_providers, i);
- if (item->ns_id == ns_id) {
- return item;
- } else if (item->ns_id > ns_id) {
- break;
- }
- }
-
- if (!force) {
- return NULL;
- }
-
- for (ssize_t j = (ssize_t)kv_size(decoration_providers)-1; j >= i; j++) {
- // allocates if needed:
- (void)kv_a(decoration_providers, (size_t)j+1);
- kv_A(decoration_providers, (size_t)j+1) = kv_A(decoration_providers, j);
- }
- DecorationProvider *item = &kv_a(decoration_providers, (size_t)i);
- *item = DECORATION_PROVIDER_INIT(ns_id);
-
- return item;
-}
-
static void clear_provider(DecorationProvider *p)
{
NLUA_CLEAR_REF(p->redraw_start);
@@ -2695,7 +2742,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
clear_provider(p);
// regardless of what happens, it seems good idea to redraw
- redraw_later(NOT_VALID); // TODO(bfredl): too soon?
+ redraw_all_later(NOT_VALID); // TODO(bfredl): too soon?
struct {
const char *name;
@@ -2706,6 +2753,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
{ "on_win", &p->redraw_win },
{ "on_line", &p->redraw_line },
{ "on_end", &p->redraw_end },
+ { "_on_hl_def", &p->hl_def },
{ NULL, NULL },
};
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index ba43bc6cb2..f09a03f592 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -142,7 +142,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
// make sure cursor is in visible range even if win != curwin
update_topline_win(win);
- redraw_win_later(win, VALID);
+ redraw_later(win, VALID);
}
/// Gets the window height
@@ -471,7 +471,7 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err)
if (!win_new_float(win, fconfig, err)) {
return;
}
- redraw_later(NOT_VALID);
+ redraw_later(win, NOT_VALID);
} else {
win_config_float(win, fconfig);
win->w_pos_changed = true;
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index ea2db41668..9c28398f5b 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 8f631ae13b..469542ec9f 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1623,7 +1623,7 @@ void enter_buffer(buf_T *buf)
}
curbuf->b_last_used = time(NULL);
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
// Change to the directory of the current buffer.
@@ -3440,31 +3440,17 @@ int build_stl_str_hl(
int use_sandbox,
char_u fillchar,
int maxwidth,
- struct stl_hlrec *hltab,
- StlClickRecord *tabtab
+ stl_hlrec_t **hltab,
+ StlClickRecord **tabtab
)
{
- int groupitems[STL_MAX_ITEM];
- struct stl_item {
- // Where the item starts in the status line output buffer
- char_u *start;
- // Function to run for ClickFunc items.
- char *cmd;
- // The minimum width of the item
- int minwid;
- // The maximum width of the item
- int maxwid;
- enum {
- Normal,
- Empty,
- Group,
- Separate,
- Highlight,
- TabPage,
- ClickFunc,
- Trunc
- } type;
- } items[STL_MAX_ITEM];
+ static size_t stl_items_len = 20; // Initial value, grows as needed.
+ static stl_item_t *stl_items = NULL;
+ static int *stl_groupitems = NULL;
+ static stl_hlrec_t *stl_hltab = NULL;
+ static StlClickRecord *stl_tabtab = NULL;
+ static int *stl_separator_locations = NULL;
+
#define TMPLEN 70
char_u buf_tmp[TMPLEN];
char_u win_tmp[TMPLEN];
@@ -3472,6 +3458,14 @@ int build_stl_str_hl(
const int save_must_redraw = must_redraw;
const int save_redr_type = curwin->w_redr_type;
+ if (stl_items == NULL) {
+ stl_items = xmalloc(sizeof(stl_item_t) * stl_items_len);
+ stl_groupitems = xmalloc(sizeof(int) * stl_items_len);
+ stl_hltab = xmalloc(sizeof(stl_hlrec_t) * stl_items_len);
+ stl_tabtab = xmalloc(sizeof(stl_hlrec_t) * stl_items_len);
+ stl_separator_locations = xmalloc(sizeof(int) * stl_items_len);
+ }
+
// When the format starts with "%!" then evaluate it as an expression and
// use the result as the actual format string.
if (fmt[0] == '%' && fmt[1] == '!') {
@@ -3540,14 +3534,17 @@ int build_stl_str_hl(
// Proceed character by character through the statusline format string
// fmt_p is the current positon in the input buffer
for (char_u *fmt_p = usefmt; *fmt_p; ) {
- if (curitem == STL_MAX_ITEM) {
- // There are too many items. Add the error code to the statusline
- // to give the user a hint about what went wrong.
- if (out_p + 5 < out_end_p) {
- memmove(out_p, " E541", (size_t)5);
- out_p += 5;
- }
- break;
+ if (curitem == (int)stl_items_len) {
+ size_t new_len = stl_items_len * 3 / 2;
+
+ stl_items = xrealloc(stl_items, sizeof(stl_item_t) * new_len);
+ stl_groupitems = xrealloc(stl_groupitems, sizeof(int) * new_len);
+ stl_hltab = xrealloc(stl_hltab, sizeof(stl_hlrec_t) * new_len);
+ stl_tabtab = xrealloc(stl_tabtab, sizeof(StlClickRecord) * new_len);
+ stl_separator_locations =
+ xrealloc(stl_separator_locations, sizeof(int) * new_len);
+
+ stl_items_len = new_len;
}
if (*fmt_p != NUL && *fmt_p != '%') {
@@ -3591,16 +3588,16 @@ int build_stl_str_hl(
if (groupdepth > 0) {
continue;
}
- items[curitem].type = Separate;
- items[curitem++].start = out_p;
+ stl_items[curitem].type = Separate;
+ stl_items[curitem++].start = out_p;
continue;
}
// STL_TRUNCMARK: Where to begin truncating if the statusline is too long.
if (*fmt_p == STL_TRUNCMARK) {
fmt_p++;
- items[curitem].type = Trunc;
- items[curitem++].start = out_p;
+ stl_items[curitem].type = Trunc;
+ stl_items[curitem++].start = out_p;
continue;
}
@@ -3616,7 +3613,7 @@ int build_stl_str_hl(
// Determine how long the group is.
// Note: We set the current output position to null
// so `vim_strsize` will work.
- char_u *t = items[groupitems[groupdepth]].start;
+ char_u *t = stl_items[stl_groupitems[groupdepth]].start;
*out_p = NUL;
long group_len = vim_strsize(t);
@@ -3626,40 +3623,40 @@ int build_stl_str_hl(
// move the output pointer back to where the group started.
// Note: This erases any non-item characters that were in the group.
// Otherwise there would be no reason to do this step.
- if (curitem > groupitems[groupdepth] + 1
- && items[groupitems[groupdepth]].minwid == 0) {
+ if (curitem > stl_groupitems[groupdepth] + 1
+ && stl_items[stl_groupitems[groupdepth]].minwid == 0) {
// remove group if all items are empty and highlight group
// doesn't change
int group_start_userhl = 0;
int group_end_userhl = 0;
int n;
- for (n = groupitems[groupdepth] - 1; n >= 0; n--) {
- if (items[n].type == Highlight) {
- group_start_userhl = group_end_userhl = items[n].minwid;
+ for (n = stl_groupitems[groupdepth] - 1; n >= 0; n--) {
+ if (stl_items[n].type == Highlight) {
+ group_start_userhl = group_end_userhl = stl_items[n].minwid;
break;
}
}
- for (n = groupitems[groupdepth] + 1; n < curitem; n++) {
- if (items[n].type == Normal) {
+ for (n = stl_groupitems[groupdepth] + 1; n < curitem; n++) {
+ if (stl_items[n].type == Normal) {
break;
}
- if (items[n].type == Highlight) {
- group_end_userhl = items[n].minwid;
+ if (stl_items[n].type == Highlight) {
+ group_end_userhl = stl_items[n].minwid;
}
}
if (n == curitem && group_start_userhl == group_end_userhl) {
// empty group
out_p = t;
group_len = 0;
- for (n = groupitems[groupdepth] + 1; n < curitem; n++) {
+ for (n = stl_groupitems[groupdepth] + 1; n < curitem; n++) {
// do not use the highlighting from the removed group
- if (items[n].type == Highlight) {
- items[n].type = Empty;
+ if (stl_items[n].type == Highlight) {
+ stl_items[n].type = Empty;
}
// adjust the start position of TabPage to the next
// item position
- if (items[n].type == TabPage) {
- items[n].start = out_p;
+ if (stl_items[n].type == TabPage) {
+ stl_items[n].start = out_p;
}
}
}
@@ -3667,18 +3664,19 @@ int build_stl_str_hl(
// If the group is longer than it is allowed to be
// truncate by removing bytes from the start of the group text.
- if (group_len > items[groupitems[groupdepth]].maxwid) {
+ if (group_len > stl_items[stl_groupitems[groupdepth]].maxwid) {
// { Determine the number of bytes to remove
long n;
if (has_mbyte) {
// Find the first character that should be included.
n = 0;
- while (group_len >= items[groupitems[groupdepth]].maxwid) {
+ while (group_len >= stl_items[stl_groupitems[groupdepth]].maxwid) {
group_len -= ptr2cells(t + n);
n += (*mb_ptr2len)(t + n);
}
} else {
- n = (long)(out_p - t) - items[groupitems[groupdepth]].maxwid + 1;
+ n = (long)(out_p - t)
+ - stl_items[stl_groupitems[groupdepth]].maxwid + 1;
}
// }
@@ -3689,25 +3687,26 @@ int build_stl_str_hl(
memmove(t + 1, t + n, (size_t)(out_p - (t + n)));
out_p = out_p - n + 1;
// Fill up space left over by half a double-wide char.
- while (++group_len < items[groupitems[groupdepth]].minwid) {
+ while (++group_len < stl_items[stl_groupitems[groupdepth]].minwid) {
*out_p++ = fillchar;
}
// }
// correct the start of the items for the truncation
- for (int idx = groupitems[groupdepth] + 1; idx < curitem; idx++) {
+ for (int idx = stl_groupitems[groupdepth] + 1; idx < curitem; idx++) {
// Shift everything back by the number of removed bytes
- items[idx].start -= n;
+ stl_items[idx].start -= n;
// If the item was partially or completely truncated, set its
// start to the start of the group
- if (items[idx].start < t) {
- items[idx].start = t;
+ if (stl_items[idx].start < t) {
+ stl_items[idx].start = t;
}
}
// If the group is shorter than the minimum width, add padding characters.
- } else if (abs(items[groupitems[groupdepth]].minwid) > group_len) {
- long min_group_width = items[groupitems[groupdepth]].minwid;
+ } else if (
+ abs(stl_items[stl_groupitems[groupdepth]].minwid) > group_len) {
+ long min_group_width = stl_items[stl_groupitems[groupdepth]].minwid;
// If the group is left-aligned, add characters to the right.
if (min_group_width < 0) {
min_group_width = 0 - min_group_width;
@@ -3726,8 +3725,8 @@ int build_stl_str_hl(
// }
// Adjust item start positions
- for (int n = groupitems[groupdepth] + 1; n < curitem; n++) {
- items[n].start += group_len;
+ for (int n = stl_groupitems[groupdepth] + 1; n < curitem; n++) {
+ stl_items[n].start += group_len;
}
// Prepend the fill characters
@@ -3763,9 +3762,9 @@ int build_stl_str_hl(
// User highlight groups override the min width field
// to denote the styling to use.
if (*fmt_p == STL_USER_HL) {
- items[curitem].type = Highlight;
- items[curitem].start = out_p;
- items[curitem].minwid = minwid > 9 ? 1 : minwid;
+ stl_items[curitem].type = Highlight;
+ stl_items[curitem].start = out_p;
+ stl_items[curitem].minwid = minwid > 9 ? 1 : minwid;
fmt_p++;
curitem++;
continue;
@@ -3799,8 +3798,8 @@ int build_stl_str_hl(
if (minwid == 0) {
// %X ends the close label, go back to the previous tab label nr.
for (long n = curitem - 1; n >= 0; n--) {
- if (items[n].type == TabPage && items[n].minwid >= 0) {
- minwid = items[n].minwid;
+ if (stl_items[n].type == TabPage && stl_items[n].minwid >= 0) {
+ minwid = stl_items[n].minwid;
break;
}
}
@@ -3809,9 +3808,9 @@ int build_stl_str_hl(
minwid = -minwid;
}
}
- items[curitem].type = TabPage;
- items[curitem].start = out_p;
- items[curitem].minwid = minwid;
+ stl_items[curitem].type = TabPage;
+ stl_items[curitem].start = out_p;
+ stl_items[curitem].minwid = minwid;
fmt_p++;
curitem++;
continue;
@@ -3826,10 +3825,10 @@ int build_stl_str_hl(
if (*fmt_p != STL_CLICK_FUNC) {
break;
}
- items[curitem].type = ClickFunc;
- items[curitem].start = out_p;
- items[curitem].cmd = xmemdupz(t, (size_t)(((char *)fmt_p - t)));
- items[curitem].minwid = minwid;
+ stl_items[curitem].type = ClickFunc;
+ stl_items[curitem].start = out_p;
+ stl_items[curitem].cmd = xmemdupz(t, (size_t)(((char *)fmt_p - t)));
+ stl_items[curitem].minwid = minwid;
fmt_p++;
curitem++;
continue;
@@ -3850,11 +3849,11 @@ int build_stl_str_hl(
// Denotes the start of a new group
if (*fmt_p == '(') {
- groupitems[groupdepth++] = curitem;
- items[curitem].type = Group;
- items[curitem].start = out_p;
- items[curitem].minwid = minwid;
- items[curitem].maxwid = maxwid;
+ stl_groupitems[groupdepth++] = curitem;
+ stl_items[curitem].type = Group;
+ stl_items[curitem].start = out_p;
+ stl_items[curitem].minwid = minwid;
+ stl_items[curitem].maxwid = maxwid;
fmt_p++;
curitem++;
continue;
@@ -4149,9 +4148,9 @@ int build_stl_str_hl(
// Create a highlight item based on the name
if (*fmt_p == '#') {
- items[curitem].type = Highlight;
- items[curitem].start = out_p;
- items[curitem].minwid = -syn_namen2id(t, (int)(fmt_p - t));
+ stl_items[curitem].type = Highlight;
+ stl_items[curitem].start = out_p;
+ stl_items[curitem].minwid = -syn_namen2id(t, (int)(fmt_p - t));
curitem++;
fmt_p++;
}
@@ -4162,8 +4161,8 @@ int build_stl_str_hl(
// If we made it this far, the item is normal and starts at
// our current position in the output buffer.
// Non-normal items would have `continued`.
- items[curitem].start = out_p;
- items[curitem].type = Normal;
+ stl_items[curitem].start = out_p;
+ stl_items[curitem].type = Normal;
// Copy the item string into the output buffer
if (str != NULL && *str) {
@@ -4321,7 +4320,7 @@ int build_stl_str_hl(
// Otherwise, there was nothing to print so mark the item as empty
} else {
- items[curitem].type = Empty;
+ stl_items[curitem].type = Empty;
}
// Only free the string buffer if we allocated it.
@@ -4362,13 +4361,13 @@ int build_stl_str_hl(
// Otherwise, look for the truncation item
} else {
// Default to truncating at the first item
- trunc_p = items[0].start;
+ trunc_p = stl_items[0].start;
item_idx = 0;
for (int i = 0; i < itemcnt; i++) {
- if (items[i].type == Trunc) {
- // Truncate at %< items.
- trunc_p = items[i].start;
+ if (stl_items[i].type == Trunc) {
+ // Truncate at %< stl_items.
+ trunc_p = stl_items[i].start;
item_idx = i;
break;
}
@@ -4403,7 +4402,7 @@ int build_stl_str_hl(
// Ignore any items in the statusline that occur after
// the truncation point
for (int i = 0; i < itemcnt; i++) {
- if (items[i].start > trunc_p) {
+ if (stl_items[i].start > trunc_p) {
itemcnt = i;
break;
}
@@ -4458,12 +4457,12 @@ int build_stl_str_hl(
for (int i = item_idx; i < itemcnt; i++) {
// Items starting at or after the end of the truncated section need
// to be moved backwards.
- if (items[i].start >= trunc_end_p) {
- items[i].start -= item_offset;
+ if (stl_items[i].start >= trunc_end_p) {
+ stl_items[i].start -= item_offset;
// Anything inside the truncated area is set to start
// at the `<` truncation character.
} else {
- items[i].start = trunc_p;
+ stl_items[i].start = trunc_p;
}
}
// }
@@ -4479,7 +4478,7 @@ int build_stl_str_hl(
// figuring out how many groups there are.
int num_separators = 0;
for (int i = 0; i < itemcnt; i++) {
- if (items[i].type == Separate) {
+ if (stl_items[i].type == Separate) {
num_separators++;
}
}
@@ -4488,11 +4487,10 @@ int build_stl_str_hl(
if (num_separators) {
// Create an array of the start location for each
// separator mark.
- int separator_locations[STL_MAX_ITEM];
int index = 0;
for (int i = 0; i < itemcnt; i++) {
- if (items[i].type == Separate) {
- separator_locations[index] = i;
+ if (stl_items[i].type == Separate) {
+ stl_separator_locations[index] = i;
index++;
}
}
@@ -4504,16 +4502,17 @@ int build_stl_str_hl(
for (int i = 0; i < num_separators; i++) {
int dislocation = (i == (num_separators - 1))
? final_spaces : standard_spaces;
- char_u *seploc = items[separator_locations[i]].start + dislocation;
- STRMOVE(seploc, items[separator_locations[i]].start);
- for (char_u *s = items[separator_locations[i]].start; s < seploc; s++) {
+ char_u *start = stl_items[stl_separator_locations[i]].start;
+ char_u *seploc = start + dislocation;
+ STRMOVE(seploc, start);
+ for (char_u *s = start; s < seploc; s++) {
*s = fillchar;
}
- for (int item_idx = separator_locations[i] + 1;
+ for (int item_idx = stl_separator_locations[i] + 1;
item_idx < itemcnt;
item_idx++) {
- items[item_idx].start += dislocation;
+ stl_items[item_idx].start += dislocation;
}
}
@@ -4523,11 +4522,12 @@ int build_stl_str_hl(
// Store the info about highlighting.
if (hltab != NULL) {
- struct stl_hlrec *sp = hltab;
+ *hltab = stl_hltab;
+ stl_hlrec_t *sp = stl_hltab;
for (long l = 0; l < itemcnt; l++) {
- if (items[l].type == Highlight) {
- sp->start = items[l].start;
- sp->userhl = items[l].minwid;
+ if (stl_items[l].type == Highlight) {
+ sp->start = stl_items[l].start;
+ sp->userhl = stl_items[l].minwid;
sp++;
}
}
@@ -4537,16 +4537,17 @@ int build_stl_str_hl(
// Store the info about tab pages labels.
if (tabtab != NULL) {
- StlClickRecord *cur_tab_rec = tabtab;
+ *tabtab = stl_tabtab;
+ StlClickRecord *cur_tab_rec = stl_tabtab;
for (long l = 0; l < itemcnt; l++) {
- if (items[l].type == TabPage) {
- cur_tab_rec->start = (char *)items[l].start;
- if (items[l].minwid == 0) {
+ if (stl_items[l].type == TabPage) {
+ cur_tab_rec->start = (char *)stl_items[l].start;
+ if (stl_items[l].minwid == 0) {
cur_tab_rec->def.type = kStlClickDisabled;
cur_tab_rec->def.tabnr = 0;
} else {
- int tabnr = items[l].minwid;
- if (items[l].minwid > 0) {
+ int tabnr = stl_items[l].minwid;
+ if (stl_items[l].minwid > 0) {
cur_tab_rec->def.type = kStlClickTabSwitch;
} else {
cur_tab_rec->def.type = kStlClickTabClose;
@@ -4556,11 +4557,11 @@ int build_stl_str_hl(
}
cur_tab_rec->def.func = NULL;
cur_tab_rec++;
- } else if (items[l].type == ClickFunc) {
- cur_tab_rec->start = (char *)items[l].start;
+ } else if (stl_items[l].type == ClickFunc) {
+ cur_tab_rec->start = (char *)stl_items[l].start;
cur_tab_rec->def.type = kStlClickFuncRun;
- cur_tab_rec->def.tabnr = items[l].minwid;
- cur_tab_rec->def.func = items[l].cmd;
+ cur_tab_rec->def.tabnr = stl_items[l].minwid;
+ cur_tab_rec->def.func = stl_items[l].cmd;
cur_tab_rec++;
}
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index ba71ac6b2b..540542f409 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -361,14 +361,36 @@ struct mapblock {
sctx_T m_script_ctx; // SCTX where map was defined
};
-/*
- * Used for highlighting in the status line.
- */
+/// Used for highlighting in the status line.
+typedef struct stl_hlrec stl_hlrec_t;
struct stl_hlrec {
char_u *start;
int userhl; // 0: no HL, 1-9: User HL, < 0 for syn ID
};
+/// Used for building the status line.
+typedef struct stl_item stl_item_t;
+struct stl_item {
+ // Where the item starts in the status line output buffer
+ char_u *start;
+ // Function to run for ClickFunc items.
+ char *cmd;
+ // The minimum width of the item
+ int minwid;
+ // The maximum width of the item
+ int maxwid;
+ enum {
+ Normal,
+ Empty,
+ Group,
+ Separate,
+ Highlight,
+ TabPage,
+ ClickFunc,
+ Trunc
+ } type;
+};
+
// values for b_syn_spell: what to do with toplevel text
#define SYNSPL_DEFAULT 0 // spell check if @Spell not defined
#define SYNSPL_TOP 1 // spell check toplevel text
@@ -661,6 +683,9 @@ struct file_buffer {
char_u *b_p_com; ///< 'comments'
char_u *b_p_cms; ///< 'commentstring'
char_u *b_p_cpt; ///< 'complete'
+#ifdef BACKSLASH_IN_FILENAME
+ char_u *b_p_csl; ///< 'completeslash'
+#endif
char_u *b_p_cfu; ///< 'completefunc'
char_u *b_p_ofu; ///< 'omnifunc'
char_u *b_p_tfu; ///< 'tagfunc'
@@ -770,6 +795,7 @@ struct file_buffer {
int b_ind_cpp_namespace;
int b_ind_if_for_while;
int b_ind_cpp_extern_c;
+ int b_ind_pragma;
linenr_T b_no_eol_lnum; /* non-zero lnum when last line of next binary
* write should not have an end-of-line */
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 71614363d2..9ee987b45d 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;
}
@@ -295,7 +294,7 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
// change.
if (wp->w_p_rnu
|| (wp->w_p_cul && lnum <= wp->w_last_cursorline)) {
- redraw_win_later(wp, SOME_VALID);
+ redraw_later(wp, SOME_VALID);
}
}
}
@@ -349,7 +348,7 @@ void changed_bytes(linenr_T lnum, colnr_T col)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_p_diff && wp != curwin) {
- redraw_win_later(wp, VALID);
+ redraw_later(wp, VALID);
wlnum = diff_lnum_win(lnum, wp);
if (wlnum > 0) {
changedOneline(wp->w_buffer, wlnum);
@@ -476,7 +475,7 @@ changed_lines(
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_p_diff && wp != curwin) {
- redraw_win_later(wp, VALID);
+ redraw_later(wp, VALID);
wlnum = diff_lnum_win(lnum, wp);
if (wlnum > 0) {
changed_lines_buf(wp->w_buffer, wlnum,
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index 036ae32589..d3ffab1759 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -482,7 +482,7 @@ bool leftcol_changed(void)
if (retval)
curwin->w_set_curswant = true;
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
return retval;
}
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 3de5fc49bd..b9c293f6c8 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -643,7 +643,7 @@ void diff_redraw(bool dofold)
if (!wp->w_p_diff) {
continue;
}
- redraw_win_later(wp, SOME_VALID);
+ redraw_later(wp, SOME_VALID);
if (dofold && foldmethodIsDiff(wp)) {
foldUpdateAll(wp);
}
@@ -1415,7 +1415,7 @@ void diff_win_options(win_T *wp, int addbuf)
if (addbuf) {
diff_buf_add(wp->w_buffer);
}
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
}
/// Set options not to show diffs. For the current window or all windows.
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 5ea6716c0a..d7cca9ba36 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -4177,6 +4177,21 @@ static int ins_compl_get_exp(pos_T *ini)
EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK) {
// May change home directory back to "~".
tilde_replace(compl_pattern, num_matches, matches);
+#ifdef BACKSLASH_IN_FILENAME
+ if (curbuf->b_p_csl[0] != NUL) {
+ for (int i = 0; i < num_matches; i++) {
+ char_u *ptr = matches[i];
+ while (*ptr != NUL) {
+ if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') {
+ *ptr = '/';
+ } else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/') {
+ *ptr = '\\';
+ }
+ ptr += utfc_ptr2len(ptr);
+ }
+ }
+ }
+#endif
ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
}
break;
@@ -5555,13 +5570,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:
@@ -5762,10 +5775,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);
@@ -5844,6 +5858,7 @@ internal_format (
curwin->w_cursor.col = startcol;
foundcol = 0;
+ int skip_pos = 0;
/*
* Find position to break at.
@@ -5913,7 +5928,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
@@ -5922,8 +5941,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)
@@ -5935,6 +5957,7 @@ internal_format (
if (curwin->w_cursor.col == 0)
break;
+ ncc = cc;
col = curwin->w_cursor.col;
dec_cursor();
@@ -5943,17 +5966,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;
@@ -6055,7 +6117,7 @@ internal_format (
}
}
}
- first_line = FALSE;
+ first_line = false;
}
if (State & VREPLACE_FLAG) {
@@ -6242,12 +6304,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.
@@ -7697,6 +7757,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) {
@@ -8513,7 +8577,7 @@ static void ins_up(
if (old_topline != curwin->w_topline
|| old_topfill != curwin->w_topfill
)
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
start_arrow(&tpos);
can_cindent = true;
} else {
@@ -8561,7 +8625,7 @@ static void ins_down(
if (old_topline != curwin->w_topline
|| old_topfill != curwin->w_topfill
)
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
start_arrow(&tpos);
can_cindent = true;
} else {
@@ -8955,7 +9019,7 @@ static int ins_ctrl_ey(int tc)
scrolldown_clamp();
else
scrollup_clamp();
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
} else {
c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
if (c != NUL) {
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 11f6a350e4..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={},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 38ffa38e20..83ef9c8762 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -2071,6 +2071,12 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
expand_T xpc;
bool error = false;
char_u *result;
+#ifdef BACKSLASH_IN_FILENAME
+ char_u *p_csl_save = p_csl;
+
+ // avoid using 'completeslash' here
+ p_csl = empty_option;
+#endif
rettv->v_type = VAR_STRING;
if (argvars[1].v_type != VAR_UNKNOWN
@@ -2123,6 +2129,9 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = NULL;
}
}
+#ifdef BACKSLASH_IN_FILENAME
+ p_csl = p_csl_save;
+#endif
}
@@ -4007,7 +4016,7 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "globpath()" function
static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int flags = 0; // Flags for globpath.
+ int flags = WILD_IGNORE_COMPLETESLASH; // Flags for globpath.
bool error = false;
// Return a string, or a list if the optional third argument is non-zero.
@@ -6381,6 +6390,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
*/
@@ -8141,15 +8156,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)
@@ -8159,7 +8176,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) {
@@ -8187,18 +8204,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;
@@ -8211,7 +8228,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--;
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 3669cbbd2d..41137bf2db 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3721,8 +3721,8 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
update_topline();
validate_cursor();
update_screen(SOME_VALID);
- highlight_match = FALSE;
- redraw_later(SOME_VALID);
+ highlight_match = false;
+ redraw_later(curwin, SOME_VALID);
curwin->w_p_fen = save_p_fen;
if (msg_row == Rows - 1)
@@ -5751,7 +5751,7 @@ static buf_T *show_sub(exarg_T *eap, pos_T old_cusr,
}
xfree(str);
- redraw_later(SOME_VALID);
+ redraw_later(curwin, SOME_VALID);
win_enter(save_curwin, false); // Return to original window
update_topline();
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 503fd8e0d0..713d18b44d 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2363,7 +2363,7 @@ void ex_compiler(exarg_T *eap)
do_unlet(S_LEN("b:current_compiler"), true);
snprintf((char *)buf, bufsize, "compiler/%s.vim", eap->arg);
- if (source_runtime(buf, DIP_ALL) == FAIL) {
+ if (source_in_path(p_rtp, buf, DIP_ALL) == FAIL) {
EMSG2(_("E666: compiler not supported: %s"), eap->arg);
}
xfree(buf);
@@ -2581,6 +2581,7 @@ int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
/// return FAIL when no file could be sourced, OK otherwise.
int source_runtime(char_u *name, int flags)
{
+ flags |= (flags & DIP_NORTP) ? 0 : DIP_START;
return source_in_path(p_rtp, name, flags);
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 71ac542323..d7ed2fe97d 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1251,7 +1251,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
char_u *errormsg = NULL; // error message
char_u *after_modifier = NULL;
exarg_T ea;
- int save_msg_scroll = msg_scroll;
+ const int save_msg_scroll = msg_scroll;
cmdmod_T save_cmdmod;
const int save_reg_executing = reg_executing;
char_u *cmd;
@@ -2003,34 +2003,10 @@ doend:
? cmdnames[(int)ea.cmdidx].cmd_name
: (char_u *)NULL);
- if (ea.verbose_save >= 0) {
- p_verbose = ea.verbose_save;
- }
- free_cmdmod();
-
+ undo_cmdmod(&ea, save_msg_scroll);
cmdmod = save_cmdmod;
reg_executing = save_reg_executing;
- if (ea.save_msg_silent != -1) {
- // messages could be enabled for a serious error, need to check if the
- // counters don't become negative
- if (!did_emsg || msg_silent > ea.save_msg_silent) {
- msg_silent = ea.save_msg_silent;
- }
- emsg_silent -= ea.did_esilent;
- if (emsg_silent < 0) {
- emsg_silent = 0;
- }
- // Restore msg_scroll, it's set by file I/O commands, even when no
- // message is actually displayed.
- msg_scroll = save_msg_scroll;
-
- /* "silent reg" or "silent echo x" inside "redir" leaves msg_col
- * somewhere in the line. Put it back in the first column. */
- if (redirecting())
- msg_col = 0;
- }
-
if (ea.did_sandbox) {
sandbox--;
}
@@ -2298,9 +2274,14 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
return OK;
}
-// Free contents of "cmdmod".
-static void free_cmdmod(void)
+// Undo and free contents of "cmdmod".
+static void undo_cmdmod(const exarg_T *eap, int save_msg_scroll)
+ FUNC_ATTR_NONNULL_ALL
{
+ if (eap->verbose_save >= 0) {
+ p_verbose = eap->verbose_save;
+ }
+
if (cmdmod.save_ei != NULL) {
/* Restore 'eventignore' to the value before ":noautocmd". */
set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei,
@@ -2308,8 +2289,27 @@ static void free_cmdmod(void)
free_string_option(cmdmod.save_ei);
}
- if (cmdmod.filter_regmatch.regprog != NULL) {
- vim_regfree(cmdmod.filter_regmatch.regprog);
+ vim_regfree(cmdmod.filter_regmatch.regprog);
+
+ if (eap->save_msg_silent != -1) {
+ // messages could be enabled for a serious error, need to check if the
+ // counters don't become negative
+ if (!did_emsg || msg_silent > eap->save_msg_silent) {
+ msg_silent = eap->save_msg_silent;
+ }
+ emsg_silent -= eap->did_esilent;
+ if (emsg_silent < 0) {
+ emsg_silent = 0;
+ }
+ // Restore msg_scroll, it's set by file I/O commands, even when no
+ // message is actually displayed.
+ msg_scroll = save_msg_scroll;
+
+ // "silent reg" or "silent echo x" inside "redir" leaves msg_col
+ // somewhere in the line. Put it back in the first column.
+ if (redirecting()) {
+ msg_col = 0;
+ }
}
}
@@ -4446,6 +4446,9 @@ void separate_nextcmd(exarg_T *eap)
else if (p[0] == '`' && p[1] == '=' && (eap->argt & XFILE)) {
p += 2;
(void)skip_expr(&p);
+ if (*p == NUL) { // stop at NUL after CTRL-V
+ break;
+ }
}
/* Check for '"': start of comment or '|': next command */
/* :@" does not start a comment!
@@ -5400,7 +5403,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 {
@@ -7379,7 +7382,7 @@ static void ex_syncbind(exarg_T *eap)
else
scrolldown(-y, TRUE);
curwin->w_scbind_pos = topline;
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
cursor_correct();
curwin->w_redr_status = TRUE;
}
@@ -8504,7 +8507,7 @@ static void ex_pedit(exarg_T *eap)
if (curwin != curwin_save && win_valid(curwin_save)) {
// Return cursor to where we were
validate_cursor();
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
win_enter(curwin_save, true);
}
g_do_tagpreview = 0;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index f9ca7bfa42..53feffd2d7 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -4990,7 +4990,7 @@ ExpandFromContext (
char_u *pat,
int *num_file,
char_u ***file,
- int options /* EW_ flags */
+ int options // WILD_ flags
)
{
regmatch_T regmatch;
@@ -5052,6 +5052,21 @@ ExpandFromContext (
ret = expand_wildcards_eval(&pat, num_file, file, flags);
if (free_pat)
xfree(pat);
+#ifdef BACKSLASH_IN_FILENAME
+ if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0) {
+ for (int i = 0; i < *num_file; i++) {
+ char_u *ptr = (*file)[i];
+ while (*ptr != NUL) {
+ if (p_csl[0] == 's' && *ptr == '\\') {
+ *ptr = '/';
+ } else if (p_csl[0] == 'b' && *ptr == '/') {
+ *ptr = '\\';
+ }
+ ptr += utfc_ptr2len(ptr);
+ }
+ }
+ }
+#endif
return ret;
}
@@ -5193,7 +5208,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,
@@ -6468,7 +6483,7 @@ static int open_cmdwin(void)
ccline.redraw_state = kCmdRedrawNone;
ui_call_cmdline_hide(ccline.level);
}
- redraw_later(SOME_VALID);
+ redraw_later(curwin, SOME_VALID);
// Save the command line info, can be used recursively.
save_cmdline(&save_ccline);
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 6b00b986dc..42a9ef08f9 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -897,8 +897,8 @@ void ex_mkrc(exarg_T *eap)
if (!failed && view_session) {
if (put_line(fd,
- "let s:so_save = &so | let s:siso_save = &siso"
- " | set so=0 siso=0") == FAIL) {
+ "let s:so_save = &g:so | let s:siso_save = &g:siso"
+ " | setg so=0 siso=0 | setl so=-1 siso=-1") == FAIL) {
failed = true;
}
if (eap->cmdidx == CMD_mksession) {
@@ -949,7 +949,7 @@ void ex_mkrc(exarg_T *eap)
}
if (fprintf(fd,
"%s",
- "let &so = s:so_save | let &siso = s:siso_save\n"
+ "let &g:so = s:so_save | let &g:siso = s:siso_save\n"
"doautoall SessionLoadPost\n")
< 0) {
failed = true;
diff --git a/src/nvim/extmark_defs.h b/src/nvim/extmark_defs.h
index f5ca0ebbb0..382aaf6ed3 100644
--- a/src/nvim/extmark_defs.h
+++ b/src/nvim/extmark_defs.h
@@ -50,10 +50,13 @@ typedef struct {
LuaRef redraw_win;
LuaRef redraw_line;
LuaRef redraw_end;
+ LuaRef hl_def;
+ int hl_valid;
} DecorationProvider;
#define DECORATION_PROVIDER_INIT(ns_id) (DecorationProvider) \
{ ns_id, false, LUA_NOREF, LUA_NOREF, \
- LUA_NOREF, LUA_NOREF, LUA_NOREF }
+ LUA_NOREF, LUA_NOREF, LUA_NOREF, \
+ LUA_NOREF, -1 }
#endif // NVIM_EXTMARK_DEFS_H
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 197aedabec..57001f77ed 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -862,7 +862,7 @@ void foldUpdateAfterInsert(void)
void foldUpdateAll(win_T *win)
{
win->w_foldinvalid = true;
- redraw_win_later(win, NOT_VALID);
+ redraw_later(win, NOT_VALID);
}
// foldMoveTo() {{{2
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/globals.h b/src/nvim/globals.h
index 2db8689a56..31dd3fc848 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -92,6 +92,10 @@ EXTERN struct nvim_stats_s {
EXTERN int Rows INIT(= DFLT_ROWS); // nr of rows in the screen
EXTERN int Columns INIT(= DFLT_COLS); // nr of columns in the screen
+EXTERN NS ns_hl_active INIT(= 0); // current ns that defines highlights
+EXTERN bool ns_hl_changed INIT(= false); // highlight need update
+
+
// We use 64-bit file functions here, if available. E.g. ftello() returns
// off_t instead of long, which helps if long is 32 bit and off_t is 64 bit.
// We assume that when fseeko() is available then ftello() is too.
@@ -941,8 +945,10 @@ EXTERN char_u e_readonly[] INIT(= N_(
EXTERN char_u e_readonlyvar[] INIT(= N_(
"E46: Cannot change read-only variable \"%.*s\""));
EXTERN char_u e_dictreq[] INIT(= N_("E715: Dictionary required"));
-EXTERN char_u e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s"));
-EXTERN char_u e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: %s"));
+EXTERN char_u e_toomanyarg[] INIT(= N_(
+ "E118: Too many arguments for function: %s"));
+EXTERN char_u e_dictkey[] INIT(= N_(
+ "E716: Key not present in Dictionary: \"%s\""));
EXTERN char_u e_listreq[] INIT(= N_("E714: List required"));
EXTERN char_u e_listdictarg[] INIT(= N_(
"E712: Argument of %s must be a List or Dictionary"));
diff --git a/src/nvim/hashtab.h b/src/nvim/hashtab.h
index 19633d455f..c82a6cc121 100644
--- a/src/nvim/hashtab.h
+++ b/src/nvim/hashtab.h
@@ -51,6 +51,7 @@ typedef struct hashitem_S {
/// Initial size for a hashtable.
/// Our items are relatively small and growing is expensive, thus start with 16.
/// Must be a power of 2.
+/// This allows for storing 10 items (2/3 of 16) before a resize is needed.
#define HT_INIT_SIZE 16
/// An array-based hashtable.
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 262afba07a..8403615166 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -14,6 +14,7 @@
#include "nvim/ui.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/lua/executor.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "highlight.c.generated.h"
@@ -28,12 +29,16 @@ static Map(int, int) *combine_attr_entries;
static Map(int, int) *blend_attr_entries;
static Map(int, int) *blendthrough_attr_entries;
+/// highlight entries private to a namespace
+static Map(ColorKey, ColorItem) *ns_hl;
+
void highlight_init(void)
{
attr_entry_ids = map_new(HlEntry, int)();
combine_attr_entries = map_new(int, int)();
blend_attr_entries = map_new(int, int)();
blendthrough_attr_entries = map_new(int, int)();
+ ns_hl = map_new(ColorKey, ColorItem)();
// index 0 is no attribute, add dummy entry:
kv_push(attr_entries, ((HlEntry){ .attr = HLATTRS_INIT, .kind = kHlUnknown,
@@ -129,21 +134,114 @@ void ui_send_all_hls(UI *ui)
}
/// Get attribute code for a syntax group.
-int hl_get_syn_attr(int idx, HlAttrs at_en)
+int hl_get_syn_attr(int ns_id, int idx, HlAttrs at_en)
{
// TODO(bfredl): should we do this unconditionally
if (at_en.cterm_fg_color != 0 || at_en.cterm_bg_color != 0
|| at_en.rgb_fg_color != -1 || at_en.rgb_bg_color != -1
|| at_en.rgb_sp_color != -1 || at_en.cterm_ae_attr != 0
- || at_en.rgb_ae_attr != 0) {
+ || at_en.rgb_ae_attr != 0 || ns_id != 0) {
return get_attr_entry((HlEntry){ .attr = at_en, .kind = kHlSyntax,
- .id1 = idx, .id2 = 0 });
+ .id1 = idx, .id2 = ns_id });
} else {
// If all the fields are cleared, clear the attr field back to default value
return 0;
}
}
+static ColorKey colored_key(NS ns_id, int syn_id)
+{
+ return (ColorKey){ .ns_id = (int)ns_id, .syn_id = syn_id };
+}
+
+void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id)
+{
+ DecorationProvider *p = get_provider(ns_id, true);
+ int attr_id = link_id > 0 ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs);
+ ColorItem it = { .attr_id = attr_id,
+ .link_id = link_id,
+ .version = p->hl_valid };
+ map_put(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id), it);
+}
+
+int ns_get_hl(NS ns_id, int hl_id, bool link)
+{
+ static int recursive = 0;
+
+ if (ns_id < 0) {
+ if (ns_hl_active <= 0) {
+ return -1;
+ }
+ ns_id = ns_hl_active;
+ }
+
+ DecorationProvider *p = get_provider(ns_id, true);
+ ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id));
+ // TODO(bfredl): map_ref true even this?
+ bool valid_cache = it.version >= p->hl_valid;
+
+ if (!valid_cache && p->hl_def != LUA_NOREF && !recursive) {
+ FIXED_TEMP_ARRAY(args, 3);
+ args.items[0] = INTEGER_OBJ((Integer)ns_id);
+ args.items[1] = STRING_OBJ(cstr_to_string((char *)syn_id2name(hl_id)));
+ args.items[2] = BOOLEAN_OBJ(link);
+ // TODO(bfredl): preload the "global" attr dict?
+
+ Error err = ERROR_INIT;
+ recursive++;
+ Object ret = nlua_call_ref(p->hl_def, "hl_def", args, true, &err);
+ recursive--;
+
+ // TODO(bfredl): or "inherit", combine with global value?
+ bool fallback = true;
+ int tmp = false;
+ HlAttrs attrs = HLATTRS_INIT;
+ if (ret.type == kObjectTypeDictionary) {
+ Dictionary dict = ret.data.dictionary;
+ fallback = false;
+ attrs = dict2hlattrs(dict, true, &it.link_id, &err);
+ for (size_t i = 0; i < dict.size; i++) {
+ char *key = dict.items[i].key.data;
+ Object val = dict.items[i].value;
+ bool truthy = api_object_to_bool(val, key, false, &err);
+
+ if (strequal(key, "fallback")) {
+ fallback = truthy;
+ } else if (strequal(key, "temp")) {
+ tmp = truthy;
+ }
+ }
+ if (it.link_id >= 0) {
+ fallback = true;
+ }
+ }
+
+ it.attr_id = fallback ? -1 : hl_get_syn_attr((int)ns_id, hl_id, attrs);
+ it.version = p->hl_valid-tmp;
+ map_put(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id), it);
+ }
+
+ if (link) {
+ return it.attr_id >= 0 ? -1 : it.link_id;
+ } else {
+ return it.attr_id;
+ }
+}
+
+
+bool win_check_ns_hl(win_T *wp)
+{
+ if (ns_hl_changed) {
+ highlight_changed();
+ if (wp) {
+ update_window_hl(wp, true);
+ }
+ ns_hl_changed = false;
+ return true;
+ }
+ return false;
+}
+
/// Get attribute code for a builtin highlight group.
///
/// The final syntax group could be modified by hi-link or 'winhighlight'.
@@ -204,6 +302,17 @@ void update_window_hl(win_T *wp, bool invalid)
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
}
+ // NOOOO! You cannot just pretend that "Normal" is just like any other
+ // syntax group! It needs at least 10 layers of special casing! Noooooo!
+ //
+ // haha, theme engine go brrr
+ int normality = syn_check_group((const char_u *)S_LEN("Normal"));
+ int ns_attr = ns_get_hl(-1, normality, false);
+ if (ns_attr > 0) {
+ // TODO(bfredl): hantera NormalNC and so on
+ wp->w_hl_attr_normal = ns_attr;
+ }
+
// if blend= attribute is not set, 'winblend' value overrides it.
if (wp->w_floating && wp->w_p_winbl > 0) {
HlEntry entry = kv_A(attr_entries, wp->w_hl_attr_normal);
@@ -275,6 +384,7 @@ void clear_hl_tables(bool reinit)
map_free(int, int)(combine_attr_entries);
map_free(int, int)(blend_attr_entries);
map_free(int, int)(blendthrough_attr_entries);
+ map_free(ColorKey, ColorItem)(ns_hl);
}
}
@@ -663,6 +773,103 @@ Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb)
return hl;
}
+HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err)
+{
+ HlAttrs hlattrs = HLATTRS_INIT;
+
+ int32_t fg = -1, bg = -1, sp = -1;
+ int16_t mask = 0;
+ for (size_t i = 0; i < dict.size; i++) {
+ char *key = dict.items[i].key.data;
+ Object val = dict.items[i].value;
+
+ struct {
+ const char *name;
+ int16_t flag;
+ } flags[] = {
+ { "bold", HL_BOLD },
+ { "standout", HL_STANDOUT },
+ { "underline", HL_UNDERLINE },
+ { "undercurl", HL_UNDERCURL },
+ { "italic", HL_ITALIC },
+ { "reverse", HL_INVERSE },
+ { NULL, 0 },
+ };
+
+ int j;
+ for (j = 0; flags[j].name; j++) {
+ if (strequal(flags[j].name, key)) {
+ if (api_object_to_bool(val, key, false, err)) {
+ mask = mask | flags[j].flag;
+ }
+ break;
+ }
+ }
+
+ struct {
+ const char *name;
+ const char *shortname;
+ int *dest;
+ } colors[] = {
+ { "foreground", "fg", &fg },
+ { "background", "bg", &bg },
+ { "special", "sp", &sp },
+ { NULL, NULL, NULL },
+ };
+
+ int k;
+ for (k = 0; (!flags[j].name) && colors[k].name; k++) {
+ if (strequal(colors[k].name, key) || strequal(colors[k].shortname, key)) {
+ if (val.type == kObjectTypeInteger) {
+ *colors[k].dest = (int)val.data.integer;
+ } else if (val.type == kObjectTypeString) {
+ String str = val.data.string;
+ // TODO(bfredl): be more fancy with "bg", "fg" etc
+ if (str.size) {
+ *colors[k].dest = name_to_color(str.data);
+ }
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "'%s' must be string or integer", key);
+ }
+ break;
+ }
+ }
+
+
+ if (flags[j].name || colors[k].name) {
+ // handled above
+ } else if (link_id && strequal(key, "link")) {
+ if (val.type == kObjectTypeString) {
+ String str = val.data.string;
+ *link_id = syn_check_group((const char_u *)str.data, (int)str.size);
+ } else if (val.type == kObjectTypeInteger) {
+ // TODO(bfredl): validate range?
+ *link_id = (int)val.data.integer;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "'link' must be string or integer");
+ }
+ }
+
+ if (ERROR_SET(err)) {
+ return hlattrs; // error set, caller should not use retval
+ }
+ }
+
+ if (use_rgb) {
+ hlattrs.rgb_ae_attr = mask;
+ hlattrs.rgb_bg_color = bg;
+ hlattrs.rgb_fg_color = fg;
+ hlattrs.rgb_sp_color = sp;
+ } else {
+ hlattrs.cterm_ae_attr = mask;
+ hlattrs.cterm_bg_color = bg == -1 ? cterm_normal_bg_color : bg + 1;
+ hlattrs.cterm_fg_color = fg == -1 ? cterm_normal_fg_color : fg + 1;
+ }
+
+ return hlattrs;
+}
Array hl_inspect(int attr)
{
Array ret = ARRAY_DICT_INIT;
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 36f3181674..6a5c593ab1 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -4,6 +4,7 @@
#include <inttypes.h>
#include "nvim/macros.h"
+#include "nvim/types.h"
typedef int32_t RgbValue;
@@ -180,6 +181,20 @@ typedef struct {
HlKind kind;
int id1;
int id2;
+ int winid;
} HlEntry;
+typedef struct {
+ int ns_id;
+ int syn_id;
+} ColorKey;
+
+typedef struct {
+ int attr_id;
+ int link_id;
+ int version;
+} ColorItem;
+#define COLOR_ITEM_INITIALIZER { .attr_id = -1, .link_id = -1, .version = -1 }
+
+
#endif // NVIM_HIGHLIGHT_DEFS_H
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index bb0fdfec01..9e6693afdf 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -295,13 +295,17 @@ int set_indent(int size, int flags)
// Replace the line (unless undo fails).
if (!(flags & SIN_UNDO) || (u_savesub(curwin->w_cursor.lnum) == OK)) {
+ const colnr_T old_offset = (colnr_T)(p - oldline);
+ const colnr_T new_offset = (colnr_T)(s - newline);
+
+ // this may free "newline"
ml_replace(curwin->w_cursor.lnum, newline, false);
if (!(flags & SIN_NOMARK)) {
extmark_splice_cols(curbuf,
(int)curwin->w_cursor.lnum-1,
skipcols,
- (int)(p-oldline) - skipcols,
- (int)(s-newline) - skipcols,
+ old_offset - skipcols,
+ new_offset - skipcols,
kExtmarkUndo);
}
@@ -311,15 +315,14 @@ int set_indent(int size, int flags)
// Correct saved cursor position if it is in this line.
if (saved_cursor.lnum == curwin->w_cursor.lnum) {
- if (saved_cursor.col >= (colnr_T)(p - oldline)) {
+ if (saved_cursor.col >= old_offset) {
// Cursor was after the indent, adjust for the number of
// bytes added/removed.
- saved_cursor.col += ind_len - (colnr_T)(p - oldline);
-
- } else if (saved_cursor.col >= (colnr_T)(s - newline)) {
+ saved_cursor.col += ind_len - old_offset;
+ } else if (saved_cursor.col >= new_offset) {
// Cursor was in the indent, and is now after it, put it back
// at the start of the indent (replacing spaces with TAB).
- saved_cursor.col = (colnr_T)(s - newline);
+ saved_cursor.col = new_offset;
}
}
retval = true;
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index bb443161ef..9298e57411 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -1676,6 +1676,9 @@ void parse_cino(buf_T *buf)
// Handle C++ extern "C" or "C++"
buf->b_ind_cpp_extern_c = 0;
+ // Handle C #pragma directives
+ buf->b_ind_pragma = 0;
+
for (p = buf->b_p_cino; *p; ) {
l = p++;
if (*p == '-') {
@@ -1747,6 +1750,7 @@ void parse_cino(buf_T *buf)
case 'N': buf->b_ind_cpp_namespace = n; break;
case 'k': buf->b_ind_if_for_while = n; break;
case 'E': buf->b_ind_cpp_extern_c = n; break;
+ case 'P': buf->b_ind_pragma = n; break;
}
if (*p == ',')
++p;
@@ -1858,12 +1862,14 @@ int get_c_indent(void)
goto laterend;
}
- /*
- * #defines and so on always go at the left when included in 'cinkeys'.
- */
+ // #defines and so on go at the left when included in 'cinkeys',
+ // exluding pragmas when customized in 'cinoptions'
if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', true))) {
- amount = curbuf->b_ind_hash_comment;
- goto theend;
+ const char_u *const directive = skipwhite(theline + 1);
+ if (curbuf->b_ind_pragma == 0 || STRNCMP(directive, "pragma", 6) != 0) {
+ amount = curbuf->b_ind_hash_comment;
+ goto theend;
+ }
}
/*
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 5c665920b5..a095f298f2 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -549,14 +549,6 @@ static lua_State *nlua_enter(void)
// stack: (empty)
lua_getglobal(lstate, "vim");
// stack: vim
- lua_getfield(lstate, -1, "_update_package_paths");
- // stack: vim, vim._update_package_paths
- if (lua_pcall(lstate, 0, 0, 0)) {
- // stack: vim, error
- nlua_error(lstate, _("E5117: Error while updating package paths: %.*s"));
- // stack: vim
- }
- // stack: vim
lua_pop(lstate, 1);
// stack: (empty)
last_p_rtp = (const void *)p_rtp;
@@ -564,14 +556,6 @@ static lua_State *nlua_enter(void)
return lstate;
}
-/// Force an update of lua's package paths if runtime path has changed.
-bool nlua_update_package_path(void)
-{
- lua_State *const lstate = nlua_enter();
-
- return !!lstate;
-}
-
static void nlua_print_event(void **argv)
{
char *str = argv[0];
@@ -891,6 +875,17 @@ LuaRef nlua_newref(lua_State *lstate, LuaRef original_ref)
return new_ref;
}
+LuaRef api_new_luaref(LuaRef original_ref)
+{
+ if (original_ref == LUA_NOREF) {
+ return LUA_NOREF;
+ }
+
+ lua_State *const lstate = nlua_enter();
+ return nlua_newref(lstate, original_ref);
+}
+
+
/// Evaluate lua string
///
/// Used for luaeval().
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 5258352e72..c53e208b00 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -58,6 +58,7 @@ static struct luaL_Reg node_meta[] = {
{ "__tostring", node_tostring },
{ "__eq", node_eq },
{ "__len", node_child_count },
+ { "id", node_id },
{ "range", node_range },
{ "start", node_start },
{ "end_", node_end },
@@ -176,10 +177,11 @@ int tslua_add_language(lua_State *L)
}
uint32_t lang_version = ts_language_version(lang);
- if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION) {
+ if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION
+ || lang_version > TREE_SITTER_LANGUAGE_VERSION) {
return luaL_error(
L,
- "ABI version mismatch : expected %" PRIu32 ", found %" PRIu32,
+ "ABI version mismatch : expected %d, found %d",
TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION, lang_version);
}
@@ -246,7 +248,12 @@ int tslua_push_parser(lua_State *L)
}
TSParser *parser = ts_parser_new();
- ts_parser_set_language(parser, lang);
+
+ if (!ts_parser_set_language(parser, lang)) {
+ ts_parser_delete(parser);
+ return luaL_error(L, "Failed to load language : %s", lang_name);
+ }
+
TSLua_parser *p = lua_newuserdata(L, sizeof(TSLua_parser)); // [udata]
p->parser = parser;
p->tree = NULL;
@@ -342,7 +349,7 @@ static int parser_parse(lua_State *L)
return 0;
}
- TSTree *new_tree;
+ TSTree *new_tree = NULL;
size_t len;
const char *str;
long bufnr;
@@ -374,6 +381,12 @@ static int parser_parse(lua_State *L)
return luaL_error(L, "invalid argument to parser:parse()");
}
+ // Sometimes parsing fails (timeout, or wrong parser ABI)
+ // In those case, just return an error.
+ if (!new_tree) {
+ return luaL_error(L, "An error occured when parsing.");
+ }
+
uint32_t n_ranges = 0;
TSRange *changed = p->tree ? ts_tree_get_changed_ranges(p->tree, new_tree,
&n_ranges) : NULL;
@@ -621,6 +634,17 @@ static int node_eq(lua_State *L)
return 1;
}
+static int node_id(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+
+ lua_pushlstring(L, (const char *)&node.id, sizeof node.id);
+ return 1;
+}
+
static int node_range(lua_State *L)
{
TSNode node;
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index bfa8b91208..85d39eaef4 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -92,67 +92,48 @@ function vim._os_proc_children(ppid)
return children
end
--- TODO(ZyX-I): Create compatibility layer.
---{{{1 package.path updater function
--- Last inserted paths. Used to clear out items from package.[c]path when they
--- are no longer in &runtimepath.
-local last_nvim_paths = {}
-function vim._update_package_paths()
- local cur_nvim_paths = {}
- local rtps = vim.api.nvim_list_runtime_paths()
- local sep = package.config:sub(1, 1)
- for _, key in ipairs({'path', 'cpath'}) do
- local orig_str = package[key] .. ';'
- local pathtrails_ordered = {}
- local orig = {}
- -- Note: ignores trailing item without trailing `;`. Not using something
- -- simpler in order to preserve empty items (stand for default path).
- for s in orig_str:gmatch('[^;]*;') do
- s = s:sub(1, -2) -- Strip trailing semicolon
- orig[#orig + 1] = s
- end
- if key == 'path' then
- -- /?.lua and /?/init.lua
- pathtrails_ordered = {sep .. '?.lua', sep .. '?' .. sep .. 'init.lua'}
- else
- local pathtrails = {}
- for _, s in ipairs(orig) do
- -- Find out path patterns. pathtrail should contain something like
- -- /?.so, \?.dll. This allows not to bother determining what correct
- -- suffixes are.
- local pathtrail = s:match('[/\\][^/\\]*%?.*$')
- if pathtrail and not pathtrails[pathtrail] then
- pathtrails[pathtrail] = true
- pathtrails_ordered[#pathtrails_ordered + 1] = pathtrail
- end
- end
- end
- local new = {}
- for _, rtp in ipairs(rtps) do
- if not rtp:match(';') then
- for _, pathtrail in pairs(pathtrails_ordered) do
- local new_path = rtp .. sep .. 'lua' .. pathtrail
- -- Always keep paths from &runtimepath at the start:
- -- append them here disregarding orig possibly containing one of them.
- new[#new + 1] = new_path
- cur_nvim_paths[new_path] = true
- end
- end
+local pathtrails = {}
+vim._so_trails = {}
+for s in (package.cpath..';'):gmatch('[^;]*;') do
+ s = s:sub(1, -2) -- Strip trailing semicolon
+ -- Find out path patterns. pathtrail should contain something like
+ -- /?.so, \?.dll. This allows not to bother determining what correct
+ -- suffixes are.
+ local pathtrail = s:match('[/\\][^/\\]*%?.*$')
+ if pathtrail and not pathtrails[pathtrail] then
+ pathtrails[pathtrail] = true
+ table.insert(vim._so_trails, pathtrail)
+ end
+end
+
+function vim._load_package(name)
+ -- tricky: when debugging this function we must let vim.inspect
+ -- module to be loaded first:
+ --local inspect = (name == "vim.inspect") and tostring or vim.inspect
+
+ local basename = name:gsub('%.', '/')
+ local paths = {"lua/"..basename..".lua", "lua/"..basename.."/init.lua"}
+ for _,path in ipairs(paths) do
+ local found = vim.api.nvim_get_runtime_file(path, false)
+ if #found > 0 then
+ return loadfile(found[1])
end
- for _, orig_path in ipairs(orig) do
- -- Handle removing obsolete paths originating from &runtimepath: such
- -- paths either belong to cur_nvim_paths and were already added above or
- -- to last_nvim_paths and should not be added at all if corresponding
- -- entry was removed from &runtimepath list.
- if not (cur_nvim_paths[orig_path] or last_nvim_paths[orig_path]) then
- new[#new + 1] = orig_path
- end
+ end
+
+ for _,trail in ipairs(vim._so_trails) do
+ local path = "lua/"..trail:gsub('?',basename)
+ local found = vim.api.nvim_get_runtime_file(path, false)
+ if #found > 0 then
+ return package.loadlib(found[1])
end
- package[key] = table.concat(new, ';')
end
- last_nvim_paths = cur_nvim_paths
+ return nil
end
+table.insert(package.loaders, 1, vim._load_package)
+
+-- TODO(ZyX-I): Create compatibility layer.
+
--- Return a human-readable representation of the given object.
---
--@see https://github.com/kikito/inspect.lua
diff --git a/src/nvim/main.c b/src/nvim/main.c
index a22df9cc69..27bf5c45c6 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -446,7 +446,7 @@ int main(int argc, char **argv)
if (exmode_active || use_remote_ui || use_builtin_ui) {
// Don't clear the screen when starting in Ex mode, or when a UI might have
// displayed messages.
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
} else {
screenclear(); // clear screen
TIME_MSG("clearing screen");
diff --git a/src/nvim/map.c b/src/nvim/map.c
index ca8ea76333..7d97b7f13d 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -12,6 +12,9 @@
#include <stdbool.h>
#include <string.h>
+#include <lua.h>
+#include <lauxlib.h>
+
#include "nvim/map.h"
#include "nvim/map_defs.h"
#include "nvim/vim.h"
@@ -173,6 +176,20 @@ static inline bool HlEntry_eq(HlEntry ae1, HlEntry ae2)
return memcmp(&ae1, &ae2, sizeof(ae1)) == 0;
}
+static inline khint_t ColorKey_hash(ColorKey ae)
+{
+ const uint8_t *data = (const uint8_t *)&ae;
+ khint_t h = 0;
+ for (size_t i = 0; i < sizeof(ae); i++) {
+ h = (h << 5) - h + data[i];
+ }
+ return h;
+}
+
+static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2)
+{
+ return memcmp(&ae1, &ae2, sizeof(ae1)) == 0;
+}
MAP_IMPL(int, int, DEFAULT_INITIALIZER)
@@ -191,6 +208,7 @@ MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
MAP_IMPL(String, handle_T, 0)
+MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER)
/// Deletes a key:value pair from a string:pointer map, and frees the
/// storage of both key and value.
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 63a18f4129..7bd3d31330 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -55,6 +55,8 @@ MAP_DECLS(String, MsgpackRpcRequestHandler)
MAP_DECLS(HlEntry, int)
MAP_DECLS(String, handle_T)
+MAP_DECLS(ColorKey, ColorItem)
+
#define map_new(T, U) map_##T##_##U##_new
#define map_free(T, U) map_##T##_##U##_free
#define map_get(T, U) map_##T##_##U##_get
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 6d188c6cd0..ec4f4cbc21 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -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/menu.c b/src/nvim/menu.c
index b060464383..4ba2e36656 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -193,7 +193,7 @@ ex_menu(exarg_T *eap)
vimmenu_T **root_menu_ptr = get_root_menu(menu_path);
if (root_menu_ptr == &curwin->w_winbar) {
// Assume the window toolbar menu will change.
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
if (enable != kNone) {
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 6cd5616acf..06ba607323 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1216,7 +1216,7 @@ void wait_return(int redraw)
ui_refresh();
} else if (!skip_redraw) {
if (redraw == true || (msg_scrolled != 0 && redraw != -1)) {
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
}
if (ui_has(kUIMessages)) {
msg_ext_clear(true);
@@ -2222,7 +2222,7 @@ void msg_scroll_up(bool may_throttle)
///
/// Probably message scrollback storage should reimplented as a file_buffer, and
/// message scrolling in TUI be reimplemented as a modal floating window. Then
-/// we get throttling "for free" using standard redraw_win_later code paths.
+/// we get throttling "for free" using standard redraw_later code paths.
void msg_scroll_flush(void)
{
if (msg_grid.throttled) {
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index fcd9ee4f75..748001dcec 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -286,7 +286,7 @@ retnomove:
check_topfill(curwin, false);
curwin->w_valid &=
~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
row = 0;
} else if (row >= curwin->w_height_inner) {
count = 0;
@@ -316,7 +316,7 @@ retnomove:
}
}
check_topfill(curwin, false);
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
curwin->w_valid &=
~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
row = curwin->w_height_inner - 1;
@@ -450,7 +450,7 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump)
// skip line number and fold column in front of the line
col -= win_col_off(win);
- if (col < 0) {
+ if (col <= 0) {
col = 0;
}
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 8084461d3a..218dcd289d 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -107,7 +107,7 @@ void redraw_for_cursorline(win_T *wp)
&& !pum_visible()) {
if (wp->w_p_rnu) {
// win_line() will redraw the number column only.
- redraw_win_later(wp, VALID);
+ redraw_later(wp, VALID);
}
if (win_cursorline_standout(wp)) {
if (wp->w_redr_type <= VALID && wp->w_last_cursorline != 0) {
@@ -117,7 +117,7 @@ void redraw_for_cursorline(win_T *wp)
redrawWinline(wp, wp->w_last_cursorline);
redrawWinline(wp, wp->w_cursor.lnum);
} else {
- redraw_win_later(wp, SOME_VALID);
+ redraw_later(wp, SOME_VALID);
}
}
}
@@ -172,7 +172,7 @@ void update_topline(void)
// If the buffer is empty, always set topline to 1.
if (BUFEMPTY()) { // special case - file is empty
if (curwin->w_topline != 1) {
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
curwin->w_topline = 1;
curwin->w_botline = 2;
@@ -326,12 +326,14 @@ void update_topline(void)
dollar_vcol = -1;
if (curwin->w_skipcol != 0) {
curwin->w_skipcol = 0;
- redraw_later(NOT_VALID);
- } else
- redraw_later(VALID);
- /* May need to set w_skipcol when cursor in w_topline. */
- if (curwin->w_cursor.lnum == curwin->w_topline)
+ redraw_later(curwin, NOT_VALID);
+ } else {
+ redraw_later(curwin, VALID);
+ }
+ // May need to set w_skipcol when cursor in w_topline.
+ if (curwin->w_cursor.lnum == curwin->w_topline) {
validate_cursor();
+ }
}
*so_ptr = save_so;
@@ -439,7 +441,7 @@ void changed_window_setting_win(win_T *wp)
wp->w_lines_valid = 0;
changed_line_abv_curs_win(wp);
wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE);
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
}
/*
@@ -455,8 +457,8 @@ void set_topline(win_T *wp, linenr_T lnum)
wp->w_topline_was_set = true;
wp->w_topfill = 0;
wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE);
- /* Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked. */
- redraw_later(VALID);
+ // Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked.
+ redraw_later(wp, VALID);
}
/*
@@ -634,7 +636,7 @@ void validate_virtcol_win(win_T *wp)
if (wp->w_p_cuc
&& !pum_visible()
)
- redraw_win_later(wp, SOME_VALID);
+ redraw_later(wp, SOME_VALID);
}
}
@@ -830,7 +832,7 @@ void curs_columns(
curwin->w_leftcol = new_leftcol;
win_check_anchored_floats(curwin);
// screen has to be redrawn with new curwin->w_leftcol
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
}
curwin->w_wcol -= curwin->w_leftcol;
@@ -934,13 +936,14 @@ void curs_columns(
} else {
curwin->w_skipcol = 0;
}
- if (prev_skipcol != curwin->w_skipcol)
- redraw_later(NOT_VALID);
+ if (prev_skipcol != curwin->w_skipcol) {
+ redraw_later(curwin, NOT_VALID);
+ }
/* Redraw when w_virtcol changes and 'cursorcolumn' is set */
if (curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0
&& !pum_visible()) {
- redraw_later(SOME_VALID);
+ redraw_later(curwin, SOME_VALID);
}
// now w_leftcol is valid, avoid check_cursor_moved() thinking otherwise
@@ -2023,7 +2026,7 @@ int onepage(Direction dir, long count)
}
}
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
return retval;
}
@@ -2209,7 +2212,7 @@ void halfpage(bool flag, linenr_T Prenum)
check_topfill(curwin, !flag);
cursor_correct();
beginline(BL_SOL | BL_FIX);
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
}
void do_check_cursorbind(void)
@@ -2257,7 +2260,7 @@ void do_check_cursorbind(void)
}
// Correct cursor for multi-byte character.
mb_adjust_cursor();
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
// Only scroll when 'scrollbind' hasn't done this.
if (!curwin->w_p_scb) {
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 92ca29209e..68ef4cd41e 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -262,11 +262,9 @@ static void parse_msgpack(Channel *channel)
call_set_error(channel, buf, ERROR_LOG_LEVEL);
}
msgpack_unpacked_destroy(&unpacked);
- // Bail out from this event loop iteration
- return;
+ } else {
+ handle_request(channel, &unpacked.data);
}
-
- handle_request(channel, &unpacked.data);
}
if (result == MSGPACK_UNPACK_NOMEM_ERROR) {
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index f291adaffe..b09b99cf35 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -903,6 +903,10 @@ normal_end:
msg_nowait = false;
+ if (finish_op) {
+ set_reg_var(get_default_register_name());
+ }
+
// Reset finish_op, in case it was set
s->c = finish_op;
finish_op = false;
@@ -3615,7 +3619,7 @@ void check_scrollbind(linenr_T topline_diff, long leftcol_diff)
scrolldown(-y, false);
}
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
cursor_correct();
curwin->w_redr_status = true;
}
@@ -4158,7 +4162,7 @@ void scroll_redraw(int up, long count)
coladvance(curwin->w_curswant);
if (moved)
curwin->w_viewport_invalid = true;
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
}
/*
@@ -4256,7 +4260,7 @@ dozet:
FALLTHROUGH;
case 't': scroll_cursor_top(0, true);
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
set_fraction(curwin);
break;
@@ -4265,7 +4269,7 @@ dozet:
FALLTHROUGH;
case 'z': scroll_cursor_halfway(true);
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
set_fraction(curwin);
break;
@@ -4286,7 +4290,7 @@ dozet:
FALLTHROUGH;
case 'b': scroll_cursor_bot(0, true);
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
set_fraction(curwin);
break;
@@ -4333,7 +4337,7 @@ dozet:
col = 0;
if (curwin->w_leftcol != col) {
curwin->w_leftcol = col;
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
}
break;
@@ -4352,7 +4356,7 @@ dozet:
}
if (curwin->w_leftcol != col) {
curwin->w_leftcol = col;
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
}
break;
@@ -4705,7 +4709,7 @@ static void nv_clear(cmdarg_T *cap)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
wp->w_s->b_syn_slow = false;
}
- redraw_later(CLEAR);
+ redraw_later(curwin, CLEAR);
}
}
@@ -6856,7 +6860,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..9e7d81fc82 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -2652,7 +2652,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
xfree(reg->y_array);
}
if (curwin->w_p_rnu) {
- redraw_later(SOME_VALID); // cursor moved to start
+ redraw_later(curwin, SOME_VALID); // cursor moved to start
}
if (message) { // Display message about yank?
if (yank_type == kMTCharWise && yanklines == 1) {
@@ -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 484d9da3a1..fcc051ef1a 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -312,6 +312,9 @@ static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
static char *(p_fcl_values[]) = { "all", NULL };
static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview",
"noinsert", "noselect", NULL };
+#ifdef BACKSLASH_IN_FILENAME
+static char *(p_csl_values[]) = { "slash", "backslash", NULL };
+#endif
static char *(p_icm_values[]) = { "nosplit", "split", NULL };
static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2",
"auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9",
@@ -2563,7 +2566,7 @@ static bool valid_spellfile(const char_u *val)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
for (const char_u *s = val; *s != NUL; s++) {
- if (!vim_isfilec(*s) && *s != ',') {
+ if (!vim_isfilec(*s) && *s != ',' && *s != ' ') {
return false;
}
}
@@ -3118,7 +3121,7 @@ ambw_end:
} else {
if (curwin->w_status_height) {
curwin->w_redr_status = true;
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
}
curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
redraw_titles();
@@ -3188,6 +3191,13 @@ ambw_end:
} else {
completeopt_was_set();
}
+#ifdef BACKSLASH_IN_FILENAME
+ } else if (gvarp == &p_csl) { // 'completeslash'
+ if (check_opt_strings(p_csl, p_csl_values, false) != OK
+ || check_opt_strings(curbuf->b_p_csl, p_csl_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+#endif
} else if (varp == &curwin->w_p_scl) {
// 'signcolumn'
if (check_opt_strings(*varp, p_scl_values, false) != OK) {
@@ -3354,10 +3364,6 @@ ambw_end:
if (!parse_winhl_opt(curwin)) {
errmsg = e_invarg;
}
- } else if (varp == &p_rtp) { // 'runtimepath'
- if (!nlua_update_package_path()) {
- errmsg = (char_u *)N_("E970: Failed to initialize lua interpreter");
- }
} else {
// Options that are a list of flags.
p = NULL;
@@ -3741,11 +3747,10 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
/// Return error message or NULL.
char_u *check_stl_option(char_u *s)
{
- int itemcnt = 0;
int groupdepth = 0;
static char_u errbuf[80];
- while (*s && itemcnt < STL_MAX_ITEM) {
+ while (*s) {
// Check for valid keys after % sequences
while (*s && *s != '%') {
s++;
@@ -3754,9 +3759,6 @@ char_u *check_stl_option(char_u *s)
break;
}
s++;
- if (*s != '%' && *s != ')') {
- itemcnt++;
- }
if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE) {
s++;
continue;
@@ -3798,9 +3800,6 @@ char_u *check_stl_option(char_u *s)
}
}
}
- if (itemcnt >= STL_MAX_ITEM) {
- return (char_u *)N_("E541: too many items");
- }
if (groupdepth != 0) {
return (char_u *)N_("E542: unbalanced groups");
}
@@ -4692,7 +4691,7 @@ static void check_redraw(uint32_t flags)
redraw_curbuf_later(NOT_VALID);
}
if (flags & P_RWINONLY) {
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
if (doclear) {
redraw_all_later(CLEAR);
@@ -5706,12 +5705,12 @@ void unset_global_local_option(char *name, void *from)
case PV_LCS:
clear_string_option(&((win_T *)from)->w_p_lcs);
set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs, true);
- redraw_win_later((win_T *)from, NOT_VALID);
+ redraw_later((win_T *)from, NOT_VALID);
break;
case PV_FCS:
clear_string_option(&((win_T *)from)->w_p_fcs);
set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true);
- redraw_win_later((win_T *)from, NOT_VALID);
+ redraw_later((win_T *)from, NOT_VALID);
break;
}
}
@@ -5866,6 +5865,9 @@ static char_u *get_varp(vimoption_T *p)
case PV_COM: return (char_u *)&(curbuf->b_p_com);
case PV_CMS: return (char_u *)&(curbuf->b_p_cms);
case PV_CPT: return (char_u *)&(curbuf->b_p_cpt);
+# ifdef BACKSLASH_IN_FILENAME
+ case PV_CSL: return (char_u *)&(curbuf->b_p_csl);
+# endif
case PV_CFU: return (char_u *)&(curbuf->b_p_cfu);
case PV_OFU: return (char_u *)&(curbuf->b_p_ofu);
case PV_EOL: return (char_u *)&(curbuf->b_p_eol);
@@ -6153,6 +6155,9 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_inf = p_inf;
buf->b_p_swf = cmdmod.noswapfile ? false : p_swf;
buf->b_p_cpt = vim_strsave(p_cpt);
+# ifdef BACKSLASH_IN_FILENAME
+ buf->b_p_csl = vim_strsave(p_csl);
+# endif
buf->b_p_cfu = vim_strsave(p_cfu);
buf->b_p_ofu = vim_strsave(p_ofu);
buf->b_p_tfu = vim_strsave(p_tfu);
@@ -6803,7 +6808,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;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index a09811c8fb..af0ea7f4a2 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
@@ -187,6 +188,7 @@ enum {
#define GO_ASELML 'A' // autoselect modeless selection
#define GO_BOT 'b' // use bottom scrollbar
#define GO_CONDIALOG 'c' // use console dialog
+#define GO_DARKTHEME 'd' // use dark theme variant
#define GO_TABLINE 'e' // may show tabline
#define GO_FORG 'f' // start GUI in foreground
#define GO_GREY 'g' // use grey menu items
@@ -204,7 +206,7 @@ enum {
#define GO_FOOTER 'F' // add footer
#define GO_VERTICAL 'v' // arrange dialog buttons vertically
#define GO_KEEPWINSIZE 'k' // keep GUI window size
-#define GO_ALL "aAbcefFghilmMprTvk" // all possible flags for 'go'
+#define GO_ALL "aAbcdefFghilmMprTvk" // all possible flags for 'go'
// flags for 'comments' option
#define COM_NEST 'n' // comments strings nest
@@ -372,6 +374,9 @@ EXTERN long p_columns; // 'columns'
EXTERN int p_confirm; // 'confirm'
EXTERN int p_cp; // 'compatible'
EXTERN char_u *p_cot; // 'completeopt'
+# ifdef BACKSLASH_IN_FILENAME
+EXTERN char_u *p_csl; // 'completeslash'
+# endif
EXTERN long p_pb; // 'pumblend'
EXTERN long p_ph; // 'pumheight'
EXTERN long p_pw; // 'pumwidth'
@@ -743,6 +748,7 @@ enum {
, BV_CPT
, BV_DICT
, BV_TSR
+ , BV_CSL
, BV_CFU
, BV_DEF
, BV_INC
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 02df0ab276..65ef7a4527 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -453,6 +453,15 @@ return {
defaults={if_true={vi="menu,preview"}}
},
{
+ full_name='completeslash', abbreviation='csl',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_csl',
+ enable_if='BACKSLASH_IN_FILENAME',
+ defaults={if_true={vi=""}}
+ },
+ {
full_name='confirm', abbreviation='cf',
type='bool', scope={'global'},
vi_def=true,
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index c8ac4218f6..bd5f2b889d 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -16,10 +16,11 @@
#define BASENAMELEN (NAME_MAX - 5)
// Use the system path length if it makes sense.
-#if defined(PATH_MAX) && (PATH_MAX > 1024)
+# define DEFAULT_MAXPATHL 4096
+#if defined(PATH_MAX) && (PATH_MAX > DEFAULT_MAXPATHL)
# define MAXPATHL PATH_MAX
#else
-# define MAXPATHL 1024
+# define MAXPATHL DEFAULT_MAXPATHL
#endif
// Command-processing buffer. Use large buffers for all platforms.
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 3beada5bc9..ac0c1f6eb1 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) {
@@ -786,7 +786,7 @@ static int pum_set_selected(int n, int repeat)
// Return cursor to where we were
validate_cursor();
- redraw_later(SOME_VALID);
+ redraw_later(curwin, SOME_VALID);
// When the preview window was resized we need to
// update the view on the buffer. Only go back to
@@ -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 96c903d206..6ca97c3072 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3707,7 +3707,7 @@ static void qf_win_goto(win_T *win, linenr_T lnum)
curwin->w_cursor.coladd = 0;
curwin->w_curswant = 0;
update_topline(); // scroll to show the line
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
curwin->w_redr_status = true; // update ruler
curwin = old_curwin;
curbuf = curwin->w_buffer;
@@ -6317,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)
{
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 9f450888a2..36a6ae59f8 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -25,7 +25,7 @@
//
// Commands that scroll a window change w_topline and must call
// check_cursor() to move the cursor into the visible part of the window, and
-// call redraw_later(VALID) to have the window displayed by update_screen()
+// call redraw_later(wp, VALID) to have the window displayed by update_screen()
// later.
//
// Commands that change text in the buffer must call changed_bytes() or
@@ -37,7 +37,7 @@
//
// Commands that change how a window is displayed (e.g., setting 'list') or
// invalidate the contents of a window in another way (e.g., change fold
-// settings), must call redraw_later(NOT_VALID) to have the whole window
+// settings), must call redraw_later(wp, NOT_VALID) to have the whole window
// redisplayed by update_screen() later.
//
// Commands that change how a buffer is displayed (e.g., setting 'tabstop')
@@ -45,11 +45,11 @@
// buffer redisplayed by update_screen() later.
//
// Commands that change highlighting and possibly cause a scroll too must call
-// redraw_later(SOME_VALID) to update the whole window but still use scrolling
-// to avoid redrawing everything. But the length of displayed lines must not
-// change, use NOT_VALID then.
+// redraw_later(wp, SOME_VALID) to update the whole window but still use
+// scrolling to avoid redrawing everything. But the length of displayed lines
+// must not change, use NOT_VALID then.
//
-// Commands that move the window position must call redraw_later(NOT_VALID).
+// Commands that move the window position must call redraw_later(wp, NOT_VALID).
// TODO(neovim): should minimize redrawing by scrolling when possible.
//
// Commands that change everything (e.g., resizing the screen) must call
@@ -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_object_to_bool(ret, "provider %s retval", default_true, &err)) {
return true;
}
@@ -195,17 +195,11 @@ static bool provider_invoke(NS ns_id, const char *name, LuaRef ref,
return false;
}
-/*
- * Redraw the current window later, with update_screen(type).
- * Set must_redraw only if not already set to a higher value.
- * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
- */
-void redraw_later(int type)
-{
- redraw_win_later(curwin, type);
-}
-
-void redraw_win_later(win_T *wp, int type)
+/// Redraw a window later, with update_screen(type).
+///
+/// Set must_redraw only if not already set to a higher value.
+/// e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
+void redraw_later(win_T *wp, int type)
FUNC_ATTR_NONNULL_ALL
{
if (!exiting && wp->w_redr_type < type) {
@@ -223,7 +217,7 @@ void redraw_win_later(win_T *wp, int type)
void redraw_all_later(int type)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- redraw_win_later(wp, type);
+ redraw_later(wp, type);
}
// This may be needed when switching tabs.
if (must_redraw < type) {
@@ -234,7 +228,7 @@ void redraw_all_later(int type)
void screen_invalidate_highlights(void)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
wp->w_grid.valid = false;
}
}
@@ -251,7 +245,7 @@ void redraw_buf_later(buf_T *buf, int type)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer == buf) {
- redraw_win_later(wp, type);
+ redraw_later(wp, type);
}
}
}
@@ -277,7 +271,7 @@ void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline)
if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lastline) {
wp->w_redraw_bot = lastline;
}
- redraw_win_later(wp, VALID);
+ redraw_later(wp, VALID);
}
}
}
@@ -305,7 +299,7 @@ redrawWinline(
if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) {
wp->w_redraw_bot = lnum;
}
- redraw_win_later(wp, VALID);
+ redraw_later(wp, VALID);
}
}
@@ -359,7 +353,6 @@ int update_screen(int type)
/* Postpone the redrawing when it's not needed and when being called
* recursively. */
if (!redrawing() || updating_screen) {
- redraw_later(type); /* remember type for next time */
must_redraw = type;
if (type > INVERTED_ALL) {
curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now
@@ -501,6 +494,12 @@ int update_screen(int type)
}
}
+ // "start" callback could have changed highlights for global elements
+ if (win_check_ns_hl(NULL)) {
+ redraw_cmdline = true;
+ redraw_tabline = true;
+ }
+
if (clear_cmdline) /* going to clear cmdline (done below) */
check_for_delay(FALSE);
@@ -1331,6 +1330,8 @@ static void win_update(win_T *wp, Providers *providers)
}
}
+ win_check_ns_hl(wp);
+
for (;; ) {
/* stop updating when reached the end of the window (check for _past_
@@ -2185,6 +2186,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// return 'false' or error: skip rest of this window
kv_A(*providers, k) = NULL;
}
+
+ win_check_ns_hl(wp);
}
}
@@ -4649,8 +4652,8 @@ void status_redraw_all(void)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_status_height) {
- wp->w_redr_status = TRUE;
- redraw_later(VALID);
+ wp->w_redr_status = true;
+ redraw_later(wp, VALID);
}
}
}
@@ -4667,7 +4670,7 @@ void status_redraw_buf(buf_T *buf)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_status_height != 0 && wp->w_buffer == buf) {
wp->w_redr_status = true;
- redraw_later(VALID);
+ redraw_later(wp, VALID);
}
}
}
@@ -5191,8 +5194,8 @@ win_redr_custom (
char_u buf[MAXPATHL];
char_u *stl;
char_u *p;
- struct stl_hlrec hltab[STL_MAX_ITEM];
- StlClickRecord tabtab[STL_MAX_ITEM];
+ stl_hlrec_t *hltab;
+ StlClickRecord *tabtab;
int use_sandbox = false;
win_T *ewp;
int p_crb_save;
@@ -5270,9 +5273,9 @@ win_redr_custom (
/* Make a copy, because the statusline may include a function call that
* might change the option value and free the memory. */
stl = vim_strsave(stl);
- width = build_stl_str_hl(ewp, buf, sizeof(buf),
- stl, use_sandbox,
- fillchar, maxwidth, hltab, tabtab);
+ width =
+ build_stl_str_hl(ewp, buf, sizeof(buf), stl, use_sandbox,
+ fillchar, maxwidth, &hltab, &tabtab);
xfree(stl);
ewp->w_p_crb = p_crb_save;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 9458e6333f..b25333c9fa 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -4923,7 +4923,7 @@ search_line:
&& curwin != curwin_save && win_valid(curwin_save)) {
/* Return cursor to where we were */
validate_cursor();
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
win_enter(curwin_save, true);
}
break;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 1984a357c3..636c71657d 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -2258,7 +2258,7 @@ char_u *did_set_spelllang(win_T *wp)
theend:
xfree(spl_copy);
recursive = false;
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
return ret_msg;
}
@@ -6877,7 +6877,7 @@ void ex_spelldump(exarg_T *eap)
if (curbuf->b_ml.ml_line_count > 1) {
ml_delete(curbuf->b_ml.ml_line_count, false);
}
- redraw_later(NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
// Go through all possible words and:
diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h
index 034c580b3e..05667f060e 100644
--- a/src/nvim/spell_defs.h
+++ b/src/nvim/spell_defs.h
@@ -119,6 +119,7 @@ struct slang_S {
bool sl_add; // true if it's a .add file.
char_u *sl_fbyts; // case-folded word bytes
+ long sl_fbyts_len; // length of sl_fbyts
idx_T *sl_fidxs; // case-folded word indexes
char_u *sl_kbyts; // keep-case word bytes
idx_T *sl_kidxs; // keep-case word indexes
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 09d8646c6d..b415a4635b 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -764,20 +764,24 @@ truncerr:
}
// <LWORDTREE>
- res = spell_read_tree(fd, &lp->sl_fbyts, &lp->sl_fidxs, false, 0);
- if (res != 0)
+ res = spell_read_tree(fd, &lp->sl_fbyts, &lp->sl_fbyts_len,
+ &lp->sl_fidxs, false, 0);
+ if (res != 0) {
goto someerror;
+ }
// <KWORDTREE>
- res = spell_read_tree(fd, &lp->sl_kbyts, &lp->sl_kidxs, false, 0);
- if (res != 0)
+ res = spell_read_tree(fd, &lp->sl_kbyts, NULL, &lp->sl_kidxs, false, 0);
+ if (res != 0) {
goto someerror;
+ }
// <PREFIXTREE>
- res = spell_read_tree(fd, &lp->sl_pbyts, &lp->sl_pidxs, true,
- lp->sl_prefixcnt);
- if (res != 0)
+ res = spell_read_tree(fd, &lp->sl_pbyts, NULL, &lp->sl_pidxs, true,
+ lp->sl_prefixcnt);
+ if (res != 0) {
goto someerror;
+ }
// For a new file link it in the list of spell files.
if (old_lp == NULL && lang != NULL) {
@@ -920,8 +924,8 @@ void suggest_load_files(void)
// <SUGWORDTREE>: <wordtree>
// Read the trie with the soundfolded words.
- if (spell_read_tree(fd, &slang->sl_sbyts, &slang->sl_sidxs,
- false, 0) != 0) {
+ if (spell_read_tree(fd, &slang->sl_sbyts, NULL, &slang->sl_sidxs,
+ false, 0) != 0) {
someerror:
EMSG2(_("E782: error while reading .sug file: %s"),
slang->sl_fname);
@@ -1630,10 +1634,12 @@ static int
spell_read_tree (
FILE *fd,
char_u **bytsp,
+ long *bytsp_len,
idx_T **idxsp,
bool prefixtree, // true for the prefix tree
int prefixcnt // when "prefixtree" is true: prefix count
)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{
int idx;
char_u *bp;
@@ -1653,6 +1659,9 @@ spell_read_tree (
// Allocate the byte array.
bp = xmalloc(len);
*bytsp = bp;
+ if (bytsp_len != NULL) {
+ *bytsp_len = len;
+ }
// Allocate the index array.
ip = xcalloc(len, sizeof(*ip));
@@ -4850,10 +4859,10 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
spin->si_blocks_cnt = 0;
// Skip over any other NUL bytes (same word with different
- // flags).
- while (byts[n + 1] == 0) {
- ++n;
- ++curi[depth];
+ // flags). But don't go over the end.
+ while (n + 1 < slang->sl_fbyts_len && byts[n + 1] == 0) {
+ n++;
+ curi[depth]++;
}
} else {
// Normal char, go one level deeper.
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 9a9cc45c6b..ec6accd473 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -73,9 +73,9 @@ struct hl_group {
RgbValue sg_rgb_fg; ///< RGB foreground color
RgbValue sg_rgb_bg; ///< RGB background color
RgbValue sg_rgb_sp; ///< RGB special color
- uint8_t *sg_rgb_fg_name; ///< RGB foreground color name
- uint8_t *sg_rgb_bg_name; ///< RGB background color name
- uint8_t *sg_rgb_sp_name; ///< RGB special color name
+ char *sg_rgb_fg_name; ///< RGB foreground color name
+ char *sg_rgb_bg_name; ///< RGB background color name
+ char *sg_rgb_sp_name; ///< RGB special color name
int sg_blend; ///< blend level (0-100 inclusive), -1 if unset
};
@@ -3147,7 +3147,7 @@ static void syn_cmd_spell(exarg_T *eap, int syncing)
}
// assume spell checking changed, force a redraw
- redraw_win_later(curwin, NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
/// Handle ":syntax iskeyword" command.
@@ -3187,7 +3187,7 @@ static void syn_cmd_iskeyword(exarg_T *eap, int syncing)
curbuf->b_p_isk = save_isk;
}
}
- redraw_win_later(curwin, NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
}
/*
@@ -4297,7 +4297,7 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
prev_toplvl_grp = curwin->w_s->b_syn_topgrp;
curwin->w_s->b_syn_topgrp = sgl_id;
if (source ? do_source(eap->arg, false, DOSO_NONE) == FAIL
- : source_runtime(eap->arg, DIP_ALL) == FAIL) {
+ : source_in_path(p_rtp, eap->arg, DIP_ALL) == FAIL) {
EMSG2(_(e_notopen), eap->arg);
}
curwin->w_s->b_syn_topgrp = prev_toplvl_grp;
@@ -6899,7 +6899,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
}
}
} else if (strcmp(key, "GUIFG") == 0) {
- char_u **const namep = &HL_TABLE()[idx].sg_rgb_fg_name;
+ char **namep = &HL_TABLE()[idx].sg_rgb_fg_name;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
if (!init) {
@@ -6909,8 +6909,8 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (*namep == NULL || STRCMP(*namep, arg) != 0) {
xfree(*namep);
if (strcmp(arg, "NONE") != 0) {
- *namep = (char_u *)xstrdup(arg);
- HL_TABLE()[idx].sg_rgb_fg = name_to_color((char_u *)arg);
+ *namep = xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_fg = name_to_color(arg);
} else {
*namep = NULL;
HL_TABLE()[idx].sg_rgb_fg = -1;
@@ -6923,7 +6923,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
normal_fg = HL_TABLE()[idx].sg_rgb_fg;
}
} else if (STRCMP(key, "GUIBG") == 0) {
- char_u **const namep = &HL_TABLE()[idx].sg_rgb_bg_name;
+ char **const namep = &HL_TABLE()[idx].sg_rgb_bg_name;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
if (!init) {
@@ -6933,8 +6933,8 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (*namep == NULL || STRCMP(*namep, arg) != 0) {
xfree(*namep);
if (STRCMP(arg, "NONE") != 0) {
- *namep = (char_u *)xstrdup(arg);
- HL_TABLE()[idx].sg_rgb_bg = name_to_color((char_u *)arg);
+ *namep = xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_bg = name_to_color(arg);
} else {
*namep = NULL;
HL_TABLE()[idx].sg_rgb_bg = -1;
@@ -6947,7 +6947,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
normal_bg = HL_TABLE()[idx].sg_rgb_bg;
}
} else if (strcmp(key, "GUISP") == 0) {
- char_u **const namep = &HL_TABLE()[idx].sg_rgb_sp_name;
+ char **const namep = &HL_TABLE()[idx].sg_rgb_sp_name;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
if (!init) {
@@ -6957,8 +6957,8 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (*namep == NULL || STRCMP(*namep, arg) != 0) {
xfree(*namep);
if (strcmp(arg, "NONE") != 0) {
- *namep = (char_u *)xstrdup(arg);
- HL_TABLE()[idx].sg_rgb_sp = name_to_color((char_u *)arg);
+ *namep = xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_sp = name_to_color(arg);
} else {
*namep = NULL;
HL_TABLE()[idx].sg_rgb_sp = -1;
@@ -7152,13 +7152,32 @@ static void highlight_list_one(const int id)
msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
}
- if (!didh)
- highlight_list_arg(id, didh, LIST_STRING, 0, (char_u *)"cleared", "");
+ if (!didh) {
+ highlight_list_arg(id, didh, LIST_STRING, 0, "cleared", "");
+ }
if (p_verbose > 0) {
last_set_msg(sgp->sg_script_ctx);
}
}
+Dictionary get_global_hl_defs(void)
+{
+ Dictionary rv = ARRAY_DICT_INIT;
+ for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
+ Dictionary attrs = ARRAY_DICT_INIT;
+ struct hl_group *h = &HL_TABLE()[i - 1];
+ if (h->sg_attr > 0) {
+ attrs = hlattrs2dict(syn_attr2entry(h->sg_attr), true);
+ } else if (h->sg_link > 0) {
+ const char *link = (const char *)HL_TABLE()[h->sg_link - 1].sg_name;
+ PUT(attrs, "link", STRING_OBJ(cstr_to_string(link)));
+ }
+ PUT(rv, (const char *)h->sg_name, DICTIONARY_OBJ(attrs));
+ }
+
+ return rv;
+}
+
/// Outputs a highlight when doing ":hi MyHighlight"
///
/// @param type one of \ref LIST_XXX
@@ -7166,15 +7185,15 @@ static void highlight_list_one(const int id)
/// @param sarg string used if \p type == LIST_STRING
static bool highlight_list_arg(
const int id, bool didh, const int type, int iarg,
- char_u *const sarg, const char *const name)
+ char *const sarg, const char *const name)
{
- char_u buf[100];
+ char buf[100];
if (got_int) {
return false;
}
if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0)) {
- char_u *ts = buf;
+ char *ts = buf;
if (type == LIST_INT) {
snprintf((char *)buf, sizeof(buf), "%d", iarg - 1);
} else if (type == LIST_STRING) {
@@ -7191,15 +7210,15 @@ static bool highlight_list_arg(
}
}
- (void)syn_list_header(didh, (int)(vim_strsize(ts) + STRLEN(name) + 1), id,
- false);
+ (void)syn_list_header(didh, (int)(vim_strsize((char_u *)ts) + STRLEN(name)
+ + 1), id, false);
didh = true;
if (!got_int) {
if (*name != NUL) {
MSG_PUTS_ATTR(name, HL_ATTR(HLF_D));
MSG_PUTS_ATTR("=", HL_ATTR(HLF_D));
}
- msg_outtrans(ts);
+ msg_outtrans((char_u *)ts);
}
}
return didh;
@@ -7378,7 +7397,7 @@ static void set_hl_attr(int idx)
at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1;
at_en.hl_blend = sgp->sg_blend;
- sgp->sg_attr = hl_get_syn_attr(idx+1, at_en);
+ sgp->sg_attr = hl_get_syn_attr(0, idx+1, at_en);
// a cursor style uses this syn_id, make sure its attribute is updated.
if (cursor_mode_uses_syn_id(idx+1)) {
@@ -7541,11 +7560,17 @@ int syn_id2attr(int hl_id)
struct hl_group *sgp;
hl_id = syn_get_final_id(hl_id);
- sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
+ int attr = ns_get_hl(-1, hl_id, false);
+ if (attr >= 0) {
+ return attr;
+ }
+ sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
return sgp->sg_attr;
}
+
+
/*
* Translate a group ID to the final group ID (following links).
*/
@@ -7562,9 +7587,22 @@ int syn_get_final_id(int hl_id)
* Look out for loops! Break after 100 links.
*/
for (count = 100; --count >= 0; ) {
- sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
- if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len)
+ // ACHTUNG: when using "tmp" attribute (no link) the function might be
+ // called twice. it needs be smart enough to remember attr only to
+ // syn_id2attr time
+ int check = ns_get_hl(-1, hl_id, true);
+ if (check == 0) {
+ return 0; // how dare! it broke the link!
+ } else if (check > 0) {
+ hl_id = check;
+ continue;
+ }
+
+
+ sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
+ if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) {
break;
+ }
hl_id = sgp->sg_link;
}
@@ -8494,7 +8532,7 @@ color_name_table_T color_name_table[] = {
///
/// @param[in] name string value to convert to RGB
/// return the hex value or -1 if could not find a correct value
-RgbValue name_to_color(const char_u *name)
+RgbValue name_to_color(const char *name)
{
if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2])
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 81d1ef4c9f..c6b1a0d04c 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -2903,7 +2903,7 @@ static int jumpto_tag(
&& curwin != curwin_save && win_valid(curwin_save)) {
/* Return cursor to where we were */
validate_cursor();
- redraw_later(VALID);
+ redraw_later(curwin, VALID);
win_enter(curwin_save, true);
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 52d3eef810..39e2ca6171 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -233,7 +233,7 @@ Terminal *terminal_open(TerminalOptions opts)
snprintf(var, sizeof(var), "terminal_color_%d", i);
char *name = get_config_string(var);
if (name) {
- color_val = name_to_color((uint8_t *)name);
+ color_val = name_to_color(name);
xfree(name);
if (color_val != -1) {
@@ -1060,7 +1060,7 @@ static bool send_mouse_event(Terminal *term, int c)
curwin->w_redr_status = true;
curwin = save_curwin;
curbuf = curwin->w_buffer;
- redraw_win_later(mouse_win, NOT_VALID);
+ redraw_later(mouse_win, NOT_VALID);
invalidate_terminal(term, -1, -1);
// Only need to exit focus if the scrolled window is the terminal window
return mouse_win == curwin;
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_cindent.vim b/src/nvim/testdir/test_cindent.vim
index debc9da46d..b6c2d1467e 100644
--- a/src/nvim/testdir/test_cindent.vim
+++ b/src/nvim/testdir/test_cindent.vim
@@ -127,4 +127,40 @@ func Test_cindent_case()
bwipe!
endfunc
+func Test_cindent_pragma()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=Ps
+
+ let code =<< trim [CODE]
+ {
+ #pragma omp parallel
+ {
+ #pragma omp task
+ foo();
+ # pragma omp taskwait
+ }
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal =G
+
+ let expected =<< trim [CODE]
+ {
+ #pragma omp parallel
+ {
+ #pragma omp task
+ foo();
+ # pragma omp taskwait
+ }
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+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_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 871143699a..e3c42a4fe3 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -722,7 +722,7 @@ func Test_verbosefile()
endfunc
func Test_verbose_option()
- " See test/functional/ui/cmdline_spec.lua
+ " See test/functional/legacy/cmdline_spec.lua
CheckScreendump
let lines =<< trim [SCRIPT]
@@ -842,6 +842,25 @@ func Test_buffers_lastused()
bwipeout bufc
endfunc
+func Test_cmdlineclear_tabenter()
+ " See test/functional/legacy/cmdline_spec.lua
+ CheckScreendump
+
+ let lines =<< trim [SCRIPT]
+ call setline(1, range(30))
+ [SCRIPT]
+
+ call writefile(lines, 'XtestCmdlineClearTabenter')
+ let buf = RunVimInTerminal('-S XtestCmdlineClearTabenter', #{rows: 10})
+ call term_wait(buf, 50)
+ " in one tab make the command line higher with CTRL-W -
+ call term_sendkeys(buf, ":tabnew\<cr>\<C-w>-\<C-w>-gtgt")
+ call VerifyScreenDump(buf, 'Test_cmdlineclear_tabenter', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XtestCmdlineClearTabenter')
+endfunc
+
" test that ";" works to find a match at the start of the first line
func Test_zero_line_search()
new
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index caebc341e0..abad6983dc 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
@@ -1578,4 +1587,11 @@ func Test_edit_browse()
bwipe!
endfunc
+func Test_read_invalid()
+ " set encoding=latin1
+ " This was not properly checking for going past the end.
+ call assert_fails('r`=', 'E484')
+ set encoding=utf-8
+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_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
index 1339a9f25d..57a0a7aaf4 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,11 +339,94 @@ 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
+" Test for insert path completion with completeslash option
+func Test_ins_completeslash()
+ CheckMSWindows
+
+ call mkdir('Xdir')
+
+ let orig_shellslash = &shellslash
+ set cpt&
+
+ new
+
+ set noshellslash
+
+ set completeslash=
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir\', getline('.'))
+
+ set completeslash=backslash
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir\', getline('.'))
+
+ set completeslash=slash
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir/', getline('.'))
+
+ set shellslash
+
+ set completeslash=
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir/', getline('.'))
+
+ set completeslash=backslash
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir\', getline('.'))
+
+ set completeslash=slash
+ exe "normal oXd\<C-X>\<C-F>"
+ call assert_equal('Xdir/', getline('.'))
+ %bw!
+ call delete('Xdir', 'rf')
+
+ set noshellslash
+ set completeslash=slash
+ call assert_true(stridx(globpath(&rtp, 'syntax/*.vim', 1, 1)[0], '\') != -1)
+
+ let &shellslash = orig_shellslash
+ set completeslash=
+endfunc
+
+func Test_issue_7021()
+ CheckMSWindows
+
+ let orig_shellslash = &shellslash
+ set noshellslash
+
+ set completeslash=slash
+ call assert_false(expand('~') =~ '/')
+
+ let &shellslash = orig_shellslash
+ set completeslash=
+endfunc
+
func Test_pum_with_folds_two_tabs()
CheckScreendump
diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim
index 31a8b48d37..8e2a987e74 100644
--- a/src/nvim/testdir/test_listdict.vim
+++ b/src/nvim/testdir/test_listdict.vim
@@ -199,9 +199,9 @@ func Test_dict_big()
try
let n = d[1500]
catch
- let str=substitute(v:exception, '\v(.{14}).*( \d{4}).*', '\1\2', '')
+ let str = substitute(v:exception, '\v(.{14}).*( "\d{4}").*', '\1\2', '')
endtry
- call assert_equal('Vim(let):E716: 1500', str)
+ call assert_equal('Vim(let):E716: "1500"', str)
" lookup each items
for i in range(1500)
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 7fbf04311d..30239a90c2 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -1,20 +1,16 @@
" Tests for :messages, :echomsg, :echoerr
-function Test_messages()
+source shared.vim
+
+func Test_messages()
let oldmore = &more
try
set nomore
- " Avoid the "message maintainer" line.
- let $LANG = ''
- let $LC_ALL = ''
- let $LC_MESSAGES = ''
- let $LC_COLLATE = ''
let arr = map(range(10), '"hello" . v:val')
for s in arr
echomsg s | redraw
endfor
- let result = ''
" get last two messages
redir => result
@@ -25,22 +21,17 @@ function Test_messages()
" clear messages without last one
1messages clear
- redir => result
- redraw | messages
- redir END
- let msg_list = split(result, "\n")
+ let msg_list = GetMessages()
call assert_equal(['hello9'], msg_list)
" clear all messages
messages clear
- redir => result
- redraw | messages
- redir END
- call assert_equal('', result)
+ let msg_list = GetMessages()
+ call assert_equal([], msg_list)
finally
let &more = oldmore
endtry
-endfunction
+endfunc
" Patch 7.4.1696 defined the "clearmode()" command for clearing the mode
" indicator (e.g., "-- INSERT --") when ":stopinsert" is invoked. Message
@@ -74,6 +65,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_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 3243edbf55..215065f941 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -470,4 +470,17 @@ func Test_mkvimrc()
call delete('Xtestvimrc')
endfunc
+func Test_scrolloff()
+ set sessionoptions+=localoptions
+ setlocal so=1 siso=1
+ mksession! Xtest_mks.out
+ setlocal so=-1 siso=-1
+ source Xtest_mks.out
+ call assert_equal(1, &l:so)
+ call assert_equal(1, &l:siso)
+ call delete('Xtest_mks.out')
+ setlocal so& siso&
+ set sessionoptions&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 9e8da74db7..10e16f4198 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -267,7 +267,6 @@ func Test_set_errors()
call assert_fails('set commentstring=x', 'E537:')
call assert_fails('set complete=x', 'E539:')
call assert_fails('set statusline=%{', 'E540:')
- call assert_fails('set statusline=' . repeat("%p", 81), 'E541:')
call assert_fails('set statusline=%(', 'E542:')
if has('cursorshape')
" This invalid value for 'guicursor' used to cause Vim to crash.
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index cf0af07528..049163890e 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -3602,6 +3602,10 @@ func Test_lhelpgrep_autocmd()
au BufEnter * call setqflist([], 'f')
augroup END
call assert_fails('helpgrep quickfix', 'E925:')
+ " run the test with a help window already open
+ help
+ wincmd w
+ call assert_fails('helpgrep quickfix', 'E925:')
augroup QF_Test
au! BufEnter
augroup END
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index d20f8d1eef..19a7c6c9d0 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -167,6 +167,75 @@ func Test_set_register()
enew!
endfunc
+func Test_v_register()
+ enew
+ call setline(1, 'nothing')
+
+ func s:Put()
+ let s:register = v:register
+ exec 'normal! "' .. v:register .. 'P'
+ endfunc
+ nnoremap <buffer> <plug>(test) :<c-u>call s:Put()<cr>
+ nmap <buffer> S <plug>(test)
+
+ let @z = "testz\n"
+ let @" = "test@\n"
+
+ let s:register = ''
+ call feedkeys('"_ddS', 'mx')
+ call assert_equal('test@', getline('.')) " fails before 8.2.0929
+ call assert_equal('"', s:register) " fails before 8.2.0929
+
+ let s:register = ''
+ call feedkeys('"zS', 'mx')
+ call assert_equal('z', s:register)
+
+ let s:register = ''
+ call feedkeys('"zSS', 'mx')
+ call assert_equal('"', s:register)
+
+ let s:register = ''
+ call feedkeys('"_S', 'mx')
+ call assert_equal('_', s:register)
+
+ let s:register = ''
+ normal "_ddS
+ call assert_equal('"', s:register) " fails before 8.2.0929
+ call assert_equal('test@', getline('.')) " fails before 8.2.0929
+
+ let s:register = ''
+ execute 'normal "z:call' "s:Put()\n"
+ call assert_equal('z', s:register)
+ call assert_equal('testz', getline('.'))
+
+ " Test operator and omap
+ let @b = 'testb'
+ func s:OpFunc(...)
+ let s:register2 = v:register
+ endfunc
+ set opfunc=s:OpFunc
+
+ normal "bg@l
+ normal S
+ call assert_equal('"', s:register) " fails before 8.2.0929
+ call assert_equal('b', s:register2)
+
+ func s:Motion()
+ let s:register1 = v:register
+ normal! l
+ endfunc
+ onoremap <buffer> Q :<c-u>call s:Motion()<cr>
+
+ normal "bg@Q
+ normal S
+ call assert_equal('"', s:register)
+ call assert_equal('b', s:register1)
+ call assert_equal('"', s:register2)
+
+ set opfunc&
+ bwipe!
+endfunc
+
func Test_ve_blockpaste()
new
set ve=all
diff --git a/src/nvim/testdir/test_ruby.vim b/src/nvim/testdir/test_ruby.vim
index 77a42e0a8a..9c74c35049 100644
--- a/src/nvim/testdir/test_ruby.vim
+++ b/src/nvim/testdir/test_ruby.vim
@@ -1,15 +1,7 @@
" Tests for ruby interface
-if !has('ruby')
- finish
-end
-
-" Helper function as there is no builtin rubyeval() function similar
-" to perleval, luaevel() or pyeval().
-func RubyEval(ruby_expr)
- let s = split(execute('ruby print ' . a:ruby_expr), "\n")
- return (len(s) == 0) ? '' : s[-1]
-endfunc
+source check.vim
+CheckFeature ruby
func Test_ruby_change_buffer()
call setline(line('$'), ['1 line 1'])
@@ -43,19 +35,19 @@ func Test_rubyfile()
call delete(tempfile)
endfunc
-func Test_set_cursor()
+func Test_ruby_set_cursor()
" Check that setting the cursor position works.
new
call setline(1, ['first line', 'second line'])
normal gg
rubydo $curwin.cursor = [1, 5]
call assert_equal([1, 6], [line('.'), col('.')])
- call assert_equal('[1, 5]', RubyEval('$curwin.cursor'))
+ 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_equal([2, 5], rubyeval('$curwin.cursor'))
" call assert_fails('ruby $curwin.cursor = [1]',
" \ 'ArgumentError: array length must be 2')
@@ -63,34 +55,34 @@ func Test_set_cursor()
endfunc
" Test buffer.count and buffer.length (number of lines in buffer)
-func Test_buffer_count()
+func Test_ruby_buffer_count()
new
call setline(1, ['one', 'two', 'three'])
- call assert_equal('3', RubyEval('$curbuf.count'))
- call assert_equal('3', RubyEval('$curbuf.length'))
+ 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()
+func Test_ruby_buffer_name()
new Xfoo
- call assert_equal(expand('%:p'), RubyEval('$curbuf.name'))
+ call assert_equal(expand('%:p'), rubyeval('$curbuf.name'))
bwipe
- call assert_equal('', RubyEval('$curbuf.name'))
+ call assert_equal('', rubyeval('$curbuf.name'))
endfunc
" Test buffer.number (number of the buffer).
-func Test_buffer_number()
+func Test_ruby_buffer_number()
new
- call assert_equal(string(bufnr('%')), RubyEval('$curbuf.number'))
+ call assert_equal(bufnr('%'), rubyeval('$curbuf.number'))
new
- call assert_equal(string(bufnr('%')), RubyEval('$curbuf.number'))
+ call assert_equal(bufnr('%'), rubyeval('$curbuf.number'))
%bwipe
endfunc
" Test buffer.delete({n}) (delete line {n})
-func Test_buffer_delete()
+func Test_ruby_buffer_delete()
new
call setline(1, ['one', 'two', 'three'])
ruby $curbuf.delete(2)
@@ -104,7 +96,7 @@ func Test_buffer_delete()
endfunc
" Test buffer.append({str}, str) (append line {str} after line {n})
-func Test_buffer_append()
+func Test_ruby_buffer_append()
new
ruby $curbuf.append(0, 'one')
ruby $curbuf.append(1, 'three')
@@ -124,11 +116,11 @@ func Test_buffer_append()
endfunc
" Test buffer.line (get or set the current line)
-func Test_buffer_line()
+func Test_ruby_buffer_line()
new
call setline(1, ['one', 'two', 'three'])
2
- call assert_equal('two', RubyEval('$curbuf.line'))
+ call assert_equal('two', rubyeval('$curbuf.line'))
ruby $curbuf.line = 'TWO'
call assert_equal(['one', 'TWO', 'three'], getline(1, '$'))
@@ -137,20 +129,20 @@ func Test_buffer_line()
endfunc
" Test buffer.line_number (get current line number)
-func Test_buffer_line_number()
+func Test_ruby_buffer_line_number()
new
call setline(1, ['one', 'two', 'three'])
2
- call assert_equal('2', RubyEval('$curbuf.line_number'))
+ call assert_equal(2, rubyeval('$curbuf.line_number'))
bwipe!
endfunc
-func Test_buffer_get()
+func Test_ruby_buffer_get()
new
call setline(1, ['one', 'two'])
- call assert_equal('one', RubyEval('$curbuf[1]'))
- call assert_equal('two', RubyEval('$curbuf[2]'))
+ 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')
@@ -160,7 +152,7 @@ func Test_buffer_get()
bwipe!
endfunc
-func Test_buffer_set()
+func Test_ruby_buffer_set()
new
call setline(1, ['one', 'two'])
ruby $curbuf[2] = 'TWO'
@@ -176,7 +168,7 @@ func Test_buffer_set()
endfunc
" Test window.width (get or set window height).
-func Test_window_height()
+func Test_ruby_window_height()
new
" Test setting window height
@@ -184,13 +176,13 @@ func Test_window_height()
call assert_equal(2, winheight(0))
" Test getting window height
- call assert_equal('2', RubyEval('$curwin.height'))
+ call assert_equal(2, rubyeval('$curwin.height'))
bwipe
endfunc
" Test window.width (get or set window width).
-func Test_window_width()
+func Test_ruby_window_width()
vnew
" Test setting window width
@@ -198,13 +190,13 @@ func Test_window_width()
call assert_equal(2, winwidth(0))
" Test getting window width
- call assert_equal('2', RubyEval('$curwin.width'))
+ call assert_equal(2, rubyeval('$curwin.width'))
bwipe
endfunc
" Test window.buffer (get buffer object of a window object).
-func Test_window_buffer()
+func Test_ruby_window_buffer()
new Xfoo1
new Xfoo2
ruby $b2 = $curwin.buffer
@@ -213,69 +205,69 @@ func Test_window_buffer()
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(string(bufnr('Xfoo1')), RubyEval('$w1.buffer.number'))
- call assert_equal(string(bufnr('Xfoo2')), RubyEval('$w2.buffer.number'))
+ " 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')
- " call assert_equal(cw, RubyEval('Vim::Window.current'))
+func Test_ruby_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()
+func Test_ruby_Vim_window_count()
new Xfoo1
new Xfoo2
split
- call assert_equal('4', RubyEval('Vim::Window.count'))
+ call assert_equal(4, rubyeval('Vim::Window.count'))
%bwipe
- call assert_equal('1', RubyEval('Vim::Window.count'))
+ call assert_equal(1, rubyeval('Vim::Window.count'))
endfunc
" Test Vim::Window[n] (get window object of window n)
-func Test_Vim_window_get()
+func Test_ruby_Vim_window_get()
new Xfoo1
new Xfoo2
- call assert_match('Xfoo2$', RubyEval('Vim::Window[0].buffer.name'))
+ call assert_match('Xfoo2$', rubyeval('Vim::Window[0].buffer.name'))
wincmd j
- call assert_match('Xfoo1$', RubyEval('Vim::Window[1].buffer.name'))
+ call assert_match('Xfoo1$', rubyeval('Vim::Window[1].buffer.name'))
wincmd j
- call assert_equal('', RubyEval('Vim::Window[2].buffer.name'))
+ 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')
- " call assert_equal(cb, RubyEval('Vim::Buffer.current'))
+func Test_ruby_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()
+func Test_ruby_Vim_buffer_count()
new Xfoo1
new Xfoo2
- call assert_equal('3', RubyEval('Vim::Buffer.count'))
+ call assert_equal(3, rubyeval('Vim::Buffer.count'))
%bwipe
- call assert_equal('1', RubyEval('Vim::Buffer.count'))
+ 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()
+func Test_ruby_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_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
@@ -283,7 +275,7 @@ endfunc
" Test Vim::command({cmd}) (execute a Ex command))
" Test Vim::command({cmd})
-func Test_Vim_command()
+func Test_ruby_Vim_command()
new
call setline(1, ['one', 'two', 'three', 'four'])
ruby Vim::command('2,3d')
@@ -292,7 +284,7 @@ func Test_Vim_command()
endfunc
" Test Vim::set_option (set a vim option)
-func Test_Vim_set_option()
+func Test_ruby_Vim_set_option()
call assert_equal(0, &number)
ruby Vim::set_option('number')
call assert_equal(1, &number)
@@ -300,37 +292,39 @@ func Test_Vim_set_option()
call assert_equal(0, &number)
endfunc
-func Test_Vim_evaluate()
- call assert_equal('123', RubyEval('Vim::evaluate("123")'))
+func Test_ruby_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_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'))
+ if has('float')
+ call assert_equal(1.23, rubyeval('Vim::evaluate("1.23")'))
+ call assert_equal('Float', rubyeval('Vim::evaluate("1.23").class'))
+ endif
- call assert_equal('foo', RubyEval('Vim::evaluate("\"foo\"")'))
- call assert_equal('String', RubyEval('Vim::evaluate("\"foo\"").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('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({'1': 2}, rubyeval('Vim::evaluate("{1:2}")'))
+ call assert_equal('Hash', rubyeval('Vim::evaluate("{1:2}").class'))
- call assert_equal('', RubyEval('Vim::evaluate("v:null")'))
- call assert_equal('NilClass', RubyEval('Vim::evaluate("v:null").class'))
+ call assert_equal(v:null, rubyeval('Vim::evaluate("v:null")'))
+ call assert_equal('NilClass', rubyeval('Vim::evaluate("v:null").class'))
- " call assert_equal('', RubyEval('Vim::evaluate("v:none")'))
- " call assert_equal('NilClass', RubyEval('Vim::evaluate("v:none").class'))
+ " call assert_equal(v:null, rubyeval('Vim::evaluate("v:none")'))
+ " call assert_equal('NilClass', rubyeval('Vim::evaluate("v:none").class'))
- call assert_equal('true', RubyEval('Vim::evaluate("v:true")'))
- call assert_equal('TrueClass', RubyEval('Vim::evaluate("v:true").class'))
- call assert_equal('false', RubyEval('Vim::evaluate("v:false")'))
- call assert_equal('FalseClass',RubyEval('Vim::evaluate("v:false").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()
+func Test_ruby_Vim_evaluate_list()
call setline(line('$'), ['2 line 2'])
ruby Vim.command("normal /^2\n")
let l = ["abc", "def"]
@@ -344,7 +338,7 @@ EOF
call assert_equal('abc/def', getline('$'))
endfunc
-func Test_Vim_evaluate_dict()
+func Test_ruby_Vim_evaluate_dict()
let d = {'a': 'foo', 'b': 123}
redir => l:out
ruby d = Vim.evaluate("d"); print d
@@ -353,34 +347,47 @@ func Test_Vim_evaluate_dict()
endfunc
" Test Vim::message({msg}) (display message {msg})
-func Test_Vim_message()
+func Test_ruby_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()
- ruby print "Hello World!"
- let messages = split(execute('message'), "\n")
- call assert_equal('Hello World!', messages[-1])
+func Test_ruby_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()
+func Test_ruby_p()
ruby p 'Just a test'
- let messages = split(execute('message'), "\n")
+ let messages = GetMessages()
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)'))
+ 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('true', RubyEval('p() == nil'))
+ call assert_equal(v:true, rubyeval('p() == nil'))
- let messages = split(execute('message'), "\n")
+ let messages = GetMessages()
call assert_equal(0, len(messages))
endfunc
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index 7efd181d04..4e38f7ebd8 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -354,6 +354,21 @@ func Test_statusline()
delfunc GetNested
delfunc GetStatusLine
+ " Test statusline works with 80+ items
+ function! StatusLabel()
+ redrawstatus
+ return '[label]'
+ endfunc
+ let statusline = '%{StatusLabel()}'
+ for i in range(150)
+ let statusline .= '%#TabLine' . (i % 2 == 0 ? 'Fill' : 'Sel') . '#' . string(i)[0]
+ endfor
+ let &statusline = statusline
+ redrawstatus
+ set statusline&
+ delfunc StatusLabel
+
+
" Check statusline in current and non-current window
" with the 'fillchars' option.
set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:-
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 2ef9bf5a2e..62d7dc8b18 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -316,7 +316,13 @@ static void terminfo_start(UI *ui)
#ifdef WIN32
uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW);
#else
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ int retry_count = 10;
+ // A signal may cause uv_tty_set_mode() to fail (e.g., SIGCONT). Retry a
+ // few times. #12322
+ while (uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO) == UV_EINTR
+ && retry_count > 0) {
+ retry_count--;
+ }
#endif
} else {
uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
@@ -1102,6 +1108,15 @@ static void tui_set_mode(UI *ui, ModeShape mode)
static void tui_mode_change(UI *ui, String mode, Integer mode_idx)
{
TUIData *data = ui->data;
+#ifdef UNIX
+ // If stdin is not a TTY, the LHS of pipe may change the state of the TTY
+ // after calling uv_tty_set_mode. So, set the mode of the TTY again here.
+ // #13073
+ if (data->is_starting && data->input.in_fd == STDERR_FILENO) {
+ uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL);
+ uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ }
+#endif
tui_set_mode(ui, (ModeShape)mode_idx);
data->is_starting = false; // mode entered, no longer starting
data->showing_mode = (ModeShape)mode_idx;
diff --git a/src/nvim/types.h b/src/nvim/types.h
index a3d87f35ca..17f7e16740 100644
--- a/src/nvim/types.h
+++ b/src/nvim/types.h
@@ -21,7 +21,7 @@ typedef int handle_T;
// absent callback etc.
typedef int LuaRef;
-typedef uint64_t NS;
+typedef handle_T NS;
typedef struct expand expand_T;
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index e582d8f859..325ad31eaf 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -26,6 +26,7 @@
#include "nvim/screen.h"
#include "nvim/syntax.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/lua/executor.h"
#include "nvim/os/os.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 6c5a6cdb46..a8b8f7aa50 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2455,7 +2455,7 @@ static void u_undo_end(
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer == curbuf && wp->w_p_cole > 0) {
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
}
}
}
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 832703e83d..873bef32d3 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -259,7 +259,6 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext()
#define PERROR(msg) (void) emsgf("%s: %s", msg, strerror(errno))
#define SHOWCMD_COLS 10 // columns needed by shown command
-#define STL_MAX_ITEM 80 // max nr of %<flag> in statusline
#include "nvim/path.h"
diff --git a/src/nvim/window.c b/src/nvim/window.c
index bbc039d151..47b6b7e713 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -606,7 +606,7 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
win_config_float(wp, fconfig);
wp->w_pos_changed = true;
- redraw_win_later(wp, VALID);
+ redraw_later(wp, VALID);
return wp;
}
@@ -679,7 +679,7 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
wp->w_pos_changed = true;
if (change_external) {
wp->w_hl_needs_update = true;
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
}
}
@@ -764,7 +764,7 @@ static void ui_ext_win_position(win_T *wp)
wp->w_grid.focusable = wp->w_float_config.focusable;
if (!valid) {
wp->w_grid.valid = false;
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
}
}
} else {
@@ -1492,8 +1492,8 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// Both windows need redrawing. Update all status lines, in case they
// show something related to the window count or position.
- redraw_win_later(wp, NOT_VALID);
- redraw_win_later(oldwin, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
+ redraw_later(oldwin, NOT_VALID);
status_redraw_all();
if (need_status) {
@@ -1823,8 +1823,8 @@ static void win_exchange(long Prenum)
(void)win_comp_pos(); /* recompute window positions */
win_enter(wp, true);
- redraw_later(NOT_VALID);
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(curwin, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
}
// rotate windows: if upwards true the second window becomes the first one
@@ -1996,8 +1996,8 @@ void win_move_after(win_T *win1, win_T *win2)
win_append(win2, win1);
frame_append(win2->w_frame, win1->w_frame);
- (void)win_comp_pos(); /* recompute w_winrow for all windows */
- redraw_later(NOT_VALID);
+ (void)win_comp_pos(); // recompute w_winrow for all windows
+ redraw_later(curwin, NOT_VALID);
}
win_enter(win1, false);
@@ -3635,7 +3635,7 @@ void curwin_init(void)
void win_init_empty(win_T *wp)
{
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
wp->w_lines_valid = 0;
wp->w_cursor.lnum = 1;
wp->w_curswant = wp->w_cursor.col = 0;
@@ -4049,7 +4049,7 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
prevwin = next_prevwin;
last_status(false); // status line may appear or disappear
- (void)win_comp_pos(); // recompute w_winrow for all windows
+ const int row = win_comp_pos(); // recompute w_winrow for all windows
diff_need_scrollbind = true;
/* The tabpage line may have appeared or disappeared, may need to resize
@@ -4060,11 +4060,20 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
clear_cmdline = true;
}
p_ch = curtab->tp_ch_used;
- if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow
- ))
+
+ // When cmdheight is changed in a tab page with '<C-w>-', cmdline_row is
+ // changed but p_ch and tp_ch_used are not changed. Thus we also need to
+ // check cmdline_row.
+ if ((row < cmdline_row) && (cmdline_row <= Rows - p_ch)) {
+ clear_cmdline = true;
+ }
+
+ if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow)) {
shell_new_rows();
- if (curtab->tp_old_Columns != Columns && starting == 0)
- shell_new_columns(); /* update window widths */
+ }
+ if (curtab->tp_old_Columns != Columns && starting == 0) {
+ shell_new_columns(); // update window widths
+ }
lastused_tabpage = old_curtab;
@@ -4587,10 +4596,11 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
}
maketitle();
- curwin->w_redr_status = TRUE;
- redraw_tabline = TRUE;
- if (restart_edit)
- redraw_later(VALID); /* causes status line redraw */
+ curwin->w_redr_status = true;
+ redraw_tabline = true;
+ if (restart_edit) {
+ redraw_later(curwin, VALID); // causes status line redraw
+ }
if (HL_ATTR(HLF_INACTIVE)
|| (prevwin && prevwin->w_hl_ids[HLF_INACTIVE])
@@ -5080,7 +5090,7 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
/* position changed, redraw */
wp->w_winrow = *row;
wp->w_wincol = *col;
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
wp->w_redr_status = true;
wp->w_pos_changed = true;
}
@@ -5133,7 +5143,7 @@ void win_setheight_win(int height, win_T *win)
if (win->w_floating) {
win->w_float_config.height = height;
win_config_float(win, win->w_float_config);
- redraw_win_later(win, NOT_VALID);
+ redraw_later(win, NOT_VALID);
} else {
frame_setheight(win->w_frame, height + win->w_status_height);
@@ -5336,7 +5346,7 @@ void win_setwidth_win(int width, win_T *wp)
if (wp->w_floating) {
wp->w_float_config.width = width;
win_config_float(wp, wp->w_float_config);
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
} else {
frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
@@ -5869,8 +5879,8 @@ void scroll_to_fraction(win_T *wp, int prev_height)
}
win_comp_scroll(wp);
- redraw_win_later(wp, SOME_VALID);
- wp->w_redr_status = TRUE;
+ redraw_later(wp, SOME_VALID);
+ wp->w_redr_status = true;
invalidate_botline_win(wp);
}
@@ -5909,7 +5919,7 @@ void win_set_inner_size(win_T *wp)
if (!exiting) {
scroll_to_fraction(wp, prev_height);
}
- redraw_win_later(wp, NOT_VALID); // SOME_VALID??
+ redraw_later(wp, NOT_VALID); // SOME_VALID??
}
if (width != wp->w_width_inner) {
@@ -5921,7 +5931,7 @@ void win_set_inner_size(win_T *wp)
update_topline();
curs_columns(true); // validate w_wrow
}
- redraw_win_later(wp, NOT_VALID);
+ redraw_later(wp, NOT_VALID);
}
if (wp->w_buffer->terminal) {
@@ -6765,7 +6775,7 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
prev->next = m;
m->next = cur;
- redraw_win_later(wp, rtype);
+ redraw_later(wp, rtype);
return id;
fail:
@@ -6823,7 +6833,7 @@ int match_delete(win_T *wp, int id, int perr)
rtype = VALID;
}
xfree(cur);
- redraw_win_later(wp, rtype);
+ redraw_later(wp, rtype);
return 0;
}
@@ -6841,7 +6851,7 @@ void clear_matches(win_T *wp)
xfree(wp->w_match_head);
wp->w_match_head = m;
}
- redraw_win_later(wp, SOME_VALID);
+ redraw_later(wp, SOME_VALID);
}
/*
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/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 9b0668f9e6..3bfae5f3d7 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -7,6 +7,7 @@ local ok = helpers.ok
local eq = helpers.eq
local matches = helpers.matches
local eval = helpers.eval
+local exec_lua = helpers.exec_lua
local feed = helpers.feed
local funcs = helpers.funcs
local mkdir = helpers.mkdir
@@ -305,6 +306,27 @@ describe('startup', function()
'+q' })
eq('[\'+q\'] 1', out)
end)
+
+ local function pack_clear(cmd)
+ clear('--cmd', 'set packpath=test/functional/fixtures', '--cmd', cmd)
+ end
+
+
+ it("handles &packpath during startup", function()
+ pack_clear [[ let g:x = bar#test() ]]
+ eq(-3, eval 'g:x')
+
+ pack_clear [[ lua _G.y = require'bar'.doit() ]]
+ eq(9003, exec_lua [[ return _G.y ]])
+ end)
+
+ it("handles :packadd during startup", function()
+ pack_clear [[ packadd! bonus | let g:x = bonus#secret() ]]
+ eq('halloj', eval 'g:x')
+
+ pack_clear [[ packadd! bonus | lua _G.y = require'bonus'.launch() ]]
+ eq('CPE 1704 TKS', exec_lua [[ return _G.y ]])
+ end)
end)
describe('sysinit', function()
diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua
index db0a706319..fa8f7d873f 100644
--- a/test/functional/eval/null_spec.lua
+++ b/test/functional/eval/null_spec.lua
@@ -132,7 +132,7 @@ describe('NULL', function()
end)
describe('dict', function()
it('does not crash when indexing NULL dict', function()
- eq('\nE716: Key not present in Dictionary: test\nE15: Invalid expression: v:_null_dict.test',
+ eq('\nE716: Key not present in Dictionary: "test"\nE15: Invalid expression: v:_null_dict.test',
redir_exec('echo v:_null_dict.test'))
end)
null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0)
diff --git a/test/functional/ex_cmds/packadd_spec.lua b/test/functional/ex_cmds/packadd_spec.lua
deleted file mode 100644
index 2b0810cf9b..0000000000
--- a/test/functional/ex_cmds/packadd_spec.lua
+++ /dev/null
@@ -1,74 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-
-local clear = helpers.clear
-local eq = helpers.eq
-local exec_lua = helpers.exec_lua
-
-describe('packadd', function()
- before_each(function()
- -- Primarily taken from test/functional/legacy/packadd_spec.lua
- clear()
- exec_lua [[
- TopDirectory = vim.fn.expand(vim.fn.getcwd() .. '/Xdir_lua')
- PlugDirectory = TopDirectory .. '/pack/mine/opt/mytest'
-
- vim.o.packpath = TopDirectory
-
- function FindPathsContainingDir(dir)
- return vim.fn.filter(
- vim.split(package.path, ';'),
- function(k, v)
- return string.find(v, 'mytest') ~= nil
- end
- )
- end
- ]]
- end)
-
- after_each(function()
- exec_lua [[
- vim.fn.delete(TopDirectory, 'rf')
- ]]
- end)
-
- it('should immediately update package.path in lua', function()
- local count_of_paths = exec_lua [[
- vim.fn.mkdir(PlugDirectory .. '/lua/', 'p')
-
- local num_paths_before = #FindPathsContainingDir('mytest')
-
- vim.cmd("packadd mytest")
-
- local num_paths_after = #FindPathsContainingDir('mytest')
-
- return { num_paths_before, num_paths_after }
- ]]
-
- eq({0, 2}, count_of_paths)
- end)
-
- it('should immediately update package.path in lua even if lua directory does not exist', function()
- local count_of_paths = exec_lua [[
- vim.fn.mkdir(PlugDirectory .. '/plugin/', 'p')
-
- local num_paths_before = #FindPathsContainingDir('mytest')
-
- vim.cmd("packadd mytest")
-
- local num_paths_after = #FindPathsContainingDir('mytest')
-
- return { num_paths_before, num_paths_after }
- ]]
-
- eq({0, 2}, count_of_paths)
- end)
-
- it('should error for invalid paths', function()
- local count_of_paths = exec_lua [[
- local ok, err = pcall(vim.cmd, "packadd asdf")
- return ok
- ]]
-
- eq(false, count_of_paths)
- end)
-end)
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/fixtures/pack/foo/opt/bonus/autoload/bonus.vim b/test/functional/fixtures/pack/foo/opt/bonus/autoload/bonus.vim
new file mode 100644
index 0000000000..5ed8b1b887
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/opt/bonus/autoload/bonus.vim
@@ -0,0 +1,3 @@
+func bonus#secret()
+ return "halloj"
+endfunc
diff --git a/test/functional/fixtures/pack/foo/opt/bonus/lua/bonus.lua b/test/functional/fixtures/pack/foo/opt/bonus/lua/bonus.lua
new file mode 100644
index 0000000000..52cb0bc118
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/opt/bonus/lua/bonus.lua
@@ -0,0 +1 @@
+return {launch=function() return "CPE 1704 TKS" end}
diff --git a/test/functional/fixtures/pack/foo/start/bar/autoload/bar.vim b/test/functional/fixtures/pack/foo/start/bar/autoload/bar.vim
new file mode 100644
index 0000000000..405e7be71c
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/start/bar/autoload/bar.vim
@@ -0,0 +1,3 @@
+func bar#test()
+ return -3
+endfunc
diff --git a/test/functional/fixtures/pack/foo/start/bar/lua/bar.lua b/test/functional/fixtures/pack/foo/start/bar/lua/bar.lua
new file mode 100644
index 0000000000..a7e9a61e35
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/start/bar/lua/bar.lua
@@ -0,0 +1 @@
+return {doit=function() return 9003 end}
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 0bd378d832..d85a6a3cfe 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -751,6 +751,14 @@ module.curbufmeths = module.create_callindex(module.curbuf)
module.curwinmeths = module.create_callindex(module.curwin)
module.curtabmeths = module.create_callindex(module.curtab)
+function module.exec(code)
+ return module.meths.exec(code, false)
+end
+
+function module.exec_capture(code)
+ return module.meths.exec(code, true)
+end
+
function module.exec_lua(code, ...)
return module.meths.exec_lua(code, {...})
end
diff --git a/test/functional/legacy/055_list_and_dict_types_spec.lua b/test/functional/legacy/055_list_and_dict_types_spec.lua
index 91ba8bb106..4d71a526c1 100644
--- a/test/functional/legacy/055_list_and_dict_types_spec.lua
+++ b/test/functional/legacy/055_list_and_dict_types_spec.lua
@@ -229,7 +229,7 @@ describe('list and dictionary types', function()
try
let n = d[1500]
catch
- $put =substitute(v:exception, '\v(.{14}).*( \d{4}).*', '\1\2', '')
+ $put = substitute(v:exception, '\v(.{14}).*( \"\d{4}\").*', '\1\2', '')
endtry
" Lookup each items.
for i in range(1500)
@@ -260,7 +260,7 @@ describe('list and dictionary types', function()
expect([[
3000 2900 2001 1600 1501
- Vim(let):E716: 1500
+ Vim(let):E716: "1500"
NONE 2999
33=999
{'33': 999}]])
diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua
new file mode 100644
index 0000000000..9ebe9aeb91
--- /dev/null
+++ b/test/functional/legacy/cmdline_spec.lua
@@ -0,0 +1,66 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+local source = helpers.source
+
+describe('cmdline', function()
+ before_each(clear)
+
+ it('is cleared when switching tabs', function()
+ local screen = Screen.new(30, 10)
+ screen:attach()
+ feed_command([[call setline(1, range(30))]])
+ screen:expect([[
+ ^0 |
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ 5 |
+ 6 |
+ 7 |
+ 8 |
+ :call setline(1, range(30)) |
+ ]])
+ feed([[:tabnew<cr><C-w>-<C-w>-gtgt]])
+ screen:expect([[
+ + [No Name] [No Name] X|
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ 6 |
+ 7 |
+ |
+ ]])
+ end)
+
+ it('prints every executed Ex command if verbose >= 16', function()
+ local screen = Screen.new(60, 12)
+ screen:attach()
+ source([[
+ command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v
+ call feedkeys("\r", 't') " for the hit-enter prompt
+ set verbose=20
+ ]])
+ feed_command('DoSomething')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ |
+ Executing: DoSomething |
+ Executing: echo 'hello' |set ts=4 |let v = '123' |echo v |
+ hello |
+ Executing: set ts=4 |let v = '123' |echo v |
+ Executing: let v = '123' |echo v |
+ Executing: echo v |
+ 123 |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
+end)
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 1bccc02847..267c759faf 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -3,7 +3,6 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
-local neq = helpers.neq
local NIL = helpers.NIL
local feed = helpers.feed
local clear = helpers.clear
@@ -13,7 +12,6 @@ local iswin = helpers.iswin
local command = helpers.command
local write_file = helpers.write_file
local redir_exec = helpers.redir_exec
-local alter_slashes = helpers.alter_slashes
local exec_lua = helpers.exec_lua
local screen
@@ -285,119 +283,6 @@ describe('debug.debug', function()
end)
end)
-describe('package.path/package.cpath', function()
- local sl = alter_slashes
-
- local function get_new_paths(sufs, runtimepaths)
- runtimepaths = runtimepaths or meths.list_runtime_paths()
- local new_paths = {}
- local sep = package.config:sub(1, 1)
- for _, v in ipairs(runtimepaths) do
- for _, suf in ipairs(sufs) do
- new_paths[#new_paths + 1] = v .. sep .. 'lua' .. suf
- end
- end
- return new_paths
- end
- local function eval_lua(expr, ...)
- return meths.exec_lua('return '..expr, {...})
- end
- local function set_path(which, value)
- return exec_lua('package[select(1, ...)] = select(2, ...)', which, value)
- end
-
- it('contains directories from &runtimepath on first invocation', function()
- local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'})
- local new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
-
- local new_cpaths = get_new_paths(iswin() and {'\\?.dll'} or {'/?.so'})
- local new_cpaths_str = table.concat(new_cpaths, ';')
- eq(new_cpaths_str, eval_lua('package.cpath'):sub(1, #new_cpaths_str))
- end)
- it('puts directories from &runtimepath always at the start', function()
- meths.set_option('runtimepath', 'a,b')
- local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {'a', 'b'})
- local new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
-
- set_path('path', sl'foo/?.lua;foo/?/init.lua;' .. new_paths_str)
-
- neq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
-
- command('set runtimepath+=c')
- new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {'a', 'b', 'c'})
- new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
- end)
- it('understands uncommon suffixes', function()
- set_path('cpath', './?/foo/bar/baz/x.nlua')
- meths.set_option('runtimepath', 'a')
- local new_paths = get_new_paths({'/?/foo/bar/baz/x.nlua'}, {'a'})
- local new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str, eval_lua('package.cpath'):sub(1, #new_paths_str))
-
- set_path('cpath', './yyy?zzz/x')
- meths.set_option('runtimepath', 'b')
- new_paths = get_new_paths({'/yyy?zzz/x'}, {'b'})
- new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str, eval_lua('package.cpath'):sub(1, #new_paths_str))
-
- set_path('cpath', './yyy?zzz/123?ghi/x')
- meths.set_option('runtimepath', 'b')
- new_paths = get_new_paths({'/yyy?zzz/123?ghi/x'}, {'b'})
- new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str, eval_lua('package.cpath'):sub(1, #new_paths_str))
- end)
- it('preserves empty items', function()
- local many_empty_path = ';;;;;;'
- local many_empty_cpath = ';;;;;;./?.luaso'
- set_path('path', many_empty_path)
- set_path('cpath', many_empty_cpath)
- meths.set_option('runtimepath', 'a')
- local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {'a'})
- local new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str .. ';' .. many_empty_path, eval_lua('package.path'))
- local new_cpaths = get_new_paths({'/?.luaso'}, {'a'})
- local new_cpaths_str = table.concat(new_cpaths, ';')
- eq(new_cpaths_str .. ';' .. many_empty_cpath, eval_lua('package.cpath'))
- end)
- it('preserves empty value', function()
- set_path('path', '')
- meths.set_option('runtimepath', 'a')
- local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {'a'})
- local new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str .. ';', eval_lua('package.path'))
- end)
- it('purges out all additions if runtimepath is set to empty', function()
- local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'})
- local new_paths_str = table.concat(new_paths, ';')
- local path = eval_lua('package.path')
- eq(new_paths_str, path:sub(1, #new_paths_str))
-
- local new_cpaths = get_new_paths(iswin() and {'\\?.dll'} or {'/?.so'})
- local new_cpaths_str = table.concat(new_cpaths, ';')
- local cpath = eval_lua('package.cpath')
- eq(new_cpaths_str, cpath:sub(1, #new_cpaths_str))
-
- meths.set_option('runtimepath', '')
- eq(path:sub(#new_paths_str + 2, -1), eval_lua('package.path'))
- eq(cpath:sub(#new_cpaths_str + 2, -1), eval_lua('package.cpath'))
- end)
- it('works with paths with escaped commas', function()
- meths.set_option('runtimepath', '\\,')
- local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {','})
- local new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
- end)
- it('ignores paths with semicolons', function()
- meths.set_option('runtimepath', 'foo;bar,\\,')
- local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {','})
- local new_paths_str = table.concat(new_paths, ';')
- eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
- end)
-end)
-
describe('os.getenv', function()
it('returns nothing for undefined env var', function()
eq(NIL, funcs.luaeval('os.getenv("XTEST_1")'))
diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua
index 3526b64395..9eb5c8b1dd 100644
--- a/test/functional/lua/treesitter_spec.lua
+++ b/test/functional/lua/treesitter_spec.lua
@@ -80,13 +80,6 @@ describe('treesitter API with C parser', function()
eq({1,2,1,12}, exec_lua("return {descendant:range()}"))
eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()"))
- eq(true, exec_lua("return child == child"))
- -- separate lua object, but represents same node
- eq(true, exec_lua("return child == root:child(0)"))
- eq(false, exec_lua("return child == descendant2"))
- eq(false, exec_lua("return child == nil"))
- eq(false, exec_lua("return child == tree"))
-
feed("2G7|ay")
exec_lua([[
tree2 = parser:parse()
@@ -98,6 +91,21 @@ describe('treesitter API with C parser', function()
eq("<node declaration>", exec_lua("return tostring(descendant2)"))
eq({1,2,1,13}, exec_lua("return {descendant2:range()}"))
+ eq(true, exec_lua("return child == child"))
+ -- separate lua object, but represents same node
+ eq(true, exec_lua("return child == root:child(0)"))
+ eq(false, exec_lua("return child == descendant2"))
+ eq(false, exec_lua("return child == nil"))
+ eq(false, exec_lua("return child == tree"))
+
+ eq("string", exec_lua("return type(child:id())"))
+ eq(true, exec_lua("return child:id() == child:id()"))
+ -- separate lua object, but represents same node
+ eq(true, exec_lua("return child:id() == root:child(0):id()"))
+ eq(false, exec_lua("return child:id() == descendant2:id()"))
+ eq(false, exec_lua("return child:id() == nil"))
+ eq(false, exec_lua("return child:id() == tree"))
+
-- orginal tree did not change
eq({1,2,1,12}, exec_lua("return {descendant:range()}"))
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index f07a2d18a2..73f3fe5d0c 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -270,6 +270,76 @@ 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.callbacks['textDocument/hover'] = function(err, method)
+ vim.lsp._last_lsp_callback = { err = err; method = method }
+ end
+ 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)
+ local lsp_cb_call = exec_lua("return vim.lsp._last_lsp_callback")
+ eq("fake-error", lsp_cb_call.err)
+ eq("textDocument/hover", lsp_cb_call.method)
end;
on_exit = function(code, signal)
eq(0, code, "exit code", fake_lsp_logfile)
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/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 01f0d8a4d7..21c01b3458 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -3,7 +3,6 @@ local Screen = require('test.functional.ui.screen')
local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
local command = helpers.command
-local feed_command = helpers.feed_command
local function new_screen(opt)
local screen = Screen.new(25, 5)
@@ -843,34 +842,3 @@ describe('cmdline redraw', function()
]], unchanged=true}
end)
end)
-
-describe('cmdline', function()
- before_each(function()
- clear()
- end)
-
- it('prints every executed Ex command if verbose >= 16', function()
- local screen = Screen.new(50, 12)
- screen:attach()
- source([[
- command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v
- call feedkeys("\r", 't') " for the hit-enter prompt
- set verbose=20
- ]])
- feed_command('DoSomething')
- screen:expect([[
- |
- ~ |
- |
- Executing: DoSomething |
- Executing: echo 'hello' |set ts=4 |let v = '123' ||
- echo v |
- hello |
- Executing: set ts=4 |let v = '123' |echo v |
- Executing: let v = '123' |echo v |
- Executing: echo v |
- 123 |
- Press ENTER or type command to continue^ |
- ]])
- end)
-end)
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 304c5aecb1..4182090732 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -5,20 +5,32 @@ local clear = helpers.clear
local feed = helpers.feed
local insert = helpers.insert
local exec_lua = helpers.exec_lua
+local exec = helpers.exec
local expect_events = helpers.expect_events
+local meths = helpers.meths
-describe('decorations provider', function()
+describe('decorations providers', function()
local screen
before_each(function()
clear()
screen = Screen.new(40, 8)
screen:attach()
- screen:set_default_attr_ids({
- [1] = {bold=true, foreground=Screen.colors.Blue},
- })
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red};
+ [3] = {foreground = Screen.colors.Brown};
+ [4] = {foreground = Screen.colors.Blue1};
+ [5] = {foreground = Screen.colors.Magenta};
+ [6] = {bold = true, foreground = Screen.colors.Brown};
+ [7] = {background = Screen.colors.Gray90};
+ [8] = {bold = true, reverse = true};
+ [9] = {reverse = true};
+ [10] = {italic = true, background = Screen.colors.Magenta};
+ [11] = {foreground = Screen.colors.Red, background = tonumber('0x005028')};
+ }
end)
- local mudholland = [[
+ local mulholland = [[
// just to see if there was an accident
// on Mulholland Drive
try_start();
@@ -28,21 +40,21 @@ describe('decorations provider', function()
restore_buffer(&save_buf); ]]
local function setup_provider(code)
- exec_lua ([[
+ return exec_lua ([[
local a = vim.api
- test1 = a.nvim_create_namespace "test1"
+ _G.ns1 = a.nvim_create_namespace "ns1"
]] .. (code or [[
beamtrace = {}
- function on_do(kind, ...)
+ local function on_do(kind, ...)
table.insert(beamtrace, {kind, ...})
end
]]) .. [[
- a.nvim_set_decoration_provider(
- test1, {
+ a.nvim_set_decoration_provider(_G.ns1, {
on_start = on_do; on_buf = on_do;
on_win = on_do; on_line = on_do;
on_end = on_do;
})
+ return _G.ns1
]])
end
@@ -51,8 +63,8 @@ describe('decorations provider', function()
expect_events(expected, actual, "beam trace")
end
- it('leaves a trace', function()
- insert(mudholland)
+ it('leave a trace', function()
+ insert(mulholland)
setup_provider()
@@ -99,11 +111,12 @@ describe('decorations provider', function()
}
end)
- it('single provider', function()
- insert(mudholland)
+ it('can have single provider', function()
+ insert(mulholland)
setup_provider [[
local hl = a.nvim_get_hl_id_by_name "ErrorMsg"
- function do_it(event, ...)
+ local test_ns = a.nvim_create_namespace "mulholland"
+ function on_do(event, ...)
if event == "line" then
local win, buf, line = ...
a.nvim_buf_set_extmark(buf, test_ns, line, line,
@@ -114,5 +127,104 @@ describe('decorations provider', function()
end
end
]]
+
+ screen:expect{grid=[[
+ {2:/}/ just to see if there was an accident |
+ /{2:/} on Mulholland Drive |
+ tr{2:y}_start(); |
+ buf{2:r}ef_T save_buf; |
+ swit{2:c}h_buffer(&save_buf, buf); |
+ posp {2:=} getmark(mark, false); |
+ restor{2:e}_buffer(&save_buf);^ |
+ |
+ ]]}
+ end)
+
+ it('can predefine highlights', function()
+ screen:try_resize(40, 16)
+ insert(mulholland)
+ exec [[
+ 3
+ set ft=c
+ syntax on
+ set number cursorline
+ split
+ ]]
+ local ns1 = setup_provider()
+
+ for k,v in pairs {
+ LineNr = {italic=true, bg="Magenta"};
+ Comment = {fg="#FF0000", bg = 80*256+40};
+ CursorLine = {link="ErrorMsg"};
+ } do meths.set_hl(ns1, k, v) end
+
+ screen:expect{grid=[[
+ {3: 1 }{4:// just to see if there was an accid}|
+ {3: }{4:ent} |
+ {3: 2 }{4:// on Mulholland Drive} |
+ {6: 3 }{7:^try_start(); }|
+ {3: 4 }bufref_T save_buf; |
+ {3: 5 }switch_buffer(&save_buf, buf); |
+ {3: 6 }posp = getmark(mark, {5:false}); |
+ {8:[No Name] [+] }|
+ {3: 2 }{4:// on Mulholland Drive} |
+ {6: 3 }{7:try_start(); }|
+ {3: 4 }bufref_T save_buf; |
+ {3: 5 }switch_buffer(&save_buf, buf); |
+ {3: 6 }posp = getmark(mark, {5:false}); |
+ {3: 7 }restore_buffer(&save_buf); |
+ {9:[No Name] [+] }|
+ |
+ ]]}
+
+ meths.set_hl_ns(ns1)
+ screen:expect{grid=[[
+ {10: 1 }{11:// just to see if there was an accid}|
+ {10: }{11:ent} |
+ {10: 2 }{11:// on Mulholland Drive} |
+ {6: 3 }{2:^try_start(); }|
+ {10: 4 }bufref_T save_buf; |
+ {10: 5 }switch_buffer(&save_buf, buf); |
+ {10: 6 }posp = getmark(mark, {5:false}); |
+ {8:[No Name] [+] }|
+ {10: 2 }{11:// on Mulholland Drive} |
+ {6: 3 }{2:try_start(); }|
+ {10: 4 }bufref_T save_buf; |
+ {10: 5 }switch_buffer(&save_buf, buf); |
+ {10: 6 }posp = getmark(mark, {5:false}); |
+ {10: 7 }restore_buffer(&save_buf); |
+ {9:[No Name] [+] }|
+ |
+ ]]}
+
+ exec_lua [[
+ local a = vim.api
+ local thewin = a.nvim_get_current_win()
+ local ns2 = a.nvim_create_namespace 'ns2'
+ a.nvim_set_decoration_provider (ns2, {
+ on_win = function (_, win, buf)
+ a.nvim_set_hl_ns(win == thewin and _G.ns1 or ns2)
+ end;
+ })
+ ]]
+ screen:expect{grid=[[
+ {10: 1 }{11:// just to see if there was an accid}|
+ {10: }{11:ent} |
+ {10: 2 }{11:// on Mulholland Drive} |
+ {6: 3 }{2:^try_start(); }|
+ {10: 4 }bufref_T save_buf; |
+ {10: 5 }switch_buffer(&save_buf, buf); |
+ {10: 6 }posp = getmark(mark, {5:false}); |
+ {8:[No Name] [+] }|
+ {3: 2 }{4:// on Mulholland Drive} |
+ {6: 3 }{7:try_start(); }|
+ {3: 4 }bufref_T save_buf; |
+ {3: 5 }switch_buffer(&save_buf, buf); |
+ {3: 6 }posp = getmark(mark, {5:false}); |
+ {3: 7 }restore_buffer(&save_buf); |
+ {9:[No Name] [+] }|
+ |
+ ]]}
+
end)
end)
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/screen.lua b/test/functional/ui/screen.lua
index bf979e89f4..8fa9fcc42f 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -1289,7 +1289,7 @@ local function fmt_ext_state(name, state)
for k,v in pairs(state) do
str = (str.." ["..k.."] = {win = {id = "..v.win.id.."}, topline = "
..v.topline..", botline = "..v.botline..", curline = "..v.curline
- ..", curcol = "..v.curcol.."},\n")
+ ..", curcol = "..v.curcol.."};\n")
end
return str .. "}"
else
@@ -1316,7 +1316,7 @@ function Screen:print_snapshot(attrs, ignore)
dict = "{"..self:_pprint_attrs(a).."}"
end
local keyval = (type(i) == "number") and "["..tostring(i).."]" or i
- table.insert(attrstrs, " "..keyval.." = "..dict..",")
+ table.insert(attrstrs, " "..keyval.." = "..dict..";")
end
attrstr = (", attr_ids={\n"..table.concat(attrstrs, "\n").."\n}")
end
diff --git a/test/unit/buffer_spec.lua b/test/unit/buffer_spec.lua
index bf4e5a0e6d..3692e19379 100644
--- a/test/unit/buffer_spec.lua
+++ b/test/unit/buffer_spec.lua
@@ -212,7 +212,7 @@ describe('buffer functions', function()
describe('build_stl_str_hl', function()
local buffer_byte_size = 100
- local STL_MAX_ITEM = 80
+ local STL_INITIAL_ITEMS = 20
local output_buffer = ''
-- This function builds the statusline
@@ -431,31 +431,23 @@ describe('buffer functions', function()
'aaaa%=b%=c%=d%=e%=fg%=hi%=jk%=lmnop%=qrstuv%=wxyz',
'aaaa b c d e fg hi jk lmnop qrstuv wxyz')
- -- maximum stl item testing
- statusline_test('should handle a much larger amount of = than buffer locations', 20,
- ('%='):rep(STL_MAX_ITEM - 1),
- ' ') -- Should be fine, because within limit
- statusline_test('should handle a much larger amount of = than stl max item', 20,
- ('%='):rep(STL_MAX_ITEM + 1),
- ' E541') -- Should show the VIM error
+ -- stl item testing
+ local tabline = ''
+ for i= 1, 1000 do
+ tabline = tabline .. (i % 2 == 0 and '%#TabLineSel#' or '%#TabLineFill#') .. tostring(i % 2)
+ end
+ statusline_test('should handle a large amount of any items', 20,
+ tabline,
+ '<1010101010101010101') -- Should not show any error
+ statusline_test('should handle a larger amount of = than stl initial item', 20,
+ ('%='):rep(STL_INITIAL_ITEMS * 5),
+ ' ') -- Should not show any error
statusline_test('should handle many extra characters', 20,
- 'a' .. ('a'):rep(STL_MAX_ITEM * 4),
- '<aaaaaaaaaaaaaaaaaaa') -- Does not show the error because there are no items
- statusline_test('should handle almost maximum of characters and flags', 20,
- 'a' .. ('%=a'):rep(STL_MAX_ITEM - 1),
- 'a<aaaaaaaaaaaaaaaaaa') -- Should not show the VIM error
- statusline_test('should handle many extra characters and flags', 20,
- 'a' .. ('%=a'):rep(STL_MAX_ITEM),
- 'a<aaaaaaaaaaaaa E541') -- Should show the VIM error
+ 'a' .. ('a'):rep(STL_INITIAL_ITEMS * 5),
+ '<aaaaaaaaaaaaaaaaaaa') -- Does not show any error
statusline_test('should handle many extra characters and flags', 20,
- 'a' .. ('%=a'):rep(STL_MAX_ITEM * 2),
- 'a<aaaaaaaaaaaaa E541') -- Should show the VIM error
- statusline_test('should handle many extra characters and flags with truncation', 20,
- 'aaa%<' .. ('%=a'):rep(STL_MAX_ITEM),
- 'aaa<aaaaaaaaaaa E541') -- Should show the VIM error
- statusline_test('should handle many characters and flags before and after truncation', 20,
- 'a%=a%=a%<' .. ('%=a'):rep(STL_MAX_ITEM),
- 'aaa<aaaaaaaaaaa E541') -- Should show the VIM error
+ 'a' .. ('%=a'):rep(STL_INITIAL_ITEMS * 2),
+ 'a<aaaaaaaaaaaaaaaaaa') -- Should not show any error
-- multi-byte testing
diff --git a/third-party/cmake/GetBinaryDeps.cmake b/third-party/cmake/GetBinaryDeps.cmake
index f262ae7159..982bf62265 100644
--- a/third-party/cmake/GetBinaryDeps.cmake
+++ b/third-party/cmake/GetBinaryDeps.cmake
@@ -39,7 +39,6 @@ function(GetBinaryDep)
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
- CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/bin
COMMAND "${_gettool_INSTALL_COMMAND}")