aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake.deps/deps.txt4
-rw-r--r--runtime/compiler/cppcheck.vim4
-rw-r--r--runtime/compiler/groff.vim4
-rw-r--r--runtime/compiler/mypy.vim4
-rw-r--r--runtime/compiler/pandoc.vim4
-rw-r--r--runtime/compiler/powershell.vim7
-rw-r--r--runtime/compiler/pylint.vim3
-rw-r--r--runtime/compiler/ruff.vim3
-rw-r--r--runtime/compiler/tex.vim7
-rw-r--r--runtime/doc/api.txt33
-rw-r--r--runtime/doc/deprecated.txt10
-rw-r--r--runtime/doc/lsp.txt210
-rw-r--r--runtime/doc/lua.txt10
-rw-r--r--runtime/doc/news.txt13
-rw-r--r--runtime/doc/options.txt4
-rw-r--r--runtime/doc/pi_netrw.txt2
-rw-r--r--runtime/doc/pi_tar.txt2
-rw-r--r--runtime/doc/treesitter.txt3
-rw-r--r--runtime/doc/ui.txt5
-rw-r--r--runtime/doc/vim_diff.txt8
-rw-r--r--runtime/doc/windows.txt3
-rw-r--r--runtime/ftplugin/checkhealth.vim7
-rw-r--r--runtime/ftplugin/karel.vim16
-rw-r--r--runtime/ftplugin/mss.vim16
-rw-r--r--runtime/ftplugin/opencl.vim12
-rw-r--r--runtime/ftplugin/query.lua1
-rw-r--r--runtime/indent/query.lua1
-rw-r--r--runtime/lua/vim/_buf.lua23
-rw-r--r--runtime/lua/vim/_defaults.lua16
-rw-r--r--runtime/lua/vim/_editor.lua13
-rw-r--r--runtime/lua/vim/_meta/api.lua30
-rw-r--r--runtime/lua/vim/_meta/options.lua7
-rw-r--r--runtime/lua/vim/filetype.lua9
-rw-r--r--runtime/lua/vim/filetype/detect.lua10
-rw-r--r--runtime/lua/vim/lsp.lua62
-rw-r--r--runtime/lua/vim/lsp/_changetracking.lua6
-rw-r--r--runtime/lua/vim/lsp/_dynamic.lua110
-rw-r--r--runtime/lua/vim/lsp/_tagfunc.lua2
-rw-r--r--runtime/lua/vim/lsp/_watchfiles.lua12
-rw-r--r--runtime/lua/vim/lsp/buf.lua80
-rw-r--r--runtime/lua/vim/lsp/client.lua384
-rw-r--r--runtime/lua/vim/lsp/codelens.lua2
-rw-r--r--runtime/lua/vim/lsp/completion.lua6
-rw-r--r--runtime/lua/vim/lsp/handlers.lua50
-rw-r--r--runtime/lua/vim/lsp/inlay_hint.lua10
-rw-r--r--runtime/lua/vim/lsp/log.lua9
-rw-r--r--runtime/lua/vim/lsp/semantic_tokens.lua8
-rw-r--r--runtime/lua/vim/lsp/util.lua46
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua12
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua2
-rw-r--r--runtime/syntax/checkhealth.vim1
-rw-r--r--runtime/syntax/hyprlang.vim58
-rw-r--r--runtime/syntax/karel.vim112
-rw-r--r--runtime/syntax/mss.vim23
-rw-r--r--runtime/syntax/opencl.vim13
-rw-r--r--runtime/syntax/query.lua1
-rwxr-xr-xscripts/gen_eval_files.lua10
-rwxr-xr-xscripts/gen_vimdoc.lua27
-rw-r--r--scripts/luacats_parser.lua25
-rwxr-xr-xsrc/clint.py14
-rw-r--r--src/nvim/CMakeLists.txt10
-rw-r--r--src/nvim/api/deprecated.c60
-rw-r--r--src/nvim/api/extmark.c24
-rw-r--r--src/nvim/api/options.c50
-rw-r--r--src/nvim/api/private/helpers.c22
-rw-r--r--src/nvim/api/vim.c38
-rw-r--r--src/nvim/api/win_config.c2
-rw-r--r--src/nvim/buffer.c94
-rw-r--r--src/nvim/buffer_defs.h4
-rw-r--r--src/nvim/cmdexpand.c1
-rw-r--r--src/nvim/diff.c4
-rw-r--r--src/nvim/eval.c54
-rw-r--r--src/nvim/eval/funcs.c5
-rw-r--r--src/nvim/eval/vars.c1
-rw-r--r--src/nvim/ex_cmds.c4
-rw-r--r--src/nvim/ex_docmd.c4
-rw-r--r--src/nvim/file_search.c2
-rw-r--r--src/nvim/fold.c2
-rw-r--r--src/nvim/generators/gen_options.lua219
-rw-r--r--src/nvim/generators/gen_options_enum.lua129
-rw-r--r--src/nvim/highlight_group.c5
-rw-r--r--src/nvim/indent.c2
-rw-r--r--src/nvim/input.c1
-rw-r--r--src/nvim/lua/executor.c39
-rw-r--r--src/nvim/mapping.c3
-rw-r--r--src/nvim/mbyte.c2
-rw-r--r--src/nvim/message.c43
-rw-r--r--src/nvim/move.c9
-rw-r--r--src/nvim/normal.c6
-rw-r--r--src/nvim/option.c807
-rw-r--r--src/nvim/option.h57
-rw-r--r--src/nvim/option_defs.h41
-rw-r--r--src/nvim/options.lua291
-rw-r--r--src/nvim/popupmenu.c2
-rw-r--r--src/nvim/search.c1
-rw-r--r--src/nvim/spellsuggest.c1
-rw-r--r--src/nvim/statusline.c4
-rw-r--r--src/nvim/textformat.c2
-rw-r--r--src/nvim/tui/termkey/termkey-internal.h2
-rw-r--r--src/nvim/ui.c2
-rw-r--r--src/nvim/window.c4
-rw-r--r--src/nvim/winfloat.c4
-rw-r--r--src/uncrustify.cfg13
-rw-r--r--test/functional/api/vim_spec.lua21
-rw-r--r--test/functional/autocmd/completedone_spec.lua2
-rw-r--r--test/functional/core/startup_spec.lua4
-rw-r--r--test/functional/editor/defaults_spec.lua47
-rw-r--r--test/functional/legacy/normal_spec.lua29
-rw-r--r--test/functional/lua/filetype_spec.lua12
-rw-r--r--test/functional/lua/system_spec.lua2
-rw-r--r--test/functional/lua/ui_event_spec.lua22
-rw-r--r--test/functional/plugin/lsp/testutil.lua13
-rw-r--r--test/functional/plugin/lsp_spec.lua178
-rw-r--r--test/functional/provider/clipboard_spec.lua2
-rw-r--r--test/functional/testnvim.lua122
-rw-r--r--test/functional/testnvim/exec_lua.lua148
-rw-r--r--test/functional/ui/messages_spec.lua188
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua33
-rw-r--r--test/functional/ui/tabline_spec.lua39
-rw-r--r--test/old/testdir/test_curswant.vim52
-rw-r--r--test/old/testdir/test_filetype.vim23
121 files changed, 2594 insertions, 2002 deletions
diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt
index d98ff6ea97..1623d0ff57 100644
--- a/cmake.deps/deps.txt
+++ b/cmake.deps/deps.txt
@@ -56,7 +56,7 @@ TREESITTER_SHA256 61a21f5d83cfe256472bfa941123a6941fb45073784ee7ec0bc32fdd52f7a4
WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v25.0.2.tar.gz
WASMTIME_SHA256 6d1c17c756b83f29f629963228e5fa208ba9d6578421ba2cd07132b6a120accb
-UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.79.0.tar.gz
-UNCRUSTIFY_SHA256 e7afaeabf636b7f0ce4e3e9747b95f7bd939613a8db49579755dddf44fedca5f
+UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.80.1.tar.gz
+UNCRUSTIFY_SHA256 0e2616ec2f78e12816388c513f7060072ff7942b42f1175eb28b24cb75aaec48
LUA_DEV_DEPS_URL https://github.com/neovim/deps/raw/5a1f71cceb24990a0b15fd9a472a5f549f019248/opt/lua-dev-deps.tar.gz
LUA_DEV_DEPS_SHA256 27db2495f5eddc7fc191701ec9b291486853530c6125609d3197d03481e8d5a2
diff --git a/runtime/compiler/cppcheck.vim b/runtime/compiler/cppcheck.vim
index 4df12d1714..033613c091 100644
--- a/runtime/compiler/cppcheck.vim
+++ b/runtime/compiler/cppcheck.vim
@@ -1,7 +1,7 @@
" vim compiler file
" Compiler: cppcheck (C++ static checker)
" Maintainer: Vincent B. (twinside@free.fr)
-" Last Change: 2024 Nov 08 by @Konfekt
+" Last Change: 2024 Nov 19 by @Konfekt
if exists("current_compiler") | finish | endif
let current_compiler = "cppcheck"
@@ -25,7 +25,7 @@ let &l:makeprg = 'cppcheck --quiet'
\ (filereadable('compile_commands.json') ? '--project=compile_commands.json' :
\ (!empty(glob('*'..s:slash..'compile_commands.json', 1, 1)) ? '--project='..glob('*'..s:slash..'compile_commands.json', 1, 1)[0] :
\ (empty(&path) ? '' : '-I')..join(map(filter(split(&path, ','), 'isdirectory(v:val)'),'shellescape(v:val)'), ' -I')))))
-exe 'CompilerSet makeprg='..escape(&l:makeprg, ' "')
+exe 'CompilerSet makeprg='..escape(&l:makeprg, ' \|"')
CompilerSet errorformat=
\%f:%l:%c:\ %tarning:\ %m,
diff --git a/runtime/compiler/groff.vim b/runtime/compiler/groff.vim
index 640146d6a1..3e9ae0488f 100644
--- a/runtime/compiler/groff.vim
+++ b/runtime/compiler/groff.vim
@@ -1,7 +1,7 @@
" Vim compiler file
" Compiler: Groff
" Maintainer: Konfekt
-" Last Change: 2024 Sep 8
+" Last Change: 2024 Nov 19
"
" Expects output file extension, say `:make html` or `:make pdf`.
" Supported devices as of Sept 2024 are: (x)html, pdf, ps, dvi, lj4, lbp ...
@@ -30,7 +30,7 @@ execute 'CompilerSet makeprg=groff'..escape(
\ ' '..s:groff_compiler_lang()..
\ ' -K'..get(b:, 'groff_compiler_encoding', get(g:, 'groff_compiler_encoding', 'utf8'))..
\ ' '..get(b:, 'groff_compiler_args', get(g:, 'groff_compiler_args', ''))..
- \ ' -mom -T$* -- %:S > %:r:S.$*', ' ')
+ \ ' -mom -T$* -- %:S > %:r:S.$*', ' \|"')
" From Gavin Freeborn's https://github.com/Gavinok/vim-troff under Vim License
" https://github.com/Gavinok/vim-troff/blob/91017b1423caa80aba541c997909a4f810edd275/compiler/troff.vim#L39
CompilerSet errorformat=%o:<standard\ input>\ (%f):%l:%m,
diff --git a/runtime/compiler/mypy.vim b/runtime/compiler/mypy.vim
index 891488626a..907b98b777 100644
--- a/runtime/compiler/mypy.vim
+++ b/runtime/compiler/mypy.vim
@@ -1,7 +1,7 @@
" Vim compiler file
" Compiler: Mypy (Python static checker)
" Maintainer: @Konfekt
-" Last Change: 2024 Nov 07
+" Last Change: 2024 Nov 19
if exists("current_compiler") | finish | endif
let current_compiler = "mypy"
@@ -12,7 +12,7 @@ set cpo&vim
" CompilerSet makeprg=mypy
let &l:makeprg = 'mypy --show-column-numbers '
\ ..get(b:, 'mypy_makeprg_params', get(g:, 'mypy_makeprg_params', '--strict --ignore-missing-imports'))
-exe 'CompilerSet makeprg='..escape(&l:makeprg, ' "')
+exe 'CompilerSet makeprg='..escape(&l:makeprg, ' \|"')
CompilerSet errorformat=%f:%l:%c:\ %t%*[^:]:\ %m
let &cpo = s:cpo_save
diff --git a/runtime/compiler/pandoc.vim b/runtime/compiler/pandoc.vim
index 6c15e104c3..5d90a518c9 100644
--- a/runtime/compiler/pandoc.vim
+++ b/runtime/compiler/pandoc.vim
@@ -1,7 +1,7 @@
" Vim compiler file
" Compiler: Pandoc
" Maintainer: Konfekt
-" Last Change: 2024 Sep 8
+" Last Change: 2024 Nov 19
"
" Expects output file extension, say `:make html` or `:make pdf`.
" Passes additional arguments to pandoc, say `:make html --self-contained`.
@@ -56,7 +56,7 @@ execute 'CompilerSet makeprg=pandoc'..escape(
\ ' '..s:PandocLang()..
\ ' --from='..s:PandocFiletype(&filetype)..
\ ' '..get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', ''))..
- \ ' --output %:r:S.$* -- %:S', ' ')
+ \ ' --output %:r:S.$* -- %:S', ' \|"')
CompilerSet errorformat=\"%f\",\ line\ %l:\ %m
let &cpo = s:keepcpo
diff --git a/runtime/compiler/powershell.vim b/runtime/compiler/powershell.vim
index 821fea4085..3d37d7c847 100644
--- a/runtime/compiler/powershell.vim
+++ b/runtime/compiler/powershell.vim
@@ -3,8 +3,9 @@
" URL: https://github.com/PProvost/vim-ps1
" Contributors: Enno Nagel
" Last Change: 2024 Mar 29
-" 2024 Apr 03 by The Vim Project (removed :CompilerSet definition)
-" 2024 Apr 05 by The Vim Project (avoid leaving behind g:makeprg)
+" 2024 Apr 03 by the Vim Project (removed :CompilerSet definition)
+" 2024 Apr 05 by the Vim Project (avoid leaving behind g:makeprg)
+" 2024 Nov 19 by the Vim Project (properly escape makeprg setting)
if exists("current_compiler")
finish
@@ -49,7 +50,7 @@ let s:makeprg = g:ps1_makeprg_cmd .. ' %:p:S'
" + CategoryInfo : ObjectNotFound: (Write-Ouput:String) [], CommandNotFoundException
" + FullyQualifiedErrorId : CommandNotFoundException
-execute 'CompilerSet makeprg=' .. escape(s:makeprg, ' ')
+execute 'CompilerSet makeprg=' .. escape(s:makeprg, ' \|"')
" Showing error in context with underlining.
CompilerSet errorformat=%+G+%m
diff --git a/runtime/compiler/pylint.vim b/runtime/compiler/pylint.vim
index 4c9c23e125..96abf315ab 100644
--- a/runtime/compiler/pylint.vim
+++ b/runtime/compiler/pylint.vim
@@ -2,6 +2,7 @@
" Compiler: Pylint for Python
" Maintainer: Daniel Moch <daniel@danielmoch.com>
" Last Change: 2024 Nov 07 by The Vim Project (added params variable)
+" 2024 Nov 19 by the Vim Project (properly escape makeprg setting)
if exists("current_compiler") | finish | endif
let current_compiler = "pylint"
@@ -13,7 +14,7 @@ set cpo&vim
let &l:makeprg = 'pylint ' .
\ '--output-format=text --msg-template="{path}:{line}:{column}:{C}: [{symbol}] {msg}" --reports=no ' .
\ get(b:, "pylint_makeprg_params", get(g:, "pylint_makeprg_params", '--jobs=0'))
-exe 'CompilerSet makeprg='..escape(&l:makeprg, ' "')
+exe 'CompilerSet makeprg='..escape(&l:makeprg, ' \|"')
CompilerSet errorformat=%A%f:%l:%c:%t:\ %m,%A%f:%l:\ %m,%A%f:(%l):\ %m,%-Z%p^%.%#,%-G%.%#
let &cpo = s:cpo_save
diff --git a/runtime/compiler/ruff.vim b/runtime/compiler/ruff.vim
index 11a69740d8..318f4fe5cb 100644
--- a/runtime/compiler/ruff.vim
+++ b/runtime/compiler/ruff.vim
@@ -2,6 +2,7 @@
" Compiler: Ruff (Python linter)
" Maintainer: @pbnj-dragon
" Last Change: 2024 Nov 07
+" 2024 Nov 19 by the Vim Project (properly escape makeprg setting)
if exists("current_compiler") | finish | endif
let current_compiler = "ruff"
@@ -12,7 +13,7 @@ set cpo&vim
" CompilerSet makeprg=ruff
let &l:makeprg= 'ruff check --output-format=concise '
\ ..get(b:, 'ruff_makeprg_params', get(g:, 'ruff_makeprg_params', '--preview'))
-exe 'CompilerSet makeprg='..escape(&l:makeprg, ' "')
+exe 'CompilerSet makeprg='..escape(&l:makeprg, ' \|"')
CompilerSet errorformat=%f:%l:%c:\ %m,%f:%l:\ %m,%f:%l:%c\ -\ %m,%f:
let &cpo = s:cpo_save
diff --git a/runtime/compiler/tex.vim b/runtime/compiler/tex.vim
index 282b3a0588..bc1623729a 100644
--- a/runtime/compiler/tex.vim
+++ b/runtime/compiler/tex.vim
@@ -3,8 +3,9 @@
" Maintainer: Artem Chuprina <ran@ran.pp.ru>
" Contributors: Enno Nagel
" Last Change: 2024 Mar 29
-" 2024 Apr 03 by The Vim Project (removed :CompilerSet definition)
-" 2024 Apr 05 by The Vim Project (avoid leaving behind g:makeprg)
+" 2024 Apr 03 by the Vim Project (removed :CompilerSet definition)
+" 2024 Apr 05 by the Vim Project (avoid leaving behind g:makeprg)
+" 2024 Nov 19 by the Vim Project (properly escape makeprg setting)
if exists("current_compiler")
finish
@@ -27,7 +28,7 @@ if exists('b:tex_ignore_makefile') || exists('g:tex_ignore_makefile') ||
let current_compiler = "latex"
endif
let s:makeprg=current_compiler .. ' -interaction=nonstopmode'
- execute 'CompilerSet makeprg=' .. escape(s:makeprg, ' ')
+ execute 'CompilerSet makeprg=' .. escape(s:makeprg, ' \|"')
else
let current_compiler = 'make'
endif
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index c9b84f5238..c5dabeb551 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -658,8 +658,8 @@ nvim_echo({chunks}, {history}, {opts}) *nvim_echo()*
Parameters: ~
• {chunks} A list of `[text, hl_group]` arrays, each representing a
- text chunk with specified highlight. `hl_group` element can
- be omitted for no highlight.
+ text chunk with specified highlight group name or ID.
+ `hl_group` element can be omitted for no highlight.
• {history} if true, add to |message-history|.
• {opts} Optional parameters.
• verbose: Message is printed as a result of 'verbose'
@@ -2672,8 +2672,10 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
• id : id of the extmark to edit.
• end_row : ending line of the mark, 0-based inclusive.
• end_col : ending col of the mark, 0-based exclusive.
- • hl_group : name of the highlight group used to highlight
- this mark.
+ • hl_group : highlight group used for the text range. This
+ and below highlight groups can be supplied either as a
+ string or as an integer, the latter of which can be
+ obtained using |nvim_get_hl_id_by_name()|.
• hl_eol : when true, for a multiline highlight covering the
EOL of a line, continue the highlight for the rest of the
screen line (just like for diff and cursorline highlight).
@@ -2682,9 +2684,7 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
with specified highlight. `highlight` element can either
be a single highlight group, or an array of multiple
highlight groups that will be stacked (highest priority
- last). A highlight group can be supplied either as a
- string or as an integer, the latter which can be obtained
- using |nvim_get_hl_id_by_name()|.
+ last).
• virt_text_pos : position of virtual text. Possible values:
• "eol": right after eol character (default).
• "overlay": display over the specified column, without
@@ -2750,15 +2750,14 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
buffer or end of the line respectively. Defaults to true.
• sign_text: string of length 1-2 used to display in the
sign column.
- • sign_hl_group: name of the highlight group used to
- highlight the sign column text.
- • number_hl_group: name of the highlight group used to
- highlight the number column.
- • line_hl_group: name of the highlight group used to
- highlight the whole line.
- • cursorline_hl_group: name of the highlight group used to
- highlight the sign column text when the cursor is on the
- same line as the mark and 'cursorline' is enabled.
+ • sign_hl_group: highlight group used for the sign column
+ text.
+ • number_hl_group: highlight group used for the number
+ column.
+ • line_hl_group: highlight group used for the whole line.
+ • cursorline_hl_group: highlight group used for the sign
+ column text when the cursor is on the same line as the
+ mark and 'cursorline' is enabled.
• conceal: string which should be either empty or a single
character. Enable concealing similar to |:syn-conceal|.
When a character is supplied it is used as |:syn-cchar|.
@@ -3196,7 +3195,7 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
• focusable: Enable focus by user actions (wincmds, mouse
events). Defaults to true. Non-focusable windows can be
entered by |nvim_set_current_win()|, or, when the `mouse`
- field is set to true, by mouse events.
+ field is set to true, by mouse events. See |focusable|.
• mouse: Specify how this window interacts with mouse
events. Defaults to `focusable` value.
• If false, mouse events pass through this window.
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index 5e809ad26c..c6ca5e5ce9 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -51,11 +51,19 @@ LSP
• vim.lsp.buf_request_all The `error` key has been renamed to `err` inside
the result parameter of the handler.
• *vim.lsp.with()* Pass configuration to equivalent
- functions in `vim.lsp.buf.*'.
+ functions in `vim.lsp.buf.*`.
• |vim.lsp.handlers|
No longer support client to server response handlers. Only server to
client requests/notification handlers are supported.
• *vim.lsp.handlers.signature_help()* Use |vim.lsp.buf.signature_help()| instead.
+• `client.request()` Use |Client:request()| instead.
+• `client.request_sync()` Use |Client:request_sync()| instead.
+• `client.notify()` Use |Client:notify()| instead.
+• `client.cancel_request()` Use |Client:cancel_request()| instead.
+• `client.stop()` Use |Client:stop()| instead.
+• `client.is_stopped()` Use |Client:is_stopped()| instead.
+• `client.supports_method()` Use |Client:supports_method()| instead.
+• `client.on_attach()` Use |Client:on_attach()| instead.
------------------------------------------------------------------------------
DEPRECATED IN 0.10 *deprecated-0.10*
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 87df1e06d6..3cb3e590f4 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -338,13 +338,16 @@ Highlight groups that are meant to be used by |vim.lsp.buf.document_highlight()|
You can see more about the differences in types here:
https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight
- *hl-LspReferenceText*
+ *hl-LspReferenceText*
LspReferenceText used for highlighting "text" references
- *hl-LspReferenceRead*
+ *hl-LspReferenceRead*
LspReferenceRead used for highlighting "read" references
- *hl-LspReferenceWrite*
+ *hl-LspReferenceWrite*
LspReferenceWrite used for highlighting "write" references
- *hl-LspInlayHint*
+ *hl-LspReferenceTarget*
+LspReferenceTarget used for highlighting reference targets (e.g. in a
+ hover range)
+ *hl-LspInlayHint*
LspInlayHint used for highlighting inlay hints
@@ -969,54 +972,24 @@ Lua module: vim.lsp.client *lsp-client*
• {capabilities} (`lsp.ClientCapabilities`) The capabilities
provided by the client (editor or tool)
• {dynamic_capabilities} (`lsp.DynamicCapabilities`)
- • {request} (`fun(method: string, params: table?, handler: lsp.Handler?, bufnr: integer?): boolean, integer?`)
- Sends a request to the server. This is a thin
- wrapper around {client.rpc.request} with some
- additional checking. If {handler} is not
- specified and if there's no respective global
- handler, then an error will occur. Returns:
- {status}, {client_id}?. {status} is a boolean
- indicating if the notification was successful.
- If it is `false`, then it will always be
- `false` (the client has shutdown). If {status}
- is `true`, the function returns {request_id}
- as the second result. You can use this with
- `client.cancel_request(request_id)` to cancel
- the request.
- • {request_sync} (`fun(method: string, params: table?, timeout_ms: integer?, bufnr: integer): {err: lsp.ResponseError?, result:any}?, string?`)
- err # a dict
- • {notify} (`fun(method: string, params: table?): boolean`)
- Sends a notification to an LSP server.
- Returns: a boolean to indicate if the
- notification was successful. If it is false,
- then it will always be false (the client has
- shutdown).
- • {cancel_request} (`fun(id: integer): boolean`) Cancels a
- request with a given request id. Returns: same
- as `notify()`.
- • {stop} (`fun(force?: boolean)`) Stops a client,
- optionally with force. By default, it will
- just ask the server to shutdown without force.
- If you request to stop a client which has
- previously been requested to shutdown, it will
- automatically escalate and force shutdown.
- • {on_attach} (`fun(bufnr: integer)`) Runs the on_attach
- function from the client's config if it was
- defined. Useful for buffer-local setup.
- • {supports_method} (`fun(method: string, opts?: {bufnr: integer?}): boolean`)
- Checks if a client supports a given method.
- Always returns true for unknown off-spec
- methods. {opts} is a optional
- `{bufnr?: integer}` table. Some language
- server capabilities can be file specific.
- • {is_stopped} (`fun(): boolean`) Checks whether a client is
- stopped. Returns: true if the client is fully
- stopped.
+ • {request} (`fun(self: vim.lsp.Client, method: string, params: table?, handler: lsp.Handler?, bufnr: integer?): boolean, integer?`)
+ See |Client:request()|.
+ • {request_sync} (`fun(self: vim.lsp.Client, method: string, params: table, timeout_ms: integer?, bufnr: integer): {err: lsp.ResponseError?, result:any}?, string?`)
+ See |Client:request_sync()|.
+ • {notify} (`fun(self: vim.lsp.Client, method: string, params: table?): boolean`)
+ See |Client:notify()|.
+ • {cancel_request} (`fun(self: vim.lsp.Client, id: integer): boolean`)
+ See |Client:cancel_request()|.
+ • {stop} (`fun(self: vim.lsp.Client, force: boolean?)`)
+ See |Client:stop()|.
+ • {is_stopped} (`fun(self: vim.lsp.Client): boolean`) See
+ |Client:is_stopped()|.
• {exec_cmd} (`fun(self: vim.lsp.Client, command: lsp.Command, context: {bufnr?: integer}?, handler: lsp.Handler?)`)
- Execute a lsp command, either via client
- command function (if available) or via
- workspace/executeCommand (if supported by the
- server)
+ See |Client:exec_cmd()|.
+ • {on_attach} (`fun(self: vim.lsp.Client, bufnr: integer)`)
+ See |Client:on_attach()|.
+ • {supports_method} (`fun(self: vim.lsp.Client, method: string, bufnr: integer?)`)
+ See |Client:supports_method()|.
*vim.lsp.Client.Progress*
Extends: |vim.Ringbuf|
@@ -1087,7 +1060,8 @@ Lua module: vim.lsp.client *lsp-client*
• {name}? (`string`, default: client-id) Name in log
messages.
• {get_language_id}? (`fun(bufnr: integer, filetype: string): string`)
- Language ID as string. Defaults to the filetype.
+ Language ID as string. Defaults to the buffer
+ filetype.
• {offset_encoding}? (`'utf-8'|'utf-16'|'utf-32'`) The encoding that
the LSP server expects. Client does not verify
this is correct.
@@ -1146,6 +1120,18 @@ Lua module: vim.lsp.client *lsp-client*
on initialization.
+Client:cancel_request({id}) *Client:cancel_request()*
+ Cancels a request with a given request id.
+
+ Parameters: ~
+ • {id} (`integer`) id of request to cancel
+
+ Return: ~
+ (`boolean`) status indicating if the notification was successful.
+
+ See also: ~
+ • |Client:notify()|
+
Client:exec_cmd({command}, {context}, {handler}) *Client:exec_cmd()*
Execute a lsp command, either via client command function (if available)
or via workspace/executeCommand (if supported by the server)
@@ -1155,6 +1141,95 @@ Client:exec_cmd({command}, {context}, {handler}) *Client:exec_cmd()*
• {context} (`{bufnr?: integer}?`)
• {handler} (`lsp.Handler?`) only called if a server command
+Client:is_stopped() *Client:is_stopped()*
+ Checks whether a client is stopped.
+
+ Return: ~
+ (`boolean`) true if client is stopped or in the process of being
+ stopped; false otherwise
+
+Client:notify({method}, {params}) *Client:notify()*
+ Sends a notification to an LSP server.
+
+ Parameters: ~
+ • {method} (`string`) LSP method name.
+ • {params} (`table?`) LSP request params.
+
+ Return: ~
+ (`boolean`) status indicating if the notification was successful. If
+ it is false, then the client has shutdown.
+
+Client:on_attach({bufnr}) *Client:on_attach()*
+ Runs the on_attach function from the client's config if it was defined.
+ Useful for buffer-local setup.
+
+ Parameters: ~
+ • {bufnr} (`integer`) Buffer number
+
+ *Client:request()*
+Client:request({method}, {params}, {handler}, {bufnr})
+ Sends a request to the server.
+
+ This is a thin wrapper around {client.rpc.request} with some additional
+ checks for capabilities and handler availability.
+
+ Parameters: ~
+ • {method} (`string`) LSP method name.
+ • {params} (`table?`) LSP request params.
+ • {handler} (`lsp.Handler?`) Response |lsp-handler| for this method.
+ • {bufnr} (`integer?`) Buffer handle. 0 for current (default).
+
+ Return (multiple): ~
+ (`boolean`) status indicates whether the request was successful. If it
+ is `false`, then it will always be `false` (the client has shutdown).
+ (`integer?`) request_id Can be used with |Client:cancel_request()|.
+ `nil` is request failed.
+
+ See also: ~
+ • |vim.lsp.buf_request_all()|
+
+ *Client:request_sync()*
+Client:request_sync({method}, {params}, {timeout_ms}, {bufnr})
+ Sends a request to the server and synchronously waits for the response.
+
+ This is a wrapper around |Client:request()|
+
+ Parameters: ~
+ • {method} (`string`) LSP method name.
+ • {params} (`table`) LSP request params.
+ • {timeout_ms} (`integer?`) Maximum time in milliseconds to wait for a
+ result. Defaults to 1000
+ • {bufnr} (`integer`) Buffer handle (0 for current).
+
+ Return (multiple): ~
+ (`{err: lsp.ResponseError?, result:any}?`) `result` and `err` from the
+ |lsp-handler|. `nil` is the request was unsuccessful
+ (`string?`) err On timeout, cancel or error, where `err` is a string
+ describing the failure reason.
+
+ See also: ~
+ • |vim.lsp.buf_request_sync()|
+
+Client:stop({force}) *Client:stop()*
+ Stops a client, optionally with force.
+
+ By default, it will just request the server to shutdown without force. If
+ you request to stop a client which has previously been requested to
+ shutdown, it will automatically escalate and force shutdown.
+
+ Parameters: ~
+ • {force} (`boolean?`)
+
+Client:supports_method({method}, {bufnr}) *Client:supports_method()*
+ Checks if a client supports a given method. Always returns true for
+ unknown off-spec methods.
+
+ Note: Some language server capabilities can be file specific.
+
+ Parameters: ~
+ • {method} (`string`)
+ • {bufnr} (`integer?`)
+
==============================================================================
Lua module: vim.lsp.buf *lsp-buf*
@@ -1335,6 +1410,14 @@ hover({config}) *vim.lsp.buf.hover()*
mappings are available as usual, except that "q" dismisses the window. You
can scroll the contents the same as you would any other buffer.
+ Note: to disable hover highlights, add the following to your config: >lua
+ vim.api.nvim_create_autocmd('ColorScheme', {
+ callback = function()
+ vim.api.nvim_set_hl(0, 'LspReferenceTarget', {})
+ end,
+ })
+<
+
Parameters: ~
• {config} (`vim.lsp.buf.hover.Opts?`) See |vim.lsp.buf.hover.Opts|.
@@ -1587,12 +1670,12 @@ get({filter}) *vim.lsp.inlay_hint.get()*
local hint = vim.lsp.inlay_hint.get({ bufnr = 0 })[1] -- 0 for current buffer
local client = vim.lsp.get_client_by_id(hint.client_id)
- local resp = client.request_sync('inlayHint/resolve', hint.inlay_hint, 100, 0)
+ local resp = client:request_sync('inlayHint/resolve', hint.inlay_hint, 100, 0)
local resolved_hint = assert(resp and resp.result, resp.err)
vim.lsp.util.apply_text_edits(resolved_hint.textEdits, 0, client.encoding)
location = resolved_hint.label[1].location
- client.request('textDocument/hover', {
+ client:request('textDocument/hover', {
textDocument = { uri = location.uri },
position = location.range.start,
})
@@ -1942,12 +2025,10 @@ make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding})
selection.
• {bufnr} (`integer?`) buffer handle or 0 for current,
defaults to current
- • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) defaults to
- `offset_encoding` of first client of `bufnr`
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
Return: ~
- (`table`) { textDocument = { uri = `current_file_uri` }, range = {
- start = `start_position`, end = `end_position` } }
+ (`{ textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }`)
*vim.lsp.util.make_position_params()*
make_position_params({window}, {offset_encoding})
@@ -1957,9 +2038,7 @@ make_position_params({window}, {offset_encoding})
Parameters: ~
• {window} (`integer?`) window handle or 0 for current,
defaults to current
- • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) defaults to
- `offset_encoding` of first client of buffer of
- `window`
+ • {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
Return: ~
(`lsp.TextDocumentPositionParams`)
@@ -1977,13 +2056,10 @@ make_range_params({window}, {offset_encoding})
Parameters: ~
• {window} (`integer?`) window handle or 0 for current,
defaults to current
- • {offset_encoding} (`"utf-8"|"utf-16"|"utf-32"?`) defaults to
- `offset_encoding` of first client of buffer of
- `window`
+ • {offset_encoding} (`"utf-8"|"utf-16"|"utf-32"`)
Return: ~
- (`table`) { textDocument = { uri = `current_file_uri` }, range = {
- start = `current_position`, end = `current_position` } }
+ (`{ textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }`)
*vim.lsp.util.make_text_document_params()*
make_text_document_params({bufnr})
@@ -2149,7 +2225,7 @@ should_log({level}) *vim.lsp.log.should_log()*
• {level} (`integer`) log level
Return: ~
- (`bool`) true if would log, false if not
+ (`boolean`) true if would log, false if not
==============================================================================
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 243c907180..4d4a51872a 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -1937,12 +1937,10 @@ vim.show_pos({bufnr}, {row}, {col}, {filter}) *vim.show_pos()*
*vim.Ringbuf*
Fields: ~
- • {clear} (`fun()`) Clear all items
- • {push} (`fun(item: T)`) Adds an item, overriding the oldest item if
- the buffer is full.
- • {pop} (`fun(): T?`) Removes and returns the first unread item
- • {peek} (`fun(): T?`) Returns the first unread item without removing
- it
+ • {clear} (`fun()`) See |Ringbuf:clear()|.
+ • {push} (`fun(item: T)`) See |Ringbuf:push()|.
+ • {pop} (`fun(): T?`) See |Ringbuf:pop()|.
+ • {peek} (`fun(): T?`) See |Ringbuf:peek()|.
Ringbuf:clear() *Ringbuf:clear()*
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index c8d0df5c96..c0d0f7b1bc 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -99,6 +99,9 @@ LSP
Instead use: >lua
vim.diagnostic.config(config, vim.lsp.diagnostic.get_namespace(client_id))
<
+• |vim.lsp.util.make_position_params()|, |vim.lsp.util.make_range_params()|
+ and |vim.lsp.util.make_given_range_params()| now require the `offset_encoding`
+ parameter.
LUA
@@ -220,12 +223,15 @@ LSP
• |vim.lsp.buf.signature_help()| can now cycle through different signatures
using `<C-s>` and also support multiple clients.
• The client now supports `'utf-8'` and `'utf-32'` position encodings.
+• |vim.lsp.buf.hover()| now highlights hover ranges using the
+ |hl-LspReferenceTarget| highlight group.
+• Functions in |vim.lsp.Client| can now be called as methods.
LUA
• |vim.fs.rm()| can delete files and directories.
• |vim.validate()| now has a new signature which uses less tables,
- is more peformant and easier to read.
+ is more performant and easier to read.
• |vim.str_byteindex()| and |vim.str_utfindex()| gained overload signatures
supporting two new parameters, `encoding` and `strict_indexing`.
@@ -322,6 +328,11 @@ These existing features changed their behavior.
current window, and it no longer throws |E444| when there is only one window
on the screen. Global variable `vim.g.pager` is removed.
+• Default 'titlestring' is now implemented with 'statusline' "%" format items.
+ This means the default, empty value is essentially an alias to:
+ `%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim`. This is only an
+ implementation simplification, not a behavior change.
+
==============================================================================
REMOVED FEATURES *news-removed*
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index c972a05c4d..64ad2d2956 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -6590,6 +6590,10 @@ A jump table for the options with a short description can be found at |Q_op|.
expanded according to the rules used for 'statusline'. If it contains
an invalid '%' format, the value is used as-is and no error or warning
will be given when the value is set.
+
+ The default behaviour is equivalent to: >vim
+ set titlestring=%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim
+<
This option cannot be set in a modeline when 'modelineexpr' is off.
Example: >vim
diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt
index 09d1369d46..04dd854637 100644
--- a/runtime/doc/pi_netrw.txt
+++ b/runtime/doc/pi_netrw.txt
@@ -1,4 +1,4 @@
-*pi_netrw.txt* For Vim version 8.2. Last change: 2020 Aug 15
+*pi_netrw.txt* Nvim
------------------------------------------------
NETRW REFERENCE MANUAL by Charles E. Campbell
diff --git a/runtime/doc/pi_tar.txt b/runtime/doc/pi_tar.txt
index c8570044e5..96b26d92e7 100644
--- a/runtime/doc/pi_tar.txt
+++ b/runtime/doc/pi_tar.txt
@@ -1,4 +1,4 @@
-*pi_tar.txt* For Vim version 8.2. Last change: 2020 Jan 07
+*pi_tar.txt* Nvim
+====================+
| Tar File Interface |
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index e439e8fccb..5fc6429f7a 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -1605,8 +1605,7 @@ LanguageTree:register_cbs({cbs}, {recursive})
• {cbs} (`table<TSCallbackNameOn,function>`) An
|nvim_buf_attach()|-like table argument with the
following handlers:
- • `on_bytes` : see |nvim_buf_attach()|, but this will be
- called after the parsers callback.
+ • `on_bytes` : see |nvim_buf_attach()|.
• `on_changedtree` : a callback that will be called every
time the tree has syntactical changes. It will be
passed two arguments: a table of the ranges (as node
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index 4ee8121034..55eba484bc 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -795,11 +795,16 @@ must handle.
"echo" |:echo| message
"echomsg" |:echomsg| message
"echoerr" |:echoerr| message
+ "list_cmd" List output for various commands (|:ls|, |:set|, …)
"lua_error" Error in |:lua| code
+ "lua_print" |print()| from |:lua| code
"rpc_error" Error response from |rpcrequest()|
+ "number_prompt" Number input prompt (|inputlist()|, |z=|, …)
"return_prompt" |press-enter| prompt after a multiple messages
"quickfix" Quickfix navigation message
+ "search_cmd" Entered search command
"search_count" Search count message ("S" flag of 'shortmess')
+ "wildlist" 'wildmode' "list" message
"wmsg" Warning ("search hit BOTTOM", |W10|, …)
New kinds may be added in the future; clients should treat unknown
kinds as the empty kind.
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 8fa94a2601..adc866af6b 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -89,7 +89,6 @@ Defaults *nvim-defaults*
- 'undodir' defaults to ~/.local/state/nvim/undo// (|xdg|), auto-created
- 'viewoptions' includes "unix,slash", excludes "options"
- 'viminfo' includes "!"
-- 'wildmenu' is enabled
- 'wildoptions' defaults to "pum,tagfile"
- |editorconfig| plugin is enabled, .editorconfig settings are applied.
@@ -414,7 +413,7 @@ TUI:
- 'term' reflects the terminal type derived from |$TERM| and other environment
checks. For debugging only; not reliable during startup. >vim
:echo &term
-- "builtin_x" means one of the |builtin-terms| was chosen, because the expected
+- "builtin_x" means one of the |builtin-terms| was chosen, because the expected
terminfo file was not found on the system.
- Nvim will use 256-colour capability on Linux virtual terminals. Vim uses
only 8 colours plus bright foreground on Linux VTs.
@@ -616,6 +615,11 @@ Autocommands:
- |TermResponse| is fired for any OSC sequence received from the terminal,
instead of the Primary Device Attributes response. |v:termresponse|
+Options:
+- 'titlestring' uses printf-style '%' items (see: 'statusline') to implement
+ the default behaviour. The implementation is equivalent to setting
+ 'titlestring' to `%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim`.
+
==============================================================================
Missing features *nvim-missing*
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 5729dd0874..24aa7b1b11 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -69,7 +69,8 @@ If a window is focusable, it is part of the "navigation stack", that is,
editor commands such as :windo, |CTRL-W|, etc., will consider the window as
one that can be made the "current window". A non-focusable window will be
skipped by such commands (though it can be explicitly focused by
-|nvim_set_current_win()|).
+|nvim_set_current_win()|). Non-focusable windows are not listed by |:tabs|, and
+are not counted by the default 'tabline'.
Windows (especially floating windows) can have many other |api-win_config|
properties such as "hide" and "fixed" which also affect behavior.
diff --git a/runtime/ftplugin/checkhealth.vim b/runtime/ftplugin/checkhealth.vim
index 62a1970b4a..cc53d723c2 100644
--- a/runtime/ftplugin/checkhealth.vim
+++ b/runtime/ftplugin/checkhealth.vim
@@ -1,6 +1,5 @@
" Vim filetype plugin
" Language: Nvim :checkhealth buffer
-" Last Change: 2022 Nov 10
if exists("b:did_ftplugin")
finish
@@ -8,11 +7,11 @@ endif
runtime! ftplugin/help.vim
-setlocal wrap breakindent linebreak
+setlocal wrap breakindent linebreak nolist
let &l:iskeyword='!-~,^*,^|,^",192-255'
if exists("b:undo_ftplugin")
- let b:undo_ftplugin .= "|setl wrap< bri< lbr< kp< isk<"
+ let b:undo_ftplugin .= "|setl wrap< bri< lbr< kp< isk< list<"
else
- let b:undo_ftplugin = "setl wrap< bri< lbr< kp< isk<"
+ let b:undo_ftplugin = "setl wrap< bri< lbr< kp< isk< list<"
endif
diff --git a/runtime/ftplugin/karel.vim b/runtime/ftplugin/karel.vim
new file mode 100644
index 0000000000..8ccc2b32ce
--- /dev/null
+++ b/runtime/ftplugin/karel.vim
@@ -0,0 +1,16 @@
+" Vim filetype plugin file
+" Language: KAREL
+" Last Change: 2024-11-18
+" Maintainer: Kirill Morozov <kirill@robotix.pro>
+" Credits: Patrick Meiser-Knosowski for the initial implementation.
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal comments=:--
+setlocal commentstring=--\ %s
+setlocal suffixesadd+=.kl,.KL
+
+let b:undo_ftplugin = "setlocal com< cms< sua<"
diff --git a/runtime/ftplugin/mss.vim b/runtime/ftplugin/mss.vim
new file mode 100644
index 0000000000..de2f8791ec
--- /dev/null
+++ b/runtime/ftplugin/mss.vim
@@ -0,0 +1,16 @@
+" Vim filetype plugin file
+" Language: Vivado mss file
+" Last Change: 2024 Oct 22
+" Document: https://docs.amd.com/r/2020.2-English/ug1400-vitis-embedded/Microprocessor-Software-Specification-MSS
+" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal comments=b:#,fb:-
+setlocal commentstring=#\ %s
+
+let b:match_words = '\<BEGIN\>:\<END\>'
+let b:undo_ftplugin = "setl com< cms< | unlet b:match_words"
diff --git a/runtime/ftplugin/opencl.vim b/runtime/ftplugin/opencl.vim
new file mode 100644
index 0000000000..e8570fbe95
--- /dev/null
+++ b/runtime/ftplugin/opencl.vim
@@ -0,0 +1,12 @@
+" Vim filetype plugin file
+" Language: OpenCL
+" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
+" Last Change: 2024 Nov 19
+
+if exists("b:did_ftplugin") | finish | endif
+let b:did_ftplugin = 1
+
+setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,://
+setlocal commentstring=/*\ %s\ */ define& include&
+
+let b:undo_ftplugin = "setl commentstring< comments<"
diff --git a/runtime/ftplugin/query.lua b/runtime/ftplugin/query.lua
index 32d615c65c..711ee35775 100644
--- a/runtime/ftplugin/query.lua
+++ b/runtime/ftplugin/query.lua
@@ -1,6 +1,5 @@
-- Neovim filetype plugin file
-- Language: Treesitter query
--- Last Change: 2024 Jul 03
if vim.b.did_ftplugin == 1 then
return
diff --git a/runtime/indent/query.lua b/runtime/indent/query.lua
index c5b4f1f03d..17b8e9d2ac 100644
--- a/runtime/indent/query.lua
+++ b/runtime/indent/query.lua
@@ -1,6 +1,5 @@
-- Neovim indent file
-- Language: Treesitter query
--- Last Change: 2024 Jul 03
-- it's a lisp!
vim.cmd([[runtime! indent/lisp.vim]])
diff --git a/runtime/lua/vim/_buf.lua b/runtime/lua/vim/_buf.lua
new file mode 100644
index 0000000000..0631c96f77
--- /dev/null
+++ b/runtime/lua/vim/_buf.lua
@@ -0,0 +1,23 @@
+local M = {}
+
+--- Adds one or more blank lines above or below the cursor.
+-- TODO: move to _defaults.lua once it is possible to assign a Lua function to options #25672
+--- @param above? boolean Place blank line(s) above the cursor
+local function add_blank(above)
+ local offset = above and 1 or 0
+ local repeated = vim.fn['repeat']({ '' }, vim.v.count1)
+ local linenr = vim.api.nvim_win_get_cursor(0)[1]
+ vim.api.nvim_buf_set_lines(0, linenr - offset, linenr - offset, true, repeated)
+end
+
+-- TODO: move to _defaults.lua once it is possible to assign a Lua function to options #25672
+function M.space_above()
+ add_blank(true)
+end
+
+-- TODO: move to _defaults.lua once it is possible to assign a Lua function to options #25672
+function M.space_below()
+ add_blank()
+end
+
+return M
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index 25afd83145..06f6ed6829 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -366,16 +366,16 @@ do
-- Add empty lines
vim.keymap.set('n', '[<Space>', function()
- local repeated = vim.fn['repeat']({ '' }, vim.v.count1)
- local linenr = vim.api.nvim_win_get_cursor(0)[1]
- vim.api.nvim_buf_set_lines(0, linenr - 1, linenr - 1, true, repeated)
- end, { desc = 'Add empty line above cursor' })
+ -- TODO: update once it is possible to assign a Lua function to options #25672
+ vim.go.operatorfunc = "v:lua.require'vim._buf'.space_above"
+ return 'g@l'
+ end, { expr = true, desc = 'Add empty line above cursor' })
vim.keymap.set('n', ']<Space>', function()
- local repeated = vim.fn['repeat']({ '' }, vim.v.count1)
- local linenr = vim.api.nvim_win_get_cursor(0)[1]
- vim.api.nvim_buf_set_lines(0, linenr, linenr, true, repeated)
- end, { desc = 'Add empty line below cursor' })
+ -- TODO: update once it is possible to assign a Lua function to options #25672
+ vim.go.operatorfunc = "v:lua.require'vim._buf'.space_below"
+ return 'g@l'
+ end, { expr = true, desc = 'Add empty line below cursor' })
end
end
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index b4a1e0fc15..44f17b3f85 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -1151,21 +1151,16 @@ end
--- @param ... any
--- @return any # given arguments.
function vim.print(...)
- if vim.in_fast_event() then
- print(...)
- return ...
- end
-
+ local msg = {}
for i = 1, select('#', ...) do
local o = select(i, ...)
if type(o) == 'string' then
- vim.api.nvim_out_write(o)
+ table.insert(msg, o)
else
- vim.api.nvim_out_write(vim.inspect(o, { newline = '\n', indent = ' ' }))
+ table.insert(msg, vim.inspect(o, { newline = '\n', indent = ' ' }))
end
- vim.api.nvim_out_write('\n')
end
-
+ print(table.concat(msg, '\n'))
return ...
end
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index c28af7bbff..3c9b9d4f44 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -592,8 +592,9 @@ function vim.api.nvim_buf_line_count(buffer) end
--- - id : id of the extmark to edit.
--- - end_row : ending line of the mark, 0-based inclusive.
--- - end_col : ending col of the mark, 0-based exclusive.
---- - hl_group : name of the highlight group used to highlight
---- this mark.
+--- - hl_group : highlight group used for the text range. This and below
+--- highlight groups can be supplied either as a string or as an integer,
+--- the latter of which can be obtained using `nvim_get_hl_id_by_name()`.
--- - hl_eol : when true, for a multiline highlight covering the
--- EOL of a line, continue the highlight for the rest
--- of the screen line (just like for diff and
@@ -603,9 +604,7 @@ function vim.api.nvim_buf_line_count(buffer) end
--- text chunk with specified highlight. `highlight` element
--- can either be a single highlight group, or an array of
--- multiple highlight groups that will be stacked
---- (highest priority last). A highlight group can be supplied
---- either as a string or as an integer, the latter which
---- can be obtained using `nvim_get_hl_id_by_name()`.
+--- (highest priority last).
--- - virt_text_pos : position of virtual text. Possible values:
--- - "eol": right after eol character (default).
--- - "overlay": display over the specified column, without
@@ -676,15 +675,12 @@ function vim.api.nvim_buf_line_count(buffer) end
--- buffer or end of the line respectively. Defaults to true.
--- - sign_text: string of length 1-2 used to display in the
--- sign column.
---- - sign_hl_group: name of the highlight group used to
---- highlight the sign column text.
---- - number_hl_group: name of the highlight group used to
---- highlight the number column.
---- - line_hl_group: name of the highlight group used to
---- highlight the whole line.
---- - cursorline_hl_group: name of the highlight group used to
---- highlight the sign column text when the cursor is on
---- the same line as the mark and 'cursorline' is enabled.
+--- - sign_hl_group: highlight group used for the sign column text.
+--- - number_hl_group: highlight group used for the number column.
+--- - line_hl_group: highlight group used for the whole line.
+--- - cursorline_hl_group: highlight group used for the sign
+--- column text when the cursor is on the same line as the
+--- mark and 'cursorline' is enabled.
--- - conceal: string which should be either empty or a single
--- character. Enable concealing similar to `:syn-conceal`.
--- When a character is supplied it is used as `:syn-cchar`.
@@ -1106,8 +1102,8 @@ function vim.api.nvim_del_var(name) end
--- Echo a message.
---
--- @param chunks any[] A list of `[text, hl_group]` arrays, each representing a
---- text chunk with specified highlight. `hl_group` element
---- can be omitted for no highlight.
+--- text chunk with specified highlight group name or ID.
+--- `hl_group` element can be omitted for no highlight.
--- @param history boolean if true, add to `message-history`.
--- @param opts vim.api.keyset.echo_opts Optional parameters.
--- - verbose: Message is printed as a result of 'verbose' option.
@@ -1768,7 +1764,7 @@ function vim.api.nvim_open_term(buffer, opts) end
--- - focusable: Enable focus by user actions (wincmds, mouse events).
--- Defaults to true. Non-focusable windows can be entered by
--- `nvim_set_current_win()`, or, when the `mouse` field is set to true,
---- by mouse events.
+--- by mouse events. See `focusable`.
--- - mouse: Specify how this window interacts with mouse events.
--- Defaults to `focusable` value.
--- - If false, mouse events pass through this window.
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index cb783720ac..e485009ca2 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -7122,6 +7122,13 @@ vim.go.titleold = vim.o.titleold
--- expanded according to the rules used for 'statusline'. If it contains
--- an invalid '%' format, the value is used as-is and no error or warning
--- will be given when the value is set.
+---
+--- The default behaviour is equivalent to:
+---
+--- ```vim
+--- set titlestring=%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim
+--- ```
+---
--- This option cannot be set in a modeline when 'modelineexpr' is off.
---
--- Example:
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 3b3c4481f2..4383c0983e 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -275,6 +275,9 @@ local extension = {
mdh = 'c',
epro = 'c',
qc = 'c',
+ c3 = 'c3',
+ c3i = 'c3',
+ c3t = 'c3',
cabal = 'cabal',
cairo = 'cairo',
capnp = 'capnp',
@@ -300,6 +303,7 @@ local extension = {
cho = 'chordpro',
chordpro = 'chordpro',
ck = 'chuck',
+ cl = detect.cl,
eni = 'cl',
icl = 'clean',
cljx = 'clojure',
@@ -653,6 +657,8 @@ local extension = {
jsp = 'jsp',
jl = 'julia',
just = 'just',
+ kl = 'karel',
+ KL = 'karel',
kdl = 'kdl',
kv = 'kivy',
kix = 'kix',
@@ -686,7 +692,6 @@ local extension = {
ily = 'lilypond',
liquid = 'liquid',
liq = 'liquidsoap',
- cl = 'lisp',
L = 'lisp',
lisp = 'lisp',
el = 'lisp',
@@ -792,6 +797,7 @@ local extension = {
mof = 'msidl',
odl = 'msidl',
msql = 'msql',
+ mss = 'mss',
mu = 'mupad',
mush = 'mush',
mustache = 'mustache',
@@ -2211,6 +2217,7 @@ local pattern = {
['/screengrab/.*%.conf$'] = 'dosini',
['^${GNUPGHOME}/gpg%.conf$'] = 'gpg',
['/boot/grub/grub%.conf$'] = 'grub',
+ ['/hypr/.*%.conf$'] = 'hyprlang',
['^lilo%.conf'] = starsetf('lilo'),
['^named.*%.conf$'] = 'named',
['^rndc.*%.conf$'] = 'named',
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 98b001bd51..81b94c69db 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -181,6 +181,16 @@ function M.changelog(_, bufnr)
end
--- @type vim.filetype.mapfn
+function M.cl(_, bufnr)
+ local lines = table.concat(getlines(bufnr, 1, 4))
+ if lines:match('/%*') then
+ return 'opencl'
+ else
+ return 'lisp'
+ end
+end
+
+--- @type vim.filetype.mapfn
function M.class(_, bufnr)
-- Check if not a Java class (starts with '\xca\xfe\xba\xbe')
if not getline(bufnr, 1):find('^\202\254\186\190') then
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 42a0ccc3d4..c032d25cb1 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -3,7 +3,6 @@ local validate = vim.validate
local lsp = vim._defer_require('vim.lsp', {
_changetracking = ..., --- @module 'vim.lsp._changetracking'
- _dynamic = ..., --- @module 'vim.lsp._dynamic'
_snippet_grammar = ..., --- @module 'vim.lsp._snippet_grammar'
_tagfunc = ..., --- @module 'vim.lsp._tagfunc'
_watchfiles = ..., --- @module 'vim.lsp._watchfiles'
@@ -31,6 +30,13 @@ local changetracking = lsp._changetracking
---@nodoc
lsp.rpc_response_error = lsp.rpc.rpc_response_error
+lsp._resolve_to_request = {
+ [ms.codeAction_resolve] = ms.textDocument_codeAction,
+ [ms.codeLens_resolve] = ms.textDocument_codeLens,
+ [ms.documentLink_resolve] = ms.textDocument_documentLink,
+ [ms.inlayHint_resolve] = ms.textDocument_inlayHint,
+}
+
-- maps request name to the required server_capability in the client.
lsp._request_name_to_capability = {
[ms.callHierarchy_incomingCalls] = { 'callHierarchyProvider' },
@@ -343,17 +349,17 @@ end
---@param bufnr integer
function lsp._set_defaults(client, bufnr)
if
- client.supports_method(ms.textDocument_definition) and is_empty_or_default(bufnr, 'tagfunc')
+ client:supports_method(ms.textDocument_definition) and is_empty_or_default(bufnr, 'tagfunc')
then
vim.bo[bufnr].tagfunc = 'v:lua.vim.lsp.tagfunc'
end
if
- client.supports_method(ms.textDocument_completion) and is_empty_or_default(bufnr, 'omnifunc')
+ client:supports_method(ms.textDocument_completion) and is_empty_or_default(bufnr, 'omnifunc')
then
vim.bo[bufnr].omnifunc = 'v:lua.vim.lsp.omnifunc'
end
if
- client.supports_method(ms.textDocument_rangeFormatting)
+ client:supports_method(ms.textDocument_rangeFormatting)
and is_empty_or_default(bufnr, 'formatprg')
and is_empty_or_default(bufnr, 'formatexpr')
then
@@ -361,14 +367,14 @@ function lsp._set_defaults(client, bufnr)
end
vim._with({ buf = bufnr }, function()
if
- client.supports_method(ms.textDocument_hover)
+ client:supports_method(ms.textDocument_hover)
and is_empty_or_default(bufnr, 'keywordprg')
and vim.fn.maparg('K', 'n', false, false) == ''
then
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr, desc = 'vim.lsp.buf.hover()' })
end
end)
- if client.supports_method(ms.textDocument_diagnostic) then
+ if client:supports_method(ms.textDocument_diagnostic) then
lsp.diagnostic._enable(bufnr)
end
end
@@ -479,12 +485,12 @@ local function text_document_did_save_handler(bufnr)
local name = api.nvim_buf_get_name(bufnr)
local old_name = changetracking._get_and_set_name(client, bufnr, name)
if old_name and name ~= old_name then
- client.notify(ms.textDocument_didClose, {
+ client:notify(ms.textDocument_didClose, {
textDocument = {
uri = vim.uri_from_fname(old_name),
},
})
- client.notify(ms.textDocument_didOpen, {
+ client:notify(ms.textDocument_didOpen, {
textDocument = {
version = 0,
uri = uri,
@@ -500,7 +506,7 @@ local function text_document_did_save_handler(bufnr)
if type(save_capability) == 'table' and save_capability.includeText then
included_text = text(bufnr)
end
- client.notify(ms.textDocument_didSave, {
+ client:notify(ms.textDocument_didSave, {
textDocument = {
uri = uri,
},
@@ -521,10 +527,10 @@ local function buf_detach_client(bufnr, client)
changetracking.reset_buf(client, bufnr)
- if client.supports_method(ms.textDocument_didClose) then
+ if client:supports_method(ms.textDocument_didClose) then
local uri = vim.uri_from_bufnr(bufnr)
local params = { textDocument = { uri = uri } }
- client.notify(ms.textDocument_didClose, params)
+ client:notify(ms.textDocument_didClose, params)
end
client.attached_buffers[bufnr] = nil
@@ -558,12 +564,12 @@ local function buf_attach(bufnr)
},
reason = protocol.TextDocumentSaveReason.Manual, ---@type integer
}
- if client.supports_method(ms.textDocument_willSave) then
- client.notify(ms.textDocument_willSave, params)
+ if client:supports_method(ms.textDocument_willSave) then
+ client:notify(ms.textDocument_willSave, params)
end
- if client.supports_method(ms.textDocument_willSaveWaitUntil) then
+ if client:supports_method(ms.textDocument_willSaveWaitUntil) then
local result, err =
- client.request_sync(ms.textDocument_willSaveWaitUntil, params, 1000, ctx.buf)
+ client:request_sync(ms.textDocument_willSaveWaitUntil, params, 1000, ctx.buf)
if result and result.result then
util.apply_text_edits(result.result, ctx.buf, client.offset_encoding)
elseif err then
@@ -597,8 +603,8 @@ local function buf_attach(bufnr)
local params = { textDocument = { uri = uri } }
for _, client in ipairs(clients) do
changetracking.reset_buf(client, bufnr)
- if client.supports_method(ms.textDocument_didClose) then
- client.notify(ms.textDocument_didClose, params)
+ if client:supports_method(ms.textDocument_didClose) then
+ client:notify(ms.textDocument_didClose, params)
end
end
for _, client in ipairs(clients) do
@@ -656,7 +662,7 @@ function lsp.buf_attach_client(bufnr, client_id)
-- Send didOpen for the client if it is initialized. If it isn't initialized
-- then it will send didOpen on initialize.
if client.initialized then
- client:_on_attach(bufnr)
+ client:on_attach(bufnr)
end
return true
end
@@ -734,13 +740,13 @@ function lsp.stop_client(client_id, force)
for _, id in ipairs(ids) do
if type(id) == 'table' then
if id.stop then
- id.stop(force)
+ id:stop(force)
end
else
--- @cast id -vim.lsp.Client
local client = all_clients[id]
if client then
- client.stop(force)
+ client:stop(force)
end
end
end
@@ -784,7 +790,7 @@ function lsp.get_clients(filter)
and (filter.id == nil or client.id == filter.id)
and (filter.bufnr == nil or client.attached_buffers[bufnr])
and (filter.name == nil or client.name == filter.name)
- and (filter.method == nil or client.supports_method(filter.method, { bufnr = filter.bufnr }))
+ and (filter.method == nil or client:supports_method(filter.method, filter.bufnr))
and (filter._uninitialized or client.initialized)
then
clients[#clients + 1] = client
@@ -806,7 +812,7 @@ api.nvim_create_autocmd('VimLeavePre', {
local active_clients = lsp.get_clients()
log.info('exit_handler', active_clients)
for _, client in pairs(all_clients) do
- client.stop()
+ client:stop()
end
local timeouts = {} --- @type table<integer,integer>
@@ -841,7 +847,7 @@ api.nvim_create_autocmd('VimLeavePre', {
if not vim.wait(max_timeout, check_clients_closed, poll_time) then
for client_id, client in pairs(active_clients) do
if timeouts[client_id] ~= nil then
- client.stop(true)
+ client:stop(true)
end
end
end
@@ -877,11 +883,11 @@ function lsp.buf_request(bufnr, method, params, handler, on_unsupported)
local clients = lsp.get_clients({ bufnr = bufnr })
local client_request_ids = {} --- @type table<integer,integer>
for _, client in ipairs(clients) do
- if client.supports_method(method, { bufnr = bufnr }) then
+ if client:supports_method(method, bufnr) then
method_supported = true
local cparams = type(params) == 'function' and params(client, bufnr) or params --[[@as table?]]
- local request_success, request_id = client.request(method, cparams, handler, bufnr)
+ local request_success, request_id = client:request(method, cparams, handler, 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
@@ -904,7 +910,7 @@ function lsp.buf_request(bufnr, method, params, handler, on_unsupported)
local function _cancel_all_requests()
for client_id, request_id in pairs(client_request_ids) do
local client = all_clients[client_id]
- client.cancel_request(request_id)
+ client:cancel_request(request_id)
end
end
@@ -1043,7 +1049,7 @@ function lsp.formatexpr(opts)
end
local bufnr = api.nvim_get_current_buf()
for _, client in pairs(lsp.get_clients({ bufnr = bufnr })) do
- if client.supports_method(ms.textDocument_rangeFormatting) then
+ if client:supports_method(ms.textDocument_rangeFormatting) then
local params = util.make_formatting_params()
local end_line = vim.fn.getline(end_lnum) --[[@as string]]
local end_col = vim.str_utfindex(end_line, client.offset_encoding)
@@ -1059,7 +1065,7 @@ function lsp.formatexpr(opts)
},
}
local response =
- client.request_sync(ms.textDocument_rangeFormatting, params, timeout_ms, bufnr)
+ client:request_sync(ms.textDocument_rangeFormatting, params, timeout_ms, bufnr)
if response and response.result then
lsp.util.apply_text_edits(response.result, bufnr, client.offset_encoding)
return 0
diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua
index b2be53269f..8588502697 100644
--- a/runtime/lua/vim/lsp/_changetracking.lua
+++ b/runtime/lua/vim/lsp/_changetracking.lua
@@ -40,7 +40,7 @@ local M = {}
--- @class vim.lsp.CTGroupState
--- @field buffers table<integer,vim.lsp.CTBufferState>
--- @field debounce integer debounce duration in ms
---- @field clients table<integer, table> clients using this state. {client_id, client}
+--- @field clients table<integer, vim.lsp.Client> clients using this state. {client_id, client}
---@param group vim.lsp.CTGroup
---@return string
@@ -273,8 +273,8 @@ local function send_changes(bufnr, sync_kind, state, buf_state)
end
local uri = vim.uri_from_bufnr(bufnr)
for _, client in pairs(state.clients) do
- if not client.is_stopped() and vim.lsp.buf_is_attached(bufnr, client.id) then
- client.notify(protocol.Methods.textDocument_didChange, {
+ if not client:is_stopped() and vim.lsp.buf_is_attached(bufnr, client.id) then
+ client:notify(protocol.Methods.textDocument_didChange, {
textDocument = {
uri = uri,
version = util.buf_versions[bufnr],
diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua
deleted file mode 100644
index 27113c0e74..0000000000
--- a/runtime/lua/vim/lsp/_dynamic.lua
+++ /dev/null
@@ -1,110 +0,0 @@
-local glob = vim.glob
-
---- @class lsp.DynamicCapabilities
---- @field capabilities table<string, lsp.Registration[]>
---- @field client_id number
-local M = {}
-
---- @param client_id number
---- @return lsp.DynamicCapabilities
-function M.new(client_id)
- return setmetatable({
- capabilities = {},
- client_id = client_id,
- }, { __index = M })
-end
-
-function M:supports_registration(method)
- local client = vim.lsp.get_client_by_id(self.client_id)
- if not client then
- return false
- end
- local capability = vim.tbl_get(client.capabilities, unpack(vim.split(method, '/')))
- return type(capability) == 'table' and capability.dynamicRegistration
-end
-
---- @param registrations lsp.Registration[]
-function M:register(registrations)
- -- remove duplicates
- self:unregister(registrations)
- for _, reg in ipairs(registrations) do
- local method = reg.method
- if not self.capabilities[method] then
- self.capabilities[method] = {}
- end
- table.insert(self.capabilities[method], reg)
- end
-end
-
---- @param unregisterations lsp.Unregistration[]
-function M:unregister(unregisterations)
- for _, unreg in ipairs(unregisterations) do
- local method = unreg.method
- if not self.capabilities[method] then
- return
- end
- local id = unreg.id
- for i, reg in ipairs(self.capabilities[method]) do
- if reg.id == id then
- table.remove(self.capabilities[method], i)
- break
- end
- end
- end
-end
-
---- @param method string
---- @param opts? {bufnr: integer?}
---- @return lsp.Registration? (table|nil) the registration if found
-function M:get(method, opts)
- opts = opts or {}
- opts.bufnr = opts.bufnr or vim.api.nvim_get_current_buf()
- for _, reg in ipairs(self.capabilities[method] or {}) do
- if not reg.registerOptions then
- return reg
- end
- local documentSelector = reg.registerOptions.documentSelector
- if not documentSelector then
- return reg
- end
- if self:match(opts.bufnr, documentSelector) then
- return reg
- end
- end
-end
-
---- @param method string
---- @param opts? {bufnr: integer?}
-function M:supports(method, opts)
- return self:get(method, opts) ~= nil
-end
-
---- @param bufnr number
---- @param documentSelector lsp.DocumentSelector
---- @private
-function M:match(bufnr, documentSelector)
- local client = vim.lsp.get_client_by_id(self.client_id)
- if not client then
- return false
- end
- local language = client.get_language_id(bufnr, vim.bo[bufnr].filetype)
- local uri = vim.uri_from_bufnr(bufnr)
- local fname = vim.uri_to_fname(uri)
- for _, filter in ipairs(documentSelector) do
- local matches = true
- if filter.language and language ~= filter.language then
- matches = false
- end
- if matches and filter.scheme and not vim.startswith(uri, filter.scheme .. ':') then
- matches = false
- end
- if matches and filter.pattern and not glob.to_lpeg(filter.pattern):match(fname) then
- matches = false
- end
- if matches then
- return true
- end
- end
-end
-
-return M
diff --git a/runtime/lua/vim/lsp/_tagfunc.lua b/runtime/lua/vim/lsp/_tagfunc.lua
index f75d43f373..f6ffc63824 100644
--- a/runtime/lua/vim/lsp/_tagfunc.lua
+++ b/runtime/lua/vim/lsp/_tagfunc.lua
@@ -59,7 +59,7 @@ local function query_definition(pattern)
remaining = remaining - 1
end
local params = util.make_position_params(win, client.offset_encoding)
- client.request(ms.textDocument_definition, params, on_response, bufnr)
+ client:request(ms.textDocument_definition, params, on_response, bufnr)
end
vim.wait(1000, function()
return remaining == 0
diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua
index 98e9818bcd..248969885c 100644
--- a/runtime/lua/vim/lsp/_watchfiles.lua
+++ b/runtime/lua/vim/lsp/_watchfiles.lua
@@ -44,9 +44,8 @@ M._poll_exclude_pattern = glob.to_lpeg('**/.git/{objects,subtree-cache}/**')
--- Registers the workspace/didChangeWatchedFiles capability dynamically.
---
---@param reg lsp.Registration LSP Registration object.
----@param ctx lsp.HandlerContext Context from the |lsp-handler|.
-function M.register(reg, ctx)
- local client_id = ctx.client_id
+---@param client_id integer Client ID.
+function M.register(reg, client_id)
local client = assert(vim.lsp.get_client_by_id(client_id), 'Client must be running')
-- Ill-behaved servers may not honor the client capability and try to register
-- anyway, so ignore requests when the user has opted out of the feature.
@@ -117,7 +116,7 @@ function M.register(reg, ctx)
local params = {
changes = change_queues[client_id],
}
- client.notify(ms.workspace_didChangeWatchedFiles, params)
+ client:notify(ms.workspace_didChangeWatchedFiles, params)
queue_timers[client_id] = nil
change_queues[client_id] = nil
change_cache[client_id] = nil
@@ -155,9 +154,8 @@ end
--- Unregisters the workspace/didChangeWatchedFiles capability dynamically.
---
---@param unreg lsp.Unregistration LSP Unregistration object.
----@param ctx lsp.HandlerContext Context from the |lsp-handler|.
-function M.unregister(unreg, ctx)
- local client_id = ctx.client_id
+---@param client_id integer Client ID.
+function M.unregister(unreg, client_id)
local client_cancels = cancels[client_id]
local reg_cancels = client_cancels[unreg.id]
while #reg_cancels > 0 do
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 6d7597c5ff..10c0dbefdc 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -20,6 +20,8 @@ local function client_positional_params(params)
end
end
+local hover_ns = api.nvim_create_namespace('vim_lsp_hover_range')
+
--- @class vim.lsp.buf.hover.Opts : vim.lsp.util.open_floating_preview.Opts
--- @field silent? boolean
@@ -30,13 +32,24 @@ end
--- In the floating window, all commands and mappings are available as usual,
--- except that "q" dismisses the window.
--- You can scroll the contents the same as you would any other buffer.
+---
+--- Note: to disable hover highlights, add the following to your config:
+---
+--- ```lua
+--- vim.api.nvim_create_autocmd('ColorScheme', {
+--- callback = function()
+--- vim.api.nvim_set_hl(0, 'LspReferenceTarget', {})
+--- end,
+--- })
+--- ```
--- @param config? vim.lsp.buf.hover.Opts
function M.hover(config)
config = config or {}
config.focus_id = ms.textDocument_hover
lsp.buf_request_all(0, ms.textDocument_hover, client_positional_params(), function(results, ctx)
- if api.nvim_get_current_buf() ~= ctx.bufnr then
+ local bufnr = assert(ctx.bufnr)
+ if api.nvim_get_current_buf() ~= bufnr then
-- Ignore result since buffer changed. This happens for slow language servers.
return
end
@@ -67,9 +80,10 @@ function M.hover(config)
local format = 'markdown'
for client_id, result in pairs(results1) do
+ local client = assert(lsp.get_client_by_id(client_id))
if nresults > 1 then
-- Show client name if there are multiple clients
- contents[#contents + 1] = string.format('# %s', lsp.get_client_by_id(client_id).name)
+ contents[#contents + 1] = string.format('# %s', client.name)
end
if type(result.contents) == 'table' and result.contents.kind == 'plaintext' then
if #results1 == 1 then
@@ -87,6 +101,22 @@ function M.hover(config)
else
vim.list_extend(contents, util.convert_input_to_markdown_lines(result.contents))
end
+ local range = result.range
+ if range then
+ local start = range.start
+ local end_ = range['end']
+ local start_idx = util._get_line_byte_from_position(bufnr, start, client.offset_encoding)
+ local end_idx = util._get_line_byte_from_position(bufnr, end_, client.offset_encoding)
+
+ vim.hl.range(
+ bufnr,
+ hover_ns,
+ 'LspReferenceTarget',
+ { start.line, start_idx },
+ { end_.line, end_idx },
+ { priority = vim.hl.priorities.user }
+ )
+ end
contents[#contents + 1] = '---'
end
@@ -100,7 +130,16 @@ function M.hover(config)
return
end
- lsp.util.open_floating_preview(contents, format, config)
+ local _, winid = lsp.util.open_floating_preview(contents, format, config)
+
+ api.nvim_create_autocmd('WinClosed', {
+ pattern = tostring(winid),
+ once = true,
+ callback = function()
+ api.nvim_buf_clear_namespace(bufnr, hover_ns, 0, -1)
+ return true
+ end,
+ })
end)
end
@@ -193,7 +232,7 @@ local function get_locations(method, opts)
end
for _, client in ipairs(clients) do
local params = util.make_position_params(win, client.offset_encoding)
- client.request(method, params, function(_, result)
+ client:request(method, params, function(_, result)
on_response(_, result, client)
end)
end
@@ -529,12 +568,14 @@ function M.format(opts)
end
if opts.async then
+ --- @param idx integer
+ --- @param client vim.lsp.Client
local function do_format(idx, client)
if not client then
return
end
local params = set_range(client, util.make_formatting_params(opts.formatting_options))
- client.request(method, params, function(...)
+ client:request(method, params, function(...)
local handler = client.handlers[method] or lsp.handlers[method]
handler(...)
do_format(next(clients, idx))
@@ -545,7 +586,7 @@ function M.format(opts)
local timeout_ms = opts.timeout_ms or 1000
for _, client in pairs(clients) do
local params = set_range(client, util.make_formatting_params(opts.formatting_options))
- local result, err = client.request_sync(method, params, timeout_ms, bufnr)
+ local result, err = client:request_sync(method, params, timeout_ms, bufnr)
if result and result.result then
util.apply_text_edits(result.result, bufnr, client.offset_encoding)
elseif err then
@@ -609,6 +650,8 @@ function M.rename(new_name, opts)
)[1]
end
+ --- @param idx integer
+ --- @param client? vim.lsp.Client
local function try_use_client(idx, client)
if not client then
return
@@ -620,15 +663,15 @@ function M.rename(new_name, opts)
params.newName = name
local handler = client.handlers[ms.textDocument_rename]
or lsp.handlers[ms.textDocument_rename]
- client.request(ms.textDocument_rename, params, function(...)
+ client:request(ms.textDocument_rename, params, function(...)
handler(...)
try_use_client(next(clients, idx))
end, bufnr)
end
- if client.supports_method(ms.textDocument_prepareRename) then
+ if client:supports_method(ms.textDocument_prepareRename) then
local params = util.make_position_params(win, client.offset_encoding)
- client.request(ms.textDocument_prepareRename, params, function(err, result)
+ client:request(ms.textDocument_prepareRename, params, function(err, result)
if err or result == nil then
if next(clients, idx) then
try_use_client(next(clients, idx))
@@ -667,7 +710,7 @@ function M.rename(new_name, opts)
end, bufnr)
else
assert(
- client.supports_method(ms.textDocument_rename),
+ client:supports_method(ms.textDocument_rename),
'Client must support textDocument/rename'
)
if new_name then
@@ -742,7 +785,7 @@ function M.references(context, opts)
params.context = context or {
includeDeclaration = true,
}
- client.request(ms.textDocument_references, params, function(_, result)
+ client:request(ms.textDocument_references, params, function(_, result)
local items = util.locations_to_items(result or {}, client.offset_encoding)
vim.list_extend(all_items, items)
remaining = remaining - 1
@@ -774,7 +817,7 @@ local function request_with_id(client_id, method, params, handler, bufnr)
)
return
end
- client.request(method, params, handler, bufnr)
+ client:request(method, params, handler, bufnr)
end
--- @param item lsp.TypeHierarchyItem|lsp.CallHierarchyItem
@@ -841,7 +884,7 @@ local function hierarchy(method)
for _, client in ipairs(clients) do
local params = util.make_position_params(win, client.offset_encoding)
--- @param result lsp.CallHierarchyItem[]|lsp.TypeHierarchyItem[]?
- client.request(prepare_method, params, function(err, result, ctx)
+ client:request(prepare_method, params, function(err, result, ctx)
if err then
vim.notify(err.message, vim.log.levels.WARN)
elseif result then
@@ -1092,13 +1135,8 @@ local function on_code_action_results(results, opts)
local action = choice.action
local bufnr = assert(choice.ctx.bufnr, 'Must have buffer number')
- local reg = client.dynamic_capabilities:get(ms.textDocument_codeAction, { bufnr = bufnr })
-
- local supports_resolve = vim.tbl_get(reg or {}, 'registerOptions', 'resolveProvider')
- or client.supports_method(ms.codeAction_resolve)
-
- if not action.edit and client and supports_resolve then
- client.request(ms.codeAction_resolve, action, function(err, resolved_action)
+ if not action.edit and client:supports_method(ms.codeAction_resolve) then
+ client:request(ms.codeAction_resolve, action, function(err, resolved_action)
if err then
if action.command then
apply_action(action, client, choice.ctx)
@@ -1219,7 +1257,7 @@ function M.code_action(opts)
})
end
- client.request(ms.textDocument_codeAction, params, on_result, bufnr)
+ client:request(ms.textDocument_codeAction, params, on_result, bufnr)
end
end
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index 2718f40c96..3b79da99ea 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -91,7 +91,7 @@ local validate = vim.validate
--- (default: client-id)
--- @field name? string
---
---- Language ID as string. Defaults to the filetype.
+--- Language ID as string. Defaults to the buffer filetype.
--- @field get_language_id? fun(bufnr: integer, filetype: string): string
---
--- The encoding that the LSP server expects. Client does not verify this is correct.
@@ -216,72 +216,31 @@ local validate = vim.validate
---
--- The capabilities provided by the client (editor or tool)
--- @field capabilities lsp.ClientCapabilities
+--- @field private registrations table<string,lsp.Registration[]>
--- @field dynamic_capabilities lsp.DynamicCapabilities
---
---- Sends a request to the server.
---- This is a thin wrapper around {client.rpc.request} with some additional
---- checking.
---- If {handler} is not specified and if there's no respective global
---- handler, then an error will occur.
---- Returns: {status}, {client_id}?. {status} is a boolean indicating if
---- the notification was successful. If it is `false`, then it will always
---- be `false` (the client has shutdown).
---- If {status} is `true`, the function returns {request_id} as the second
---- result. You can use this with `client.cancel_request(request_id)` to cancel
---- the request.
---- @field request fun(method: string, params: table?, handler: lsp.Handler?, bufnr: integer?): boolean, integer?
----
---- Sends a request to the server and synchronously waits for the response.
---- This is a wrapper around {client.request}
---- Returns: { err=err, result=result }, a dict, where `err` and `result`
---- come from the |lsp-handler|. On timeout, cancel or error, returns `(nil,
---- err)` where `err` is a string describing the failure reason. If the request
---- was unsuccessful returns `nil`.
---- @field request_sync fun(method: string, params: table?, timeout_ms: integer?, bufnr: integer): {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dict
----
---- Sends a notification to an LSP server.
---- Returns: a boolean to indicate if the notification was successful. If
---- it is false, then it will always be false (the client has shutdown).
---- @field notify fun(method: string, params: table?): boolean
----
---- Cancels a request with a given request id.
---- Returns: same as `notify()`.
---- @field cancel_request fun(id: integer): boolean
----
---- Stops a client, optionally with force.
---- By default, it will just ask the server to shutdown without force.
---- If you request to stop a client which has previously been requested to
---- shutdown, it will automatically escalate and force shutdown.
---- @field stop fun(force?: boolean)
----
---- Runs the on_attach function from the client's config if it was defined.
---- Useful for buffer-local setup.
---- @field on_attach fun(bufnr: integer)
----
--- @field private _before_init_cb? vim.lsp.client.before_init_cb
--- @field private _on_attach_cbs vim.lsp.client.on_attach_cb[]
--- @field private _on_init_cbs vim.lsp.client.on_init_cb[]
--- @field private _on_exit_cbs vim.lsp.client.on_exit_cb[]
--- @field private _on_error_cb? fun(code: integer, err: string)
----
---- Checks if a client supports a given method.
---- Always returns true for unknown off-spec methods.
---- {opts} is a optional `{bufnr?: integer}` table.
---- Some language server capabilities can be file specific.
---- @field supports_method fun(method: string, opts?: {bufnr: integer?}): boolean
----
---- Checks whether a client is stopped.
---- Returns: true if the client is fully stopped.
---- @field is_stopped fun(): boolean
local Client = {}
Client.__index = Client
---- @param cls table
---- @param meth any
---- @return function
-local function method_wrapper(cls, meth)
- return function(...)
- return meth(cls, ...)
+--- @param obj table<string,any>
+--- @param cls table<string,function>
+--- @param name string
+local function method_wrapper(obj, cls, name)
+ local meth = assert(cls[name])
+ obj[name] = function(...)
+ local arg = select(1, ...)
+ if arg and getmetatable(arg) == cls then
+ -- First argument is self, call meth directly
+ return meth(...)
+ end
+ vim.deprecate('client.' .. name, 'client:' .. name, '0.13')
+ -- First argument is not self, insert it
+ return meth(obj, ...)
end
end
@@ -403,18 +362,16 @@ local function get_name(id, config)
return tostring(id)
end
---- @param workspace_folders lsp.WorkspaceFolder[]?
---- @param root_dir string?
+--- @param workspace_folders string|lsp.WorkspaceFolder[]?
--- @return lsp.WorkspaceFolder[]?
-local function get_workspace_folders(workspace_folders, root_dir)
- if workspace_folders then
+local function get_workspace_folders(workspace_folders)
+ if type(workspace_folders) == 'table' then
return workspace_folders
- end
- if root_dir then
+ elseif type(workspace_folders) == 'string' then
return {
{
- uri = vim.uri_from_fname(root_dir),
- name = root_dir,
+ uri = vim.uri_from_fname(workspace_folders),
+ name = workspace_folders,
},
}
end
@@ -451,13 +408,13 @@ function Client.create(config)
requests = {},
attached_buffers = {},
server_capabilities = {},
- dynamic_capabilities = lsp._dynamic.new(id),
+ registrations = {},
commands = config.commands or {},
settings = config.settings or {},
flags = config.flags or {},
get_language_id = config.get_language_id or default_get_language_id,
capabilities = config.capabilities or lsp.protocol.make_client_capabilities(),
- workspace_folders = get_workspace_folders(config.workspace_folders, config.root_dir),
+ workspace_folders = get_workspace_folders(config.workspace_folders or config.root_dir),
root_dir = config.root_dir,
_before_init_cb = config.before_init,
_on_init_cbs = ensure_list(config.on_init),
@@ -478,24 +435,45 @@ function Client.create(config)
messages = { name = name, messages = {}, progress = {}, status = {} },
}
- self.request = method_wrapper(self, Client._request)
- self.request_sync = method_wrapper(self, Client._request_sync)
- self.notify = method_wrapper(self, Client._notify)
- self.cancel_request = method_wrapper(self, Client._cancel_request)
- self.stop = method_wrapper(self, Client._stop)
- self.is_stopped = method_wrapper(self, Client._is_stopped)
- self.on_attach = method_wrapper(self, Client._on_attach)
- self.supports_method = method_wrapper(self, Client._supports_method)
+ --- @class lsp.DynamicCapabilities
+ --- @nodoc
+ self.dynamic_capabilities = {
+ capabilities = self.registrations,
+ client_id = id,
+ register = function(_, registrations)
+ return self:_register_dynamic(registrations)
+ end,
+ unregister = function(_, unregistrations)
+ return self:_unregister_dynamic(unregistrations)
+ end,
+ get = function(_, method, opts)
+ return self:_get_registration(method, opts and opts.bufnr)
+ end,
+ supports_registration = function(_, method)
+ return self:_supports_registration(method)
+ end,
+ supports = function(_, method, opts)
+ return self:_get_registration(method, opts and opts.bufnr) ~= nil
+ end,
+ }
--- @type table<string|integer, string> title of unfinished progress sequences by token
self.progress.pending = {}
--- @type vim.lsp.rpc.Dispatchers
local dispatchers = {
- notification = method_wrapper(self, Client._notification),
- server_request = method_wrapper(self, Client._server_request),
- on_error = method_wrapper(self, Client._on_error),
- on_exit = method_wrapper(self, Client._on_exit),
+ notification = function(...)
+ return self:_notification(...)
+ end,
+ server_request = function(...)
+ return self:_server_request(...)
+ end,
+ on_error = function(...)
+ return self:_on_error(...)
+ end,
+ on_exit = function(...)
+ return self:_on_exit(...)
+ end,
}
-- Start the RPC client.
@@ -512,6 +490,15 @@ function Client.create(config)
setmetatable(self, Client)
+ method_wrapper(self, Client, 'request')
+ method_wrapper(self, Client, 'request_sync')
+ method_wrapper(self, Client, 'notify')
+ method_wrapper(self, Client, 'cancel_request')
+ method_wrapper(self, Client, 'stop')
+ method_wrapper(self, Client, 'is_stopped')
+ method_wrapper(self, Client, 'on_attach')
+ method_wrapper(self, Client, 'supports_method')
+
return self
end
@@ -595,7 +582,7 @@ function Client:initialize()
end
if next(self.settings) then
- self:_notify(ms.workspace_didChangeConfiguration, { settings = self.settings })
+ self:notify(ms.workspace_didChangeConfiguration, { settings = self.settings })
end
-- If server is being restarted, make sure to re-attach to any previously attached buffers.
@@ -607,7 +594,7 @@ function Client:initialize()
for buf in pairs(reattach_bufs) do
-- The buffer may have been detached in the on_init callback.
if self.attached_buffers[buf] then
- self:_on_attach(buf)
+ self:on_attach(buf)
end
end
@@ -624,14 +611,14 @@ end
--- Returns the default handler if the user hasn't set a custom one.
---
--- @param method (string) LSP method name
---- @return lsp.Handler|nil handler for the given method, if defined, or the default from |vim.lsp.handlers|
+--- @return lsp.Handler? handler for the given method, if defined, or the default from |vim.lsp.handlers|
function Client:_resolve_handler(method)
return self.handlers[method] or lsp.handlers[method]
end
--- Returns the buffer number for the given {bufnr}.
---
---- @param bufnr (integer|nil) Buffer number to resolve. Defaults to current buffer
+--- @param bufnr integer? Buffer number to resolve. Defaults to current buffer
--- @return integer bufnr
local function resolve_bufnr(bufnr)
validate('bufnr', bufnr, 'number', true)
@@ -641,7 +628,6 @@ local function resolve_bufnr(bufnr)
return bufnr
end
---- @private
--- Sends a request to the server.
---
--- This is a thin wrapper around {client.rpc.request} with some additional
@@ -650,15 +636,14 @@ end
--- @param method string LSP method name.
--- @param params? table LSP request params.
--- @param handler? lsp.Handler Response |lsp-handler| for this method.
---- @param bufnr integer Buffer handle (0 for current).
---- @return boolean status, integer? request_id {status} is a bool indicating
---- whether the request was successful. If it is `false`, then it will
---- always be `false` (the client has shutdown). If it was
---- successful, then it will return {request_id} as the
---- second result. You can use this with `client.cancel_request(request_id)`
+--- @param bufnr? integer Buffer handle. 0 for current (default).
+--- @return boolean status indicates whether the request was successful.
+--- If it is `false`, then it will always be `false` (the client has shutdown).
+--- @return integer? request_id Can be used with |Client:cancel_request()|.
+--- `nil` is request failed.
--- to cancel the-request.
--- @see |vim.lsp.buf_request_all()|
-function Client:_request(method, params, handler, bufnr)
+function Client:request(method, params, handler, bufnr)
if not handler then
handler = assert(
self:_resolve_handler(method),
@@ -667,8 +652,8 @@ function Client:_request(method, params, handler, bufnr)
end
-- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state
changetracking.flush(self, bufnr)
- local version = lsp.util.buf_versions[bufnr]
bufnr = resolve_bufnr(bufnr)
+ local version = lsp.util.buf_versions[bufnr]
log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr)
local success, request_id = self.rpc.request(method, params, function(err, result)
local context = {
@@ -722,29 +707,27 @@ local function err_message(...)
end
end
---- @private
--- Sends a request to the server and synchronously waits for the response.
---
---- This is a wrapper around {client.request}
+--- This is a wrapper around |Client:request()|
---
---- @param method (string) LSP method name.
---- @param params (table) LSP request params.
---- @param timeout_ms (integer|nil) Maximum time in milliseconds to wait for
+--- @param method string LSP method name.
+--- @param params table LSP request params.
+--- @param timeout_ms integer? Maximum time in milliseconds to wait for
--- a result. Defaults to 1000
---- @param bufnr (integer) Buffer handle (0 for current).
---- @return {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dict, where
---- `err` and `result` come from the |lsp-handler|.
---- On timeout, cancel or error, returns `(nil, err)` where `err` is a
---- string describing the failure reason. If the request was unsuccessful
---- returns `nil`.
+--- @param bufnr integer Buffer handle (0 for current).
+--- @return {err: lsp.ResponseError?, result:any}? `result` and `err` from the |lsp-handler|.
+--- `nil` is the request was unsuccessful
+--- @return string? err On timeout, cancel or error, where `err` is a
+--- string describing the failure reason.
--- @see |vim.lsp.buf_request_sync()|
-function Client:_request_sync(method, params, timeout_ms, bufnr)
+function Client:request_sync(method, params, timeout_ms, bufnr)
local request_result = nil
local function _sync_handler(err, result)
request_result = { err = err, result = result }
end
- local success, request_id = self:_request(method, params, _sync_handler, bufnr)
+ local success, request_id = self:request(method, params, _sync_handler, bufnr)
if not success then
return nil
end
@@ -755,22 +738,20 @@ function Client:_request_sync(method, params, timeout_ms, bufnr)
if not wait_result then
if request_id then
- self:_cancel_request(request_id)
+ self:cancel_request(request_id)
end
return nil, wait_result_reason[reason]
end
return request_result
end
---- @package
--- Sends a notification to an LSP server.
---
--- @param method string LSP method name.
---- @param params table|nil LSP request params.
---- @return boolean status true if the notification was successful.
---- If it is false, then it will always be false
---- (the client has shutdown).
-function Client:_notify(method, params)
+--- @param params table? LSP request params.
+--- @return boolean status indicating if the notification was successful.
+--- If it is false, then the client has shutdown.
+function Client:notify(method, params)
if method ~= ms.textDocument_didChange then
changetracking.flush(self)
end
@@ -793,13 +774,12 @@ function Client:_notify(method, params)
return client_active
end
---- @private
--- Cancels a request with a given request id.
---
---- @param id (integer) id of request to cancel
---- @return boolean status true if notification was successful. false otherwise
---- @see |vim.lsp.client.notify()|
-function Client:_cancel_request(id)
+--- @param id integer id of request to cancel
+--- @return boolean status indicating if the notification was successful.
+--- @see |Client:notify()|
+function Client:cancel_request(id)
validate('id', id, 'number')
local request = self.requests[id]
if request and request.type == 'pending' then
@@ -813,15 +793,14 @@ function Client:_cancel_request(id)
return self.rpc.notify(ms.dollar_cancelRequest, { id = id })
end
---- @private
--- Stops a client, optionally with force.
---
---- By default, it will just ask the - server to shutdown without force. If
+--- By default, it will just request the server to shutdown without force. If
--- you request to stop a client which has previously been requested to
--- shutdown, it will automatically escalate and force shutdown.
---
---- @param force boolean|nil
-function Client:_stop(force)
+--- @param force? boolean
+function Client:stop(force)
local rpc = self.rpc
if rpc.is_closing() then
@@ -846,12 +825,110 @@ function Client:_stop(force)
end)
end
+--- Get options for a method that is registered dynamically.
+--- @param method string
+function Client:_supports_registration(method)
+ local capability = vim.tbl_get(self.capabilities, unpack(vim.split(method, '/')))
+ return type(capability) == 'table' and capability.dynamicRegistration
+end
+
+--- @private
+--- @param registrations lsp.Registration[]
+function Client:_register_dynamic(registrations)
+ -- remove duplicates
+ self:_unregister_dynamic(registrations)
+ for _, reg in ipairs(registrations) do
+ local method = reg.method
+ if not self.registrations[method] then
+ self.registrations[method] = {}
+ end
+ table.insert(self.registrations[method], reg)
+ end
+end
+
+--- @param registrations lsp.Registration[]
+function Client:_register(registrations)
+ self:_register_dynamic(registrations)
+
+ local unsupported = {} --- @type string[]
+
+ for _, reg in ipairs(registrations) do
+ local method = reg.method
+ if method == ms.workspace_didChangeWatchedFiles then
+ vim.lsp._watchfiles.register(reg, self.id)
+ elseif not self:_supports_registration(method) then
+ unsupported[#unsupported + 1] = method
+ end
+ end
+
+ if #unsupported > 0 then
+ local warning_tpl = 'The language server %s triggers a registerCapability '
+ .. 'handler for %s despite dynamicRegistration set to false. '
+ .. 'Report upstream, this warning is harmless'
+ log.warn(string.format(warning_tpl, self.name, table.concat(unsupported, ', ')))
+ end
+end
+
+--- @private
+--- @param unregistrations lsp.Unregistration[]
+function Client:_unregister_dynamic(unregistrations)
+ for _, unreg in ipairs(unregistrations) do
+ local sreg = self.registrations[unreg.method]
+ -- Unegister dynamic capability
+ for i, reg in ipairs(sreg or {}) do
+ if reg.id == unreg.id then
+ table.remove(sreg, i)
+ break
+ end
+ end
+ end
+end
+
+--- @param unregistrations lsp.Unregistration[]
+function Client:_unregister(unregistrations)
+ self:_unregister_dynamic(unregistrations)
+ for _, unreg in ipairs(unregistrations) do
+ if unreg.method == ms.workspace_didChangeWatchedFiles then
+ vim.lsp._watchfiles.unregister(unreg, self.id)
+ end
+ end
+end
+
--- @private
+function Client:_get_language_id(bufnr)
+ return self.get_language_id(bufnr, vim.bo[bufnr].filetype)
+end
+
+--- @param method string
+--- @param bufnr? integer
+--- @return lsp.Registration?
+function Client:_get_registration(method, bufnr)
+ bufnr = bufnr or vim.api.nvim_get_current_buf()
+ for _, reg in ipairs(self.registrations[method] or {}) do
+ if not reg.registerOptions or not reg.registerOptions.documentSelector then
+ return reg
+ end
+ local documentSelector = reg.registerOptions.documentSelector
+ local language = self:_get_language_id(bufnr)
+ local uri = vim.uri_from_bufnr(bufnr)
+ local fname = vim.uri_to_fname(uri)
+ for _, filter in ipairs(documentSelector) do
+ if
+ not (filter.language and language ~= filter.language)
+ and not (filter.scheme and not vim.startswith(uri, filter.scheme .. ':'))
+ and not (filter.pattern and not vim.glob.to_lpeg(filter.pattern):match(fname))
+ then
+ return reg
+ end
+ end
+ end
+end
+
--- Checks whether a client is stopped.
---
--- @return boolean # true if client is stopped or in the process of being
--- stopped; false otherwise
-function Client:_is_stopped()
+function Client:is_stopped()
return self.rpc.is_closing()
end
@@ -893,7 +970,7 @@ function Client:exec_cmd(command, context, handler)
command = cmdname,
arguments = command.arguments,
}
- self.request(ms.workspace_executeCommand, params, handler, context.bufnr)
+ self:request(ms.workspace_executeCommand, params, handler, context.bufnr)
end
--- Default handler for the 'textDocument/didOpen' LSP notification.
@@ -901,19 +978,18 @@ end
--- @param bufnr integer Number of the buffer, or 0 for current
function Client:_text_document_did_open_handler(bufnr)
changetracking.init(self, bufnr)
- if not self.supports_method(ms.textDocument_didOpen) then
+ if not self:supports_method(ms.textDocument_didOpen) then
return
end
if not api.nvim_buf_is_loaded(bufnr) then
return
end
- local filetype = vim.bo[bufnr].filetype
- self.notify(ms.textDocument_didOpen, {
+ self:notify(ms.textDocument_didOpen, {
textDocument = {
version = lsp.util.buf_versions[bufnr],
uri = vim.uri_from_bufnr(bufnr),
- languageId = self.get_language_id(bufnr, filetype),
+ languageId = self:_get_language_id(bufnr),
text = lsp._buf_get_full_text(bufnr),
},
})
@@ -930,8 +1006,9 @@ function Client:_text_document_did_open_handler(bufnr)
end
--- Runs the on_attach function from the client's config if it was defined.
+--- Useful for buffer-local setup.
--- @param bufnr integer Buffer number
-function Client:_on_attach(bufnr)
+function Client:on_attach(bufnr)
self:_text_document_did_open_handler(bufnr)
lsp._set_defaults(self, bufnr)
@@ -966,10 +1043,18 @@ function Client:write_error(code, err)
err_message(self._log_prefix, ': Error ', client_error, ': ', vim.inspect(err))
end
---- @private
+--- Checks if a client supports a given method.
+--- Always returns true for unknown off-spec methods.
+---
+--- Note: Some language server capabilities can be file specific.
--- @param method string
---- @param opts? {bufnr: integer?}
-function Client:_supports_method(method, opts)
+--- @param bufnr? integer
+function Client:supports_method(method, bufnr)
+ -- Deprecated form
+ if type(bufnr) == 'table' then
+ --- @diagnostic disable-next-line:no-unknown
+ bufnr = bufnr.bufnr
+ end
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
@@ -978,12 +1063,37 @@ function Client:_supports_method(method, opts)
if vim.tbl_get(self.server_capabilities, unpack(required_capability)) then
return true
end
- if self.dynamic_capabilities:supports_registration(method) then
- return self.dynamic_capabilities:supports(method, opts)
+
+ local rmethod = lsp._resolve_to_request[method]
+ if rmethod then
+ if self:_supports_registration(rmethod) then
+ local reg = self:_get_registration(rmethod, bufnr)
+ return vim.tbl_get(reg or {}, 'registerOptions', 'resolveProvider') or false
+ end
+ else
+ if self:_supports_registration(method) then
+ return self:_get_registration(method, bufnr) ~= nil
+ end
end
return false
end
+--- Get options for a method that is registered dynamically.
+--- @param method string
+--- @param bufnr? integer
+--- @return lsp.LSPAny?
+function Client:_get_registration_options(method, bufnr)
+ if not self:_supports_registration(method) then
+ return
+ end
+
+ local reg = self:_get_registration(method, bufnr)
+
+ if reg then
+ return reg.registerOptions
+ end
+end
+
--- @private
--- Handles a notification sent by an LSP server by invoking the
--- corresponding handler.
@@ -1061,9 +1171,9 @@ function Client:_add_workspace_folder(dir)
end
end
- local wf = assert(get_workspace_folders(nil, dir))
+ local wf = assert(get_workspace_folders(dir))
- self:_notify(ms.workspace_didChangeWorkspaceFolders, {
+ self:notify(ms.workspace_didChangeWorkspaceFolders, {
event = { added = wf, removed = {} },
})
@@ -1076,9 +1186,9 @@ end
--- Remove a directory to the workspace folders.
--- @param dir string?
function Client:_remove_workspace_folder(dir)
- local wf = assert(get_workspace_folders(nil, dir))
+ local wf = assert(get_workspace_folders(dir))
- self:_notify(ms.workspace_didChangeWorkspaceFolders, {
+ self:notify(ms.workspace_didChangeWorkspaceFolders, {
event = { added = {}, removed = wf },
})
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index fdbdda695a..a11f84d6c6 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -231,7 +231,7 @@ local function resolve_lenses(lenses, bufnr, client_id, callback)
countdown()
else
assert(client)
- client.request(ms.codeLens_resolve, lens, function(_, result)
+ client:request(ms.codeLens_resolve, lens, function(_, result)
if api.nvim_buf_is_loaded(bufnr) and result and result.command then
lens.command = result.command
-- Eager display to have some sort of incremental feedback
diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
index 92bc110a97..0f388a88fd 100644
--- a/runtime/lua/vim/lsp/completion.lua
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -404,7 +404,7 @@ local function request(clients, bufnr, win, callback)
for _, client in pairs(clients) do
local client_id = client.id
local params = lsp.util.make_position_params(win, client.offset_encoding)
- local ok, request_id = client.request(ms.textDocument_completion, params, function(err, result)
+ local ok, request_id = client:request(ms.textDocument_completion, params, function(err, result)
responses[client_id] = { err = err, result = result }
remaining_requests = remaining_requests - 1
if remaining_requests == 0 then
@@ -421,7 +421,7 @@ local function request(clients, bufnr, win, callback)
for client_id, request_id in pairs(request_ids) do
local client = lsp.get_client_by_id(client_id)
if client then
- client.cancel_request(request_id)
+ client:cancel_request(request_id)
end
end
end
@@ -582,7 +582,7 @@ local function on_complete_done()
local changedtick = vim.b[bufnr].changedtick
--- @param result lsp.CompletionItem
- client.request(ms.completionItem_resolve, completion_item, function(err, result)
+ client:request(ms.completionItem_resolve, completion_item, function(err, result)
if changedtick ~= vim.b[bufnr].changedtick then
return
end
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 2b7aefe0e1..5c28d88b38 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -122,46 +122,19 @@ end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability
--- @param params lsp.RegistrationParams
RSC[ms.client_registerCapability] = function(_, params, ctx)
- local client_id = ctx.client_id
- local client = assert(vim.lsp.get_client_by_id(client_id))
-
- client.dynamic_capabilities:register(params.registrations)
- for bufnr, _ in pairs(client.attached_buffers) do
+ local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
+ client:_register(params.registrations)
+ for bufnr in pairs(client.attached_buffers) do
vim.lsp._set_defaults(client, bufnr)
end
-
- ---@type string[]
- local unsupported = {}
- for _, reg in ipairs(params.registrations) do
- if reg.method == ms.workspace_didChangeWatchedFiles then
- vim.lsp._watchfiles.register(reg, ctx)
- elseif not client.dynamic_capabilities:supports_registration(reg.method) then
- unsupported[#unsupported + 1] = reg.method
- end
- end
- if #unsupported > 0 then
- local warning_tpl = 'The language server %s triggers a registerCapability '
- .. 'handler for %s despite dynamicRegistration set to false. '
- .. 'Report upstream, this warning is harmless'
- local client_name = client and client.name or string.format('id=%d', client_id)
- local warning = string.format(warning_tpl, client_name, table.concat(unsupported, ', '))
- log.warn(warning)
- end
return vim.NIL
end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_unregisterCapability
--- @param params lsp.UnregistrationParams
RSC[ms.client_unregisterCapability] = function(_, params, ctx)
- local client_id = ctx.client_id
- local client = assert(vim.lsp.get_client_by_id(client_id))
- client.dynamic_capabilities:unregister(params.unregisterations)
-
- for _, unreg in ipairs(params.unregisterations) do
- if unreg.method == ms.workspace_didChangeWatchedFiles then
- vim.lsp._watchfiles.unregister(unreg, ctx)
- end
- end
+ local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
+ client:_unregister(params.unregisterations)
return vim.NIL
end
@@ -173,8 +146,7 @@ RSC[ms.workspace_applyEdit] = function(_, params, ctx)
'workspace/applyEdit must be called with `ApplyWorkspaceEditParams`. Server is violating the specification'
)
-- TODO(ashkan) Do something more with label?
- local client_id = ctx.client_id
- local client = assert(vim.lsp.get_client_by_id(client_id))
+ local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
if params.label then
print('Workspace edit', params.label)
end
@@ -196,12 +168,11 @@ end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration
--- @param params lsp.ConfigurationParams
RSC[ms.workspace_configuration] = function(_, params, ctx)
- local client_id = ctx.client_id
- local client = vim.lsp.get_client_by_id(client_id)
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
if not client then
err_message(
'LSP[',
- client_id,
+ ctx.client_id,
'] client has shut down after sending a workspace/configuration request'
)
return
@@ -229,10 +200,9 @@ end
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_workspaceFolders
RSC[ms.workspace_workspaceFolders] = function(_, _, ctx)
- local client_id = ctx.client_id
- local client = vim.lsp.get_client_by_id(client_id)
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
if not client then
- err_message('LSP[id=', client_id, '] client has shut down after sending the message')
+ err_message('LSP[id=', ctx.client_id, '] client has shut down after sending the message')
return
end
return client.workspace_folders or vim.NIL
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua
index ca7bc3b022..f1a58de621 100644
--- a/runtime/lua/vim/lsp/inlay_hint.lua
+++ b/runtime/lua/vim/lsp/inlay_hint.lua
@@ -65,7 +65,7 @@ function M.on_inlayhint(err, result, ctx)
if num_unprocessed == 0 then
client_hints[client_id] = {}
bufstate.version = ctx.version
- api.nvim__redraw({ buf = bufnr, valid = true })
+ api.nvim__redraw({ buf = bufnr, valid = true, flush = false })
return
end
@@ -81,7 +81,7 @@ function M.on_inlayhint(err, result, ctx)
client_hints[client_id] = new_lnum_hints
bufstate.version = ctx.version
- api.nvim__redraw({ buf = bufnr, valid = true })
+ api.nvim__redraw({ buf = bufnr, valid = true, flush = false })
end
--- |lsp-handler| for the method `workspace/inlayHint/refresh`
@@ -122,12 +122,12 @@ end
--- local hint = vim.lsp.inlay_hint.get({ bufnr = 0 })[1] -- 0 for current buffer
---
--- local client = vim.lsp.get_client_by_id(hint.client_id)
---- local resp = client.request_sync('inlayHint/resolve', hint.inlay_hint, 100, 0)
+--- local resp = client:request_sync('inlayHint/resolve', hint.inlay_hint, 100, 0)
--- local resolved_hint = assert(resp and resp.result, resp.err)
--- vim.lsp.util.apply_text_edits(resolved_hint.textEdits, 0, client.encoding)
---
--- location = resolved_hint.label[1].location
---- client.request('textDocument/hover', {
+--- client:request('textDocument/hover', {
--- textDocument = { uri = location.uri },
--- position = location.range.start,
--- })
@@ -215,7 +215,7 @@ local function clear(bufnr)
end
end
api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
- api.nvim__redraw({ buf = bufnr, valid = true })
+ api.nvim__redraw({ buf = bufnr, valid = true, flush = false })
end
--- Disable inlay hints for a buffer
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 4f177b47fd..ec78dd3dc5 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -32,12 +32,12 @@ local function notify(msg, level)
end
end
-local logfilename = vim.fs.joinpath(vim.fn.stdpath('log'), 'lsp.log')
+local logfilename = vim.fs.joinpath(vim.fn.stdpath('log') --[[@as string]], 'lsp.log')
-- TODO: Ideally the directory should be created in open_logfile(), right
-- before opening the log file, but open_logfile() can be called from libuv
-- callbacks, where using fn.mkdir() is not allowed.
-vim.fn.mkdir(vim.fn.stdpath('log'), 'p')
+vim.fn.mkdir(vim.fn.stdpath('log') --[[@as string]], 'p')
--- Returns the log filename.
---@return string log filename
@@ -82,6 +82,7 @@ end
for level, levelnr in pairs(log_levels) do
-- Also export the log level on the root object.
+ ---@diagnostic disable-next-line: no-unknown
log[level] = levelnr
-- Add a reverse lookup.
@@ -93,7 +94,7 @@ end
--- @return fun(...:any): boolean?
local function create_logger(level, levelnr)
return function(...)
- if levelnr < current_log_level then
+ if not log.should_log(levelnr) then
return false
end
local argc = select('#', ...)
@@ -169,7 +170,7 @@ end
--- Checks whether the level is sufficient for logging.
---@param level integer log level
----@return bool : true if would log, false if not
+---@return boolean : true if would log, false if not
function log.should_log(level)
return level >= current_log_level
end
diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua
index 215e5f41aa..01421fea29 100644
--- a/runtime/lua/vim/lsp/semantic_tokens.lua
+++ b/runtime/lua/vim/lsp/semantic_tokens.lua
@@ -273,7 +273,7 @@ function STHighlighter:send_request()
if client and current_result.version ~= version and active_request.version ~= version then
-- cancel stale in-flight request
if active_request.request_id then
- client.cancel_request(active_request.request_id)
+ client:cancel_request(active_request.request_id)
active_request = {}
state.active_request = active_request
end
@@ -288,7 +288,7 @@ function STHighlighter:send_request()
method = method .. '/delta'
params.previousResultId = current_result.result_id
end
- local success, request_id = client.request(method, params, function(err, response, ctx)
+ local success, request_id = client:request(method, params, function(err, response, ctx)
-- look client up again using ctx.client_id instead of using a captured
-- client object
local c = vim.lsp.get_client_by_id(ctx.client_id)
@@ -519,7 +519,7 @@ function STHighlighter:reset()
if state.active_request.request_id then
local client = vim.lsp.get_client_by_id(client_id)
assert(client)
- client.cancel_request(state.active_request.request_id)
+ client:cancel_request(state.active_request.request_id)
state.active_request = {}
end
end
@@ -547,7 +547,7 @@ function STHighlighter:mark_dirty(client_id)
if state.active_request.request_id then
local client = vim.lsp.get_client_by_id(client_id)
assert(client)
- client.cancel_request(state.active_request.request_id)
+ client:cancel_request(state.active_request.request_id)
state.active_request = {}
end
end
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 6eab0f3da4..cfa8a194d9 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1848,12 +1848,11 @@ function M.try_trim_markdown_code_blocks(lines)
end
---@param window integer?: window handle or 0 for current, defaults to current
----@param offset_encoding? 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of buffer of `window`
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
local function make_position_param(window, offset_encoding)
window = window or 0
local buf = api.nvim_win_get_buf(window)
local row, col = unpack(api.nvim_win_get_cursor(window))
- offset_encoding = offset_encoding or M._get_offset_encoding(buf)
row = row - 1
local line = api.nvim_buf_get_lines(buf, row, row + 1, true)[1]
if not line then
@@ -1868,13 +1867,19 @@ end
--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
---
---@param window integer?: window handle or 0 for current, defaults to current
----@param offset_encoding 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of buffer of `window`
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
---@return lsp.TextDocumentPositionParams
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params(window, offset_encoding)
window = window or 0
local buf = api.nvim_win_get_buf(window)
- offset_encoding = offset_encoding or M._get_offset_encoding(buf)
+ if offset_encoding == nil then
+ vim.notify_once(
+ 'warning: offset_encoding is required, using the offset_encoding from the first client',
+ vim.log.levels.WARN
+ )
+ offset_encoding = M._get_offset_encoding(buf)
+ end
return {
textDocument = M.make_text_document_params(buf),
position = make_position_param(window, offset_encoding),
@@ -1882,6 +1887,7 @@ function M.make_position_params(window, offset_encoding)
end
--- Utility function for getting the encoding of the first LSP client on the given buffer.
+---@deprecated
---@param bufnr integer buffer handle or 0 for current, defaults to current
---@return string encoding first client if there is one, nil otherwise
function M._get_offset_encoding(bufnr)
@@ -1904,7 +1910,7 @@ function M._get_offset_encoding(bufnr)
offset_encoding = this_offset_encoding
elseif offset_encoding ~= this_offset_encoding then
vim.notify_once(
- 'warning: multiple different client offset_encodings detected for buffer, this is not supported yet',
+ 'warning: multiple different client offset_encodings detected for buffer, vim.lsp.util._get_offset_encoding() uses the offset_encoding from the first client',
vim.log.levels.WARN
)
end
@@ -1919,12 +1925,17 @@ end
--- `textDocument/rangeFormatting`.
---
---@param window integer? window handle or 0 for current, defaults to current
----@param offset_encoding "utf-8"|"utf-16"|"utf-32"? defaults to `offset_encoding` of first client of buffer of `window`
----@return table { textDocument = { uri = `current_file_uri` }, range = { start =
----`current_position`, end = `current_position` } }
+---@param offset_encoding "utf-8"|"utf-16"|"utf-32"
+---@return { textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }
function M.make_range_params(window, offset_encoding)
local buf = api.nvim_win_get_buf(window or 0)
- offset_encoding = offset_encoding or M._get_offset_encoding(buf)
+ if offset_encoding == nil then
+ vim.notify_once(
+ 'warning: offset_encoding is required, using the offset_encoding from the first client',
+ vim.log.levels.WARN
+ )
+ offset_encoding = M._get_offset_encoding(buf)
+ end
local position = make_position_param(window, offset_encoding)
return {
textDocument = M.make_text_document_params(buf),
@@ -1940,15 +1951,20 @@ end
---@param end_pos [integer,integer]? {row,col} mark-indexed position.
--- Defaults to the end of the last visual selection.
---@param bufnr integer? buffer handle or 0 for current, defaults to current
----@param offset_encoding 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of `bufnr`
----@return table { textDocument = { uri = `current_file_uri` }, range = { start =
----`start_position`, end = `end_position` } }
+---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
+---@return { textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }
function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding)
validate('start_pos', start_pos, 'table', true)
validate('end_pos', end_pos, 'table', true)
validate('offset_encoding', offset_encoding, 'string', true)
bufnr = bufnr or api.nvim_get_current_buf()
- offset_encoding = offset_encoding or M._get_offset_encoding(bufnr)
+ if offset_encoding == nil then
+ vim.notify_once(
+ 'warning: offset_encoding is required, using the offset_encoding from the first client',
+ vim.log.levels.WARN
+ )
+ offset_encoding = M._get_offset_encoding(bufnr)
+ end
--- @type [integer, integer]
local A = { unpack(start_pos or api.nvim_buf_get_mark(bufnr, '<')) }
--- @type [integer, integer]
@@ -2122,7 +2138,7 @@ function M._refresh(method, opts)
local first = vim.fn.line('w0', window)
local last = vim.fn.line('w$', window)
for _, client in ipairs(clients) do
- client.request(method, {
+ client:request(method, {
textDocument = textDocument,
range = make_line_range_params(bufnr, first - 1, last - 1, client.offset_encoding),
}, nil, bufnr)
@@ -2131,7 +2147,7 @@ function M._refresh(method, opts)
end
else
for _, client in ipairs(clients) do
- client.request(method, {
+ client:request(method, {
textDocument = textDocument,
range = make_line_range_params(
bufnr,
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 7bdcdc774a..8ce8652f7d 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -93,9 +93,6 @@ function TSHighlighter.new(tree, opts)
opts = opts or {} ---@type { queries: table<string,string> }
self.tree = tree
tree:register_cbs({
- on_bytes = function(...)
- self:on_bytes(...)
- end,
on_detach = function()
self:on_detach()
end,
@@ -215,13 +212,6 @@ function TSHighlighter:for_each_highlight_state(fn)
end
---@package
----@param start_row integer
----@param new_end integer
-function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end)
- api.nvim__redraw({ buf = self.bufnr, range = { start_row, start_row + new_end + 1 } })
-end
-
----@package
function TSHighlighter:on_detach()
self:destroy()
end
@@ -230,7 +220,7 @@ end
---@param changes Range6[]
function TSHighlighter:on_changedtree(changes)
for _, ch in ipairs(changes) do
- api.nvim__redraw({ buf = self.bufnr, range = { ch[1], ch[4] + 1 } })
+ api.nvim__redraw({ buf = self.bufnr, range = { ch[1], ch[4] + 1 }, flush = false })
end
end
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index fd68c2b910..4b42164dc8 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -1037,7 +1037,7 @@ end
--- Registers callbacks for the [LanguageTree].
---@param cbs table<TSCallbackNameOn,function> An [nvim_buf_attach()]-like table argument with the following handlers:
---- - `on_bytes` : see [nvim_buf_attach()], but this will be called _after_ the parsers callback.
+--- - `on_bytes` : see [nvim_buf_attach()].
--- - `on_changedtree` : a callback that will be called every time the tree has syntactical changes.
--- It will be passed two arguments: a table of the ranges (as node ranges) that
--- changed and the changed tree.
diff --git a/runtime/syntax/checkhealth.vim b/runtime/syntax/checkhealth.vim
index a4f6e016cb..14c80640ba 100644
--- a/runtime/syntax/checkhealth.vim
+++ b/runtime/syntax/checkhealth.vim
@@ -1,6 +1,5 @@
" Vim syntax file
" Language: Nvim :checkhealth buffer
-" Last Change: 2022 Nov 10
if exists("b:current_syntax")
finish
diff --git a/runtime/syntax/hyprlang.vim b/runtime/syntax/hyprlang.vim
new file mode 100644
index 0000000000..f36c58c646
--- /dev/null
+++ b/runtime/syntax/hyprlang.vim
@@ -0,0 +1,58 @@
+" Vim syntax file
+" Language: hyprlang
+" Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
+" Last Change: 2024 nov 15
+
+if exists("b:current_syntax")
+ finish
+endif
+let b:current_syntax = "hyprlang"
+
+syn case ignore
+
+syn match hyprCommand '^\s*\zs\S\+\ze\s*=' contains=hyprVariable
+syn match hyprValue '=\s*\zs.\+\ze$' contains=hyprNumber,hyprFloat,hyprBoolean,hyprString,hyprColor,hyprModifier,hyprVariable,hyprComment
+
+syn match hyprVariable '\$\w\+' contained
+
+" Category
+syn region hyprCategory matchgroup=hyprCategoryD start='^\s*\k\+\s*{' end='^\s*}' contains=hyprCommand,hyprValue,hyprComment,hyprCategory,hyprCategoryD
+
+" Variables Types
+syn match hyprNumber '\%[-+]\<\d\+\>\%[%]' contained
+syn match hyprFloat '\%[-+]\<\d\+\.\d\+\>\%[%]' contained
+syn match hyprString '["\'].*["\']' contained
+syn match hyprColor 'rgb(\(\w\|\d\)\{6})' contained
+syn match hyprColor 'rgba(\(\w\|\d\)\{8})' contained
+syn match hyprColor '0x\(\w\|\d\)\{8}' contained
+syn keyword hyprBoolean true false yes no on off contained
+
+" Super Shift Alt Ctrl Control
+syn keyword hyprModifier contained
+ \ super supershift superalt superctrl supercontrol
+ \ super_shift super_alt super_ctrl super_control
+ \ shift shiftsuper shiftalt shiftctrl shiftcontrol
+ \ shift_super shift_alt shift_ctrl shift_control
+ \ alt altsuper altshift altctrl altcontrol
+ \ alt_super alt_shift alt_ctrl alt_control
+ \ ctrl ctrlsuper ctrlshift ctrlalt ctrlcontrol
+ \ ctrl_super ctrl_shift ctrl_alt ctrl_control
+ \ control controlsuper controlshift controlalt controlctrl
+ \ control_super control_shift control_alt control_ctrl
+
+" Comments
+syn match hyprComment '#.*$'
+
+" Link to default groups
+hi def link hyprVariable Identifier
+hi def link hyprCategoryD Special
+hi def link hyprComment Comment
+hi def link hyprNumber Constant
+hi def link hyprModifier Constant
+hi def link hyprFloat hyprNumber
+hi def link hyprBoolean Boolean
+hi def link hyprString String
+hi def link hyprColor Structure
+hi def link hyprCommand Keyword
+
+" vim: ts=8 sts=2 sw=2 et
diff --git a/runtime/syntax/karel.vim b/runtime/syntax/karel.vim
new file mode 100644
index 0000000000..85c78529e6
--- /dev/null
+++ b/runtime/syntax/karel.vim
@@ -0,0 +1,112 @@
+" Vim syntax file
+" Language: KAREL
+" Last Change: 2024-11-17
+" Maintainer: Kirill Morozov <kirill@robotix.pro>
+" Credits: Jay Strybis for the initial implementation and Patrick Knosowski
+" for a couple of fixes.
+
+if exists("b:current_syntax")
+ finish
+endif
+
+" KAREL is case-insensitive
+syntax case ignore
+
+" Identifiers
+syn match karelIdentifier /[a-zA-Z0-9_]\+/
+hi def link karelIdentifier Identifier
+
+" Constants
+syn keyword karelConstant CR
+syn region karelString start="'" end="'"
+syn match karelReal /\d\+\.\d\+/
+syn match karelInteger /\d\+/
+syn keyword karelBoolean true false
+hi def link karelConstant Constant
+hi def link karelString String
+hi def link karelInteger Number
+hi def link karelReal Float
+hi def link karelBoolean Boolean
+
+" Directives
+syn match karelDirective /%[a-zA-Z]\+/
+hi def link karelDirective PreProc
+
+" Operators
+syn keyword karelOperator AND OR NOT DIV MOD
+syn match karelOperator /[\+\-\*\/\<\=\>\:\#\@]/
+syn match karelOperator /<=/
+syn match karelOperator />=/
+syn match karelOperator /<>/
+syn match karelOperator />=</
+hi def link karelOperator Operator
+
+" Types
+syn keyword karelType ARRAY BOOLEAN BYTE CONFIG DISP_DAT_T FILE INTEGER JOINTPOS PATH POSITION QUEUE_TYPE REAL SHORT STD_PTH_NODE STRING VECTOR XYZWPR XYZWPREXT
+syn keyword karelStructure STRUCTURE ENDSTRUCTURE
+hi def link karelType Type
+hi def link karelStructure Typedef
+
+syn keyword karelAction NOABORT NOMESSAGE NOPAUSE PAUSE PULSE RESUME STOP UNHOLD UNPAUSE
+syn match karelAction /SIGNAL EVENT/
+syn match karelAction /SIGNAL SEMAPHORE/
+hi def link karelAction Keyword
+
+syn keyword karelFunction ABS ACOS APPROACH ARRAY_LEN ASIN ATAN2 ATTACH BYNAME BYTES_LEFT CHR COS CURJPOS CURPOS CURR_PROG EXP
+syn keyword karelFunction FRAME GET_FILE_POS GET_JPOS_REG GET_JPOS_TPE GET_PORT_ATR GET_POS_REG GET_POS_TPE GET_USEC_TIM INDEX
+syn keyword karelFunction IN_RANGE INV IO_STATUS J_IN_RANGE JOINT2POS LN MIRROR MOTION_CTL NODE_SIZE ORD ORIENT PATH_LEN POS POS2JOINT
+syn keyword karelFunction ROUND SEMA_COUNT SIN SQRT STR_LEN SUB_STR TAN TRUNC UNINIT
+hi def link karelFunction Function
+
+syn keyword karelClause EVAL FROM IN WHEN WITH
+hi def link karelClause Keyword
+
+syn keyword karelConditional IF THEN ELSE ENDIF SELECT ENDSELECT CASE
+hi def link karelConditional Conditional
+
+syn keyword karelRepeat WHILE DO ENDWHILE FOR
+hi def link karelRepeat Repeat
+
+syn keyword karelProcedure ABORT_TASK ACT_SCREEN ACT_TBL ADD_BYNAMEPC ADD_DICT ADD_INTPC ADD_REALPC ADD_STRINGPC APPEND_NODE APPEND_QUEUE
+syn keyword karelProcedure ATT_WINDOW_D ATT_WINDOW_S AVL_POS_NUM
+syn keyword karelProcedure BYTES_AHEAD
+syn keyword karelProcedure CALL_PROG CALL_PROGLIN CHECK_DICT CHECK_EPOS CHECK_NAME CLEAR CLEAR_SEMA CLOSE_TEP CLR_IO_STAT CLR_PORT_SIM CLR_POS_REG
+syn keyword karelProcedure CNC_DYN_DISB CNC_DYN_DISE CNC_DYN_DISI CNC_DYN_DISP CNC_DYN_DISR CNC_DYN_DISS CNCL_STP_MTN CNV_CNF_STRG CNV_CONF_STR CNV_INT_STR CNV_JPOS_REL CNV_REAL_STR CNV_REL_JPOS CNV_STR_CONF CNV_STR_INT CNV_STR_REAL CNV_STR_TIME CNV_TIME_STR
+syn keyword karelProcedure COMPARE_FILE CONT_TASK COPY_FILE COPY_PATH COPY_QUEUE COPY_TPE CREATE_TPE CREATE_VAR
+syn keyword karelProcedure DAQ_CHECKP DAQ_REGPIPE DAQ_START DAQ_STOP DAQ_UNREG DAQ_WRITE DEF_SCREEN DEF_WINDOW
+syn keyword karelProcedure DELETE_FILE DELETE_NODE DELETE_QUEUE DEL_INST_TPE DET_WINDOW DISCTRL_ALPH DISCTRL_FORM DISCTRL_LIST DISCTRL_PLMN DISCTRL_SBMN DISCTRL_TBL DISMOUNT_DEV DOSFILE_INF
+syn keyword karelProcedure ERR_DATA FILE_LIST FORCE_SPMENU FORMAT_DEV GET_ATTR_PRG GET_PORT_ASG GET_PORT_CMT GET_PORT_MOD GET_PORT_SIM GET_PORT_VAL GET_POS_FRM GET_POS_TYP GET_PREG_CMT GET_QUEUE
+syn keyword karelProcedure GET_REG GET_REG_CMT GET_SREG_CMT GET_STR_REG GET_TIME GET_TPE_CMT GET_TPE_PRM GET_TSK_INFO GET_USEC_SUB GET_VAR
+syn keyword karelProcedure INI_DYN_DISB INI_DYN_DISE INI_DYN_DISI INI_DYN_DISP INI_DYN_DISR INI_DYN_DISS INIT_QUEUE INIT_TBL INSERT_NODE INSERT_QUEUE IO_MOD_TYPE
+syn keyword karelProcedure KCL KCL_NO_WAIT KCL_STATUS LOAD LOAD_STATUS LOCK_GROUP MODIFY_QUEUE MOUNT_DEV MOVE_FILE MSG_CONNECT MSG_DISO MSG_PING
+syn keyword karelProcedure OPEN_TPE PAUSE_TASK PEND_SEMA PIPE_CONFIG POP_KEY_RD POS_REG_TYPE POST_ERR POST_ERR_L POST_SEMA PRINT_FILE PROG_BACKUP PROG_CLEAR PROG_RESTORE PROG_LIST
+syn keyword karelProcedure PURGE_DEV PUSH_KEY_RD READ_DICT READ_DICT_V READ_KB REMOVE_DICT RENAME_FILE RENAME_VAR RENAME_VARS RESET RUN_TASK SAVE SAVE_DRAM SELECT_TPE SEND_DATAPC SEND_EVENTPC SET_ATTR_PRG SET_CURSOR SET_EPOS_REG SET_EPOS_TPE
+syn keyword karelProcedure SET_FILE_ATR SET_FILE_POS SET_INT_REG SET_JPOS_REG SET_JPOS_TPE SET_LANG SET_PERCH SET_PORT_ASG SET_PORT_ATR SET_PORT_CMT SET_PORT_MOD SET_PORT_SIM SET_PORT_VAL SET_POS_REG SET_POS_TPE SET_PREG_CMT SET_REAL_REG SET_REG CMT SET_SREG_CMT SET_STR_REG SET_TIME SET_TPE_CMT SET_TRNS_TPE SET_TSK_ATTR SET_TSK_NAME SET_VAR
+syn keyword karelProcedure TRANSLATE UNLOCK_GROUP UNPOS V_CAM_CALIB V_GET_OFFSET V_GET_PASSFL V_GET_QUEUE V_INIT_QUEUE V_RALC_QUEUE V_RUN_FIND V_SET_REF V_START_VTRK V_STOP_VTRK VAR_INFO VAR_LIST VOL_SPACE VREG_FND_POS VREG_OFFSET
+syn keyword karelProcedure WRITE_DICT WRITE_DICT_V XML_ADDTAG XML_GETDATA XML_REMTAG XML_SCAN XML_SETVAR
+hi def link karelProcedure Function
+
+syn keyword karelStatement ABORT CONDITION ENDCONDITION CONTINUE DELAY ERROR EVENT FOR ENDFOR HOLD READ RELEASE REPEAT RETURN SEMAPHORE UNTIL USING ENDUSING WRITE
+syn match karelStatement /CANCEL FILE/
+syn match karelStatement /CLOSE FILE/
+syn match karelStatement /CLOSE HAND/
+syn match karelStatement /CONNECT TIMER/
+syn match karelStatement /DISABLE CONDITION/
+syn match karelStatement /DISCONNECT TIMER/
+syn match karelStatement /ENABLE CONDITION/
+syn match karelStatement /GO TO/
+syn match karelStatement /OPEN FILE/
+syn match karelStatement /OPEN HAND/
+syn match karelStatement /PURGE CONDITION/
+syn match karelStatement /RELAX HAND/
+syn match karelStatement /WAIT FOR/
+hi def link karelStatement Statement
+
+syn keyword karelKeyword BEGIN CONST END PROGRAM ROUTINE STRUCT TYPE VAR
+hi def link karelKeyword Keyword
+
+" Comments
+syn region karelComment start="--" end="$"
+hi def link karelComment Comment
+
+let b:current_syntax = "karel"
diff --git a/runtime/syntax/mss.vim b/runtime/syntax/mss.vim
new file mode 100644
index 0000000000..de95d1d2ad
--- /dev/null
+++ b/runtime/syntax/mss.vim
@@ -0,0 +1,23 @@
+" Vim syntax file
+" Language: Vivado mss file
+" Maintainer: The Vim Project <https://github.com/vim/vim>
+" Last Change: 2024 Oct 22
+" Document: https://docs.amd.com/r/2020.2-English/ug1400-vitis-embedded/Microprocessor-Software-Specification-MSS
+" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
+
+if exists("b:current_syntax")
+ finish
+endif
+
+syn case ignore
+syn match mssComment "#.*$" contains=@Spell
+syn keyword mssKeyword BEGIN END PARAMETER
+syn keyword mssType OS PROCESSOR DRIVER LIBRARY
+syn keyword mssConstant VERSION PROC_INSTANCE HW_INSTANCE OS_NAME OS_VER DRIVER_NAME DRIVER_VER LIBRARY_NAME LIBRARY_VER STDIN STDOUT XMDSTUB_PERIPHERAL ARCHIVER COMPILER COMPILER_FLAGS EXTRA_COMPILER_FLAGS
+
+hi def link mssComment Comment
+hi def link mssKeyword Keyword
+hi def link mssType Type
+hi def link mssConstant Constant
+
+let b:current_syntax = "mss"
diff --git a/runtime/syntax/opencl.vim b/runtime/syntax/opencl.vim
new file mode 100644
index 0000000000..c237aa30f9
--- /dev/null
+++ b/runtime/syntax/opencl.vim
@@ -0,0 +1,13 @@
+" Vim syntax file
+" Language: OpenCL
+" Last Change: 2024 Nov 19
+" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
+
+if exists("b:current_syntax")
+ finish
+endif
+
+" TODO: support openCL specific keywords
+runtime! syntax/c.vim
+
+let current_syntax = "opencl"
diff --git a/runtime/syntax/query.lua b/runtime/syntax/query.lua
index 2dfe29f69b..0de08b4dfb 100644
--- a/runtime/syntax/query.lua
+++ b/runtime/syntax/query.lua
@@ -1,6 +1,5 @@
-- Neovim syntax file
-- Language: Treesitter query
--- Last Change: 2024 Jul 03
-- it's a lisp!
vim.cmd([[runtime! syntax/lisp.vim]])
diff --git a/scripts/gen_eval_files.lua b/scripts/gen_eval_files.lua
index edf95043c5..a9431ae2e5 100755
--- a/scripts/gen_eval_files.lua
+++ b/scripts/gen_eval_files.lua
@@ -617,8 +617,8 @@ local function render_option_meta(_f, opt, write)
end
for _, s in pairs {
- { 'wo', 'window' },
- { 'bo', 'buffer' },
+ { 'wo', 'win' },
+ { 'bo', 'buf' },
{ 'go', 'global' },
} do
local id, scope = s[1], s[2]
@@ -661,8 +661,8 @@ end
local function scope_to_doc(s)
local m = {
global = 'global',
- buffer = 'local to buffer',
- window = 'local to window',
+ buf = 'local to buffer',
+ win = 'local to window',
tab = 'local to tab page',
}
@@ -717,7 +717,7 @@ local function get_option_meta()
local optinfo = vim.api.nvim_get_all_options_info()
local ret = {} --- @type table<string,vim.option_meta>
for _, o in ipairs(opts) do
- local is_window_option = #o.scope == 1 and o.scope[1] == 'window'
+ local is_window_option = #o.scope == 1 and o.scope[1] == 'win'
local is_option_hidden = o.immutable and not o.varname and not is_window_option
if not is_option_hidden and o.desc then
if o.full_name == 'cmdheight' then
diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua
index 9cd5b598da..1125021bdc 100755
--- a/scripts/gen_vimdoc.lua
+++ b/scripts/gen_vimdoc.lua
@@ -538,7 +538,8 @@ end
--- @param generics? table<string,string>
--- @param classes? table<string,nvim.luacats.parser.class>
--- @param exclude_types? true
-local function render_fields_or_params(xs, generics, classes, exclude_types)
+--- @param cfg nvim.gen_vimdoc.Config
+local function render_fields_or_params(xs, generics, classes, exclude_types, cfg)
local ret = {} --- @type string[]
xs = vim.tbl_filter(should_render_field_or_param, xs)
@@ -558,7 +559,9 @@ local function render_fields_or_params(xs, generics, classes, exclude_types)
p.desc = pdesc
inline_type(p, classes)
- local nm, ty, desc = p.name, p.type, p.desc
+ local nm, ty = p.name, p.type
+
+ local desc = p.classvar and string.format('See |%s|.', cfg.fn_helptag_fmt(p)) or p.desc
local fnm = p.kind == 'operator' and fmt('op(%s)', nm) or fmt_field_name(nm)
local pnm = fmt(' • %-' .. indent .. 's', fnm)
@@ -591,7 +594,8 @@ end
--- @param class nvim.luacats.parser.class
--- @param classes table<string,nvim.luacats.parser.class>
-local function render_class(class, classes)
+--- @param cfg nvim.gen_vimdoc.Config
+local function render_class(class, classes, cfg)
if class.access or class.nodoc or class.inlinedoc then
return
end
@@ -610,7 +614,7 @@ local function render_class(class, classes)
table.insert(ret, md_to_vimdoc(class.desc, INDENTATION, INDENTATION, TEXT_WIDTH))
end
- local fields_txt = render_fields_or_params(class.fields, nil, classes)
+ local fields_txt = render_fields_or_params(class.fields, nil, classes, nil, cfg)
if not fields_txt:match('^%s*$') then
table.insert(ret, '\n Fields: ~\n')
table.insert(ret, fields_txt)
@@ -621,11 +625,12 @@ local function render_class(class, classes)
end
--- @param classes table<string,nvim.luacats.parser.class>
-local function render_classes(classes)
+--- @param cfg nvim.gen_vimdoc.Config
+local function render_classes(classes, cfg)
local ret = {} --- @type string[]
for _, class in vim.spairs(classes) do
- ret[#ret + 1] = render_class(class, classes)
+ ret[#ret + 1] = render_class(class, classes, cfg)
end
return table.concat(ret)
@@ -656,10 +661,6 @@ local function render_fun_header(fun, cfg)
local proto = fun.table and nm or nm .. '(' .. table.concat(args, ', ') .. ')'
- if not cfg.fn_helptag_fmt then
- cfg.fn_helptag_fmt = fn_helptag_fmt_common
- end
-
local tag = '*' .. cfg.fn_helptag_fmt(fun) .. '*'
if #proto + #tag > TEXT_WIDTH - 8 then
@@ -774,7 +775,8 @@ local function render_fun(fun, classes, cfg)
end
if fun.params and #fun.params > 0 then
- local param_txt = render_fields_or_params(fun.params, fun.generics, classes, cfg.exclude_types)
+ local param_txt =
+ render_fields_or_params(fun.params, fun.generics, classes, cfg.exclude_types, cfg)
if not param_txt:match('^%s*$') then
table.insert(ret, '\n Parameters: ~\n')
ret[#ret + 1] = param_txt
@@ -957,6 +959,7 @@ end
--- @param cfg nvim.gen_vimdoc.Config
local function gen_target(cfg)
+ cfg.fn_helptag_fmt = cfg.fn_helptag_fmt or fn_helptag_fmt_common
print('Target:', cfg.filename)
local sections = {} --- @type table<string,nvim.gen_vimdoc.Section>
@@ -987,7 +990,7 @@ local function gen_target(cfg)
print(' Processing file:', f)
local funs_txt = render_funs(funs, all_classes, cfg)
if next(classes) then
- local classes_txt = render_classes(classes)
+ local classes_txt = render_classes(classes, cfg)
if vim.trim(classes_txt) ~= '' then
funs_txt = classes_txt .. '\n' .. funs_txt
end
diff --git a/scripts/luacats_parser.lua b/scripts/luacats_parser.lua
index 9a763e4d7b..8a50077aa8 100644
--- a/scripts/luacats_parser.lua
+++ b/scripts/luacats_parser.lua
@@ -1,9 +1,6 @@
local luacats_grammar = require('scripts.luacats_grammar')
---- @class nvim.luacats.parser.param
---- @field name string
---- @field type string
---- @field desc string
+--- @class nvim.luacats.parser.param : nvim.luacats.Param
--- @class nvim.luacats.parser.return
--- @field name string
@@ -41,21 +38,14 @@ local luacats_grammar = require('scripts.luacats_grammar')
--- @field notes? nvim.luacats.parser.note[]
--- @field see? nvim.luacats.parser.note[]
---- @class nvim.luacats.parser.field
---- @field name string
---- @field type string
---- @field desc string
---- @field access? 'private'|'package'|'protected'
+--- @class nvim.luacats.parser.field : nvim.luacats.Field
+--- @field classvar? string
--- @field nodoc? true
---- @class nvim.luacats.parser.class
---- @field kind 'class'
---- @field parent? string
---- @field name string
---- @field desc string
+--- @class nvim.luacats.parser.class : nvim.luacats.Class
+--- @field desc? string
--- @field nodoc? true
--- @field inlinedoc? true
---- @field access? 'private'|'package'|'protected'
--- @field fields nvim.luacats.parser.field[]
--- @field notes? string[]
@@ -332,7 +322,10 @@ local function process_lua_line(line, state, classes, classvars, has_indent)
end
-- Add method as the field to the class
- table.insert(classes[class].fields, fun2field(cur_obj))
+ local cls = classes[class]
+ local field = fun2field(cur_obj)
+ field.classvar = cur_obj.classvar
+ table.insert(cls.fields, field)
return
end
diff --git a/src/clint.py b/src/clint.py
index b57bbe354b..8044607098 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -897,7 +897,7 @@ def CheckIncludes(filename, lines, error):
if (not name.endswith('.h.generated.h') and
not name.endswith('/defs.h') and
not name.endswith('_defs.h') and
- not name.endswith('h.inline.generated.h') and
+ not name.endswith('.h.inline.generated.h') and
not name.endswith('_defs.generated.h') and
not name.endswith('_enum.generated.h')):
error(filename, i, 'build/include_defs', 5,
@@ -2206,12 +2206,6 @@ def ProcessFileData(filename, file_extension, lines, error,
error = RecordedError
- if file_extension == 'h':
- CheckForHeaderGuard(filename, lines, error)
- CheckIncludes(filename, lines, error)
- if filename.endswith('/defs.h') or filename.endswith('_defs.h'):
- CheckNonSymbols(filename, lines, error)
-
RemoveMultiLineComments(filename, lines, error)
clean_lines = CleansedLines(lines, init_lines)
for line in range(clean_lines.NumLines()):
@@ -2219,6 +2213,12 @@ def ProcessFileData(filename, file_extension, lines, error,
nesting_state, error,
extra_check_functions)
+ if file_extension == 'h':
+ CheckForHeaderGuard(filename, lines, error)
+ CheckIncludes(filename, lines, error)
+ if filename.endswith('/defs.h') or filename.endswith('_defs.h'):
+ CheckNonSymbols(filename, lines, error)
+
# We check here rather than inside ProcessLine so that we see raw
# lines rather than "cleaned" lines.
CheckForBadCharacters(filename, lines, error)
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 1b6827322d..38b54082c3 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -308,7 +308,6 @@ set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua)
set(GENERATOR_HASHY ${GENERATOR_DIR}/hashy.lua)
set(GENERATOR_PRELOAD ${GENERATOR_DIR}/preload.lua)
set(HEADER_GENERATOR ${GENERATOR_DIR}/gen_declarations.lua)
-set(OPTIONS_ENUM_GENERATOR ${GENERATOR_DIR}/gen_options_enum.lua)
set(OPTIONS_GENERATOR ${GENERATOR_DIR}/gen_options.lua)
# GENERATED_DIR and GENERATED_INCLUDES_DIR
@@ -687,16 +686,11 @@ add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
DEPENDS ${LUA_GEN_DEPS} ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua
)
-add_custom_command(OUTPUT ${GENERATED_OPTIONS}
- COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS}
+add_custom_command(OUTPUT ${GENERATED_OPTIONS} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP}
+ COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP}
DEPENDS ${LUA_GEN_DEPS} ${OPTIONS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua
)
-add_custom_command(OUTPUT ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP}
- COMMAND ${LUA_GEN} ${OPTIONS_ENUM_GENERATOR} ${GENERATED_OPTIONS_ENUM} ${GENERATED_OPTIONS_MAP}
- DEPENDS ${LUA_GEN_DEPS} ${OPTIONS_ENUM_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua
-)
-
# NVIM_GENERATED_FOR_SOURCES and NVIM_GENERATED_FOR_HEADERS must be mutually exclusive.
foreach(hfile ${NVIM_GENERATED_FOR_HEADERS})
list(FIND NVIM_GENERATED_FOR_SOURCES ${hfile} hfile_idx)
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index b3ba832fec..b38a7d4173 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -533,7 +533,7 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err)
FUNC_API_SINCE(1)
FUNC_API_DEPRECATED_SINCE(11)
{
- set_option_to(channel_id, NULL, kOptReqGlobal, name, value, err);
+ set_option_to(channel_id, NULL, kOptScopeGlobal, name, value, err);
}
/// Gets the global value of an option.
@@ -546,7 +546,7 @@ Object nvim_get_option(String name, Error *err)
FUNC_API_SINCE(1)
FUNC_API_DEPRECATED_SINCE(11)
{
- return get_option_from(NULL, kOptReqGlobal, name, err);
+ return get_option_from(NULL, kOptScopeGlobal, name, err);
}
/// Gets a buffer option value
@@ -566,7 +566,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
return (Object)OBJECT_INIT;
}
- return get_option_from(buf, kOptReqBuf, name, err);
+ return get_option_from(buf, kOptScopeBuf, name, err);
}
/// Sets a buffer option value. Passing `nil` as value deletes the option (only
@@ -588,7 +588,7 @@ void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object
return;
}
- set_option_to(channel_id, buf, kOptReqBuf, name, value, err);
+ set_option_to(channel_id, buf, kOptScopeBuf, name, value, err);
}
/// Gets a window option value
@@ -608,7 +608,7 @@ Object nvim_win_get_option(Window window, String name, Error *err)
return (Object)OBJECT_INIT;
}
- return get_option_from(win, kOptReqWin, name, err);
+ return get_option_from(win, kOptScopeWin, name, err);
}
/// Sets a window option value. Passing `nil` as value deletes the option (only
@@ -630,48 +630,18 @@ void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object
return;
}
- set_option_to(channel_id, win, kOptReqWin, name, value, err);
-}
-
-/// Check if option has a value in the requested scope.
-///
-/// @param opt_idx Option index in options[] table.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
-///
-/// @return true if option has a value in the requested scope, false otherwise.
-static bool option_has_scope(OptIndex opt_idx, OptReqScope req_scope)
-{
- if (opt_idx == kOptInvalid) {
- return false;
- }
-
- vimoption_T *opt = get_option(opt_idx);
-
- // TTY option.
- if (is_tty_option(opt->fullname)) {
- return req_scope == kOptReqGlobal;
- }
-
- switch (req_scope) {
- case kOptReqGlobal:
- return opt->var != VAR_WIN;
- case kOptReqBuf:
- return opt->indir & PV_BUF;
- case kOptReqWin:
- return opt->indir & PV_WIN;
- }
- UNREACHABLE;
+ set_option_to(channel_id, win, kOptScopeWin, name, value, err);
}
/// Gets the value of a global or local (buffer, window) option.
///
/// @param[in] from Pointer to buffer or window for local option value.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param name The option name.
/// @param[out] err Details of an error that may have occurred.
///
/// @return the option value.
-static Object get_option_from(void *from, OptReqScope req_scope, String name, Error *err)
+static Object get_option_from(void *from, OptScope req_scope, String name, Error *err)
{
VALIDATE_S(name.size > 0, "option name", "<empty>", {
return (Object)OBJECT_INIT;
@@ -681,7 +651,7 @@ static Object get_option_from(void *from, OptReqScope req_scope, String name, Er
OptVal value = NIL_OPTVAL;
if (option_has_scope(opt_idx, req_scope)) {
- value = get_option_value_for(opt_idx, req_scope == kOptReqGlobal ? OPT_GLOBAL : OPT_LOCAL,
+ value = get_option_value_for(opt_idx, req_scope == kOptScopeGlobal ? OPT_GLOBAL : OPT_LOCAL,
req_scope, from, err);
if (ERROR_SET(err)) {
return (Object)OBJECT_INIT;
@@ -698,11 +668,11 @@ static Object get_option_from(void *from, OptReqScope req_scope, String name, Er
/// Sets the value of a global or local (buffer, window) option.
///
/// @param[in] to Pointer to buffer or window for local option value.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param name The option name.
/// @param value New option value.
/// @param[out] err Details of an error that may have occurred.
-static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope, String name,
+static void set_option_to(uint64_t channel_id, void *to, OptScope req_scope, String name,
Object value, Error *err)
{
VALIDATE_S(name.size > 0, "option name", "<empty>", {
@@ -725,12 +695,12 @@ static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope,
return;
});
- int attrs = get_option_attrs(opt_idx);
// For global-win-local options -> setlocal
// For win-local options -> setglobal and setlocal (opt_flags == 0)
- const int opt_flags = (req_scope == kOptReqWin && !(attrs & SOPT_GLOBAL))
- ? 0
- : (req_scope == kOptReqGlobal) ? OPT_GLOBAL : OPT_LOCAL;
+ const int opt_flags
+ = (req_scope == kOptScopeWin && !option_has_scope(opt_idx, kOptScopeGlobal))
+ ? 0
+ : ((req_scope == kOptScopeGlobal) ? OPT_GLOBAL : OPT_LOCAL);
WITH_SCRIPT_CONTEXT(channel_id, {
set_option_value_for(name.data, opt_idx, optval, opt_flags, req_scope, to, err);
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 7786c30624..c94b8df9ea 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -381,8 +381,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// - id : id of the extmark to edit.
/// - end_row : ending line of the mark, 0-based inclusive.
/// - end_col : ending col of the mark, 0-based exclusive.
-/// - hl_group : name of the highlight group used to highlight
-/// this mark.
+/// - hl_group : highlight group used for the text range. This and below
+/// highlight groups can be supplied either as a string or as an integer,
+/// the latter of which can be obtained using |nvim_get_hl_id_by_name()|.
/// - hl_eol : when true, for a multiline highlight covering the
/// EOL of a line, continue the highlight for the rest
/// of the screen line (just like for diff and
@@ -392,9 +393,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// text chunk with specified highlight. `highlight` element
/// can either be a single highlight group, or an array of
/// multiple highlight groups that will be stacked
-/// (highest priority last). A highlight group can be supplied
-/// either as a string or as an integer, the latter which
-/// can be obtained using |nvim_get_hl_id_by_name()|.
+/// (highest priority last).
/// - virt_text_pos : position of virtual text. Possible values:
/// - "eol": right after eol character (default).
/// - "overlay": display over the specified column, without
@@ -465,15 +464,12 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// buffer or end of the line respectively. Defaults to true.
/// - sign_text: string of length 1-2 used to display in the
/// sign column.
-/// - sign_hl_group: name of the highlight group used to
-/// highlight the sign column text.
-/// - number_hl_group: name of the highlight group used to
-/// highlight the number column.
-/// - line_hl_group: name of the highlight group used to
-/// highlight the whole line.
-/// - cursorline_hl_group: name of the highlight group used to
-/// highlight the sign column text when the cursor is on
-/// the same line as the mark and 'cursorline' is enabled.
+/// - sign_hl_group: highlight group used for the sign column text.
+/// - number_hl_group: highlight group used for the number column.
+/// - line_hl_group: highlight group used for the whole line.
+/// - cursorline_hl_group: highlight group used for the sign
+/// column text when the cursor is on the same line as the
+/// mark and 'cursorline' is enabled.
/// - conceal: string which should be either empty or a single
/// character. Enable concealing similar to |:syn-conceal|.
/// When a character is supplied it is used as |:syn-cchar|.
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index 96866d80ba..3289daeb6f 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -23,8 +23,8 @@
#endif
static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *opt_idxp,
- int *scope, OptReqScope *req_scope, void **from,
- char **filetype, Error *err)
+ int *scope, OptScope *req_scope, void **from, char **filetype,
+ Error *err)
{
#define HAS_KEY_X(d, v) HAS_KEY(d, option, v)
if (HAS_KEY_X(opts, scope)) {
@@ -39,14 +39,14 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
}
}
- *req_scope = kOptReqGlobal;
+ *req_scope = kOptScopeGlobal;
if (filetype != NULL && HAS_KEY_X(opts, filetype)) {
*filetype = opts->filetype.data;
}
if (HAS_KEY_X(opts, win)) {
- *req_scope = kOptReqWin;
+ *req_scope = kOptScopeWin;
*from = find_window_by_handle(opts->win, err);
if (ERROR_SET(err)) {
return FAIL;
@@ -59,7 +59,7 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
return FAIL;
});
*scope = OPT_LOCAL;
- *req_scope = kOptReqBuf;
+ *req_scope = kOptScopeBuf;
*from = find_buffer_by_handle(opts->buf, err);
if (ERROR_SET(err)) {
return FAIL;
@@ -78,18 +78,17 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
});
*opt_idxp = find_option(name);
- int flags = get_option_attrs(*opt_idxp);
- if (flags == 0) {
+ if (*opt_idxp == kOptInvalid) {
// unknown option
api_set_error(err, kErrorTypeValidation, "Unknown option '%s'", name);
- } else if (*req_scope == kOptReqBuf || *req_scope == kOptReqWin) {
+ } else if (*req_scope == kOptScopeBuf || *req_scope == kOptScopeWin) {
// if 'buf' or 'win' is passed, make sure the option supports it
- int req_flags = *req_scope == kOptReqBuf ? SOPT_BUF : SOPT_WIN;
- if (!(flags & req_flags)) {
- char *tgt = *req_scope & kOptReqBuf ? "buf" : "win";
- char *global = flags & SOPT_GLOBAL ? "global " : "";
- char *req = flags & SOPT_BUF ? "buffer-local "
- : flags & SOPT_WIN ? "window-local " : "";
+ if (!option_has_scope(*opt_idxp, *req_scope)) {
+ char *tgt = *req_scope == kOptScopeBuf ? "buf" : "win";
+ char *global = option_has_scope(*opt_idxp, kOptScopeGlobal) ? "global " : "";
+ char *req = option_has_scope(*opt_idxp, kOptScopeBuf)
+ ? "buffer-local "
+ : (option_has_scope(*opt_idxp, kOptScopeWin) ? "window-local " : "");
api_set_error(err, kErrorTypeValidation, "'%s' cannot be passed for %s%soption '%s'",
tgt, global, req, name);
@@ -153,7 +152,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
{
OptIndex opt_idx = 0;
int scope = 0;
- OptReqScope req_scope = kOptReqGlobal;
+ OptScope req_scope = kOptScopeGlobal;
void *from = NULL;
char *filetype = NULL;
@@ -166,6 +165,14 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
buf_T *ftbuf = do_ft_buf(filetype, &aco, err);
if (ERROR_SET(err)) {
+ if (ftbuf != NULL) {
+ // restore curwin/curbuf and a few other things
+ aucmd_restbuf(&aco);
+
+ assert(curbuf != ftbuf); // safety check
+ wipe_buffer(ftbuf, false);
+ }
+
return (Object)OBJECT_INIT;
}
@@ -218,7 +225,7 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(
{
OptIndex opt_idx = 0;
int scope = 0;
- OptReqScope req_scope = kOptReqGlobal;
+ OptScope req_scope = kOptScopeGlobal;
void *to = NULL;
if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &to, NULL, err)) {
return;
@@ -230,9 +237,8 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(
// - option is global or local to window (global-local)
//
// Then force scope to local since we don't want to change the global option
- if (req_scope == kOptReqWin && scope == 0) {
- int flags = get_option_attrs(opt_idx);
- if (flags & SOPT_GLOBAL) {
+ if (req_scope == kOptScopeWin && scope == 0) {
+ if (option_has_scope(opt_idx, kOptScopeGlobal)) {
scope = OPT_LOCAL;
}
}
@@ -305,15 +311,15 @@ Dict nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena, Error
{
OptIndex opt_idx = 0;
int scope = 0;
- OptReqScope req_scope = kOptReqGlobal;
+ OptScope req_scope = kOptScopeGlobal;
void *from = NULL;
if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &from, NULL,
err)) {
return (Dict)ARRAY_DICT_INIT;
}
- buf_T *buf = (req_scope == kOptReqBuf) ? (buf_T *)from : curbuf;
- win_T *win = (req_scope == kOptReqWin) ? (win_T *)from : curwin;
+ buf_T *buf = (req_scope == kOptScopeBuf) ? (buf_T *)from : curbuf;
+ win_T *win = (req_scope == kOptScopeWin) ? (win_T *)from : curwin;
return get_vimoption(name, scope, buf, win, arena, err);
}
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index d21caf7ed0..8ddaecc58e 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -771,7 +771,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err)
int id = (int)obj.data.integer;
return (1 <= id && id <= highlight_num_groups()) ? id : 0;
} else {
- api_set_error(err, kErrorTypeValidation, "Invalid highlight: %s", what);
+ api_set_error(err, kErrorTypeValidation, "Invalid hl_group: %s", what);
return 0;
}
}
@@ -809,28 +809,20 @@ HlMessage parse_hl_msg(Array chunks, Error *err)
{
HlMessage hl_msg = KV_INITIAL_VALUE;
for (size_t i = 0; i < chunks.size; i++) {
- if (chunks.items[i].type != kObjectTypeArray) {
- api_set_error(err, kErrorTypeValidation, "Chunk is not an array");
+ VALIDATE_T("chunk", kObjectTypeArray, chunks.items[i].type, {
goto free_exit;
- }
+ });
Array chunk = chunks.items[i].data.array;
- if (chunk.size == 0 || chunk.size > 2
- || chunk.items[0].type != kObjectTypeString
- || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) {
- api_set_error(err, kErrorTypeValidation,
- "Chunk is not an array with one or two strings");
+ VALIDATE((chunk.size > 0 && chunk.size <= 2 && chunk.items[0].type == kObjectTypeString),
+ "%s", "Invalid chunk: expected Array with 1 or 2 Strings", {
goto free_exit;
- }
+ });
String str = copy_string(chunk.items[0].data.string, NULL);
int hl_id = 0;
if (chunk.size == 2) {
- String hl = chunk.items[1].data.string;
- if (hl.size > 0) {
- // TODO(bfredl): use object_to_hl_id and allow integer
- hl_id = syn_check_group(hl.data, hl.size);
- }
+ hl_id = object_to_hl_id(chunk.items[1], "text highlight", err);
}
kv_push(hl_msg, ((HlMessageChunk){ .text = str, .hl_id = hl_id }));
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index e6ec88c5e8..83f9aa573d 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -779,8 +779,8 @@ void nvim_set_vvar(String name, Object value, Error *err)
/// Echo a message.
///
/// @param chunks A list of `[text, hl_group]` arrays, each representing a
-/// text chunk with specified highlight. `hl_group` element
-/// can be omitted for no highlight.
+/// text chunk with specified highlight group name or ID.
+/// `hl_group` element can be omitted for no highlight.
/// @param history if true, add to |message-history|.
/// @param opts Optional parameters.
/// - verbose: Message is printed as a result of 'verbose' option.
@@ -1004,10 +1004,10 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
if (scratch) {
- set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0, kOptReqBuf,
- buf);
- set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0, kOptReqBuf,
- buf);
+ set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0,
+ kOptScopeBuf, buf);
+ set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0,
+ kOptScopeBuf, buf);
assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already
buf->b_p_swf = false;
buf->b_p_ml = false;
@@ -2398,14 +2398,22 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
redraw_buf_range_later(rbuf, first, last);
}
- bool flush = opts->flush;
+ // Redraw later types require update_screen() so call implicitly unless set to false.
+ if (HAS_KEY(opts, redraw, valid) || HAS_KEY(opts, redraw, range)) {
+ opts->flush = HAS_KEY(opts, redraw, flush) ? opts->flush : true;
+ }
+
+ // When explicitly set to false and only "redraw later" types are present,
+ // don't call ui_flush() either.
+ bool flush_ui = opts->flush;
if (opts->tabline) {
// Flush later in case tabline was just hidden or shown for the first time.
if (redraw_tabline && firstwin->w_lines_valid == 0) {
- flush = true;
+ opts->flush = true;
} else {
draw_tabline();
}
+ flush_ui = true;
}
bool save_lz = p_lz;
@@ -2416,31 +2424,35 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
if (win == NULL) {
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (buf == NULL || wp->w_buffer == buf) {
- redraw_status(wp, opts, &flush);
+ redraw_status(wp, opts, &opts->flush);
}
}
} else {
- redraw_status(win, opts, &flush);
+ redraw_status(win, opts, &opts->flush);
}
+ flush_ui = true;
}
win_T *cwin = win ? win : curwin;
// Allow moving cursor to recently opened window and make sure it is drawn #28868.
if (opts->cursor && (!cwin->w_grid.target || !cwin->w_grid.target->valid)) {
- flush = true;
+ opts->flush = true;
}
// Redraw pending screen updates when explicitly requested or when determined
// that it is necessary to properly draw other requested components.
- if (flush && !cmdpreview) {
+ if (opts->flush && !cmdpreview) {
update_screen();
}
if (opts->cursor) {
setcursor_mayforce(cwin, true);
+ flush_ui = true;
}
- ui_flush();
+ if (flush_ui) {
+ ui_flush();
+ }
RedrawingDisabled = save_rd;
p_lz = save_lz;
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 16811e0cd9..6f5a9a90c0 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -130,7 +130,7 @@
/// - focusable: Enable focus by user actions (wincmds, mouse events).
/// Defaults to true. Non-focusable windows can be entered by
/// |nvim_set_current_win()|, or, when the `mouse` field is set to true,
-/// by mouse events.
+/// by mouse events. See |focusable|.
/// - mouse: Specify how this window interacts with mouse events.
/// Defaults to `focusable` value.
/// - If false, mouse events pass through this window.
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index abcce0dfe8..1908516e85 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -2819,6 +2819,7 @@ void buflist_list(exarg_T *eap)
garray_T buflist;
buf_T **buflist_data = NULL;
+ msg_ext_set_kind("list_cmd");
if (vim_strchr(eap->arg, 't')) {
ga_init(&buflist, sizeof(buf_T *), 50);
for (buf = firstbuf; buf != NULL; buf = buf->b_next) {
@@ -3341,96 +3342,11 @@ void maketitle(void)
title_str = p_titlestring;
}
} else {
- // Format: "fname + (path) (1 of 2) - VIM".
-
-#define SPACE_FOR_FNAME (sizeof(buf) - 100)
-#define SPACE_FOR_DIR (sizeof(buf) - 20)
-#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - Nvim".
- char *buf_p = buf;
- if (curbuf->b_fname == NULL) {
- const size_t size = xstrlcpy(buf_p, _("[No Name]"),
- SPACE_FOR_FNAME + 1);
- buf_p += MIN(size, SPACE_FOR_FNAME);
- } else {
- buf_p += transstr_buf(path_tail(curbuf->b_fname), -1, buf_p, SPACE_FOR_FNAME + 1, true);
- }
-
- switch (bufIsChanged(curbuf)
- | (curbuf->b_p_ro << 1)
- | (!MODIFIABLE(curbuf) << 2)) {
- case 0:
- break;
- case 1:
- buf_p = strappend(buf_p, " +"); break;
- case 2:
- buf_p = strappend(buf_p, " ="); break;
- case 3:
- buf_p = strappend(buf_p, " =+"); break;
- case 4:
- case 6:
- buf_p = strappend(buf_p, " -"); break;
- case 5:
- case 7:
- buf_p = strappend(buf_p, " -+"); break;
- default:
- abort();
- }
-
- if (curbuf->b_fname != NULL) {
- // Get path of file, replace home dir with ~.
- *buf_p++ = ' ';
- *buf_p++ = '(';
- home_replace(curbuf, curbuf->b_ffname, buf_p,
- (SPACE_FOR_DIR - (size_t)(buf_p - buf)), true);
-#ifdef BACKSLASH_IN_FILENAME
- // Avoid "c:/name" to be reduced to "c".
- if (isalpha((uint8_t)(*buf_p)) && *(buf_p + 1) == ':') {
- buf_p += 2;
- }
-#endif
- // Remove the file name.
- char *p = path_tail_with_sep(buf_p);
- if (p == buf_p) {
- // Must be a help buffer.
- xstrlcpy(buf_p, _("help"), SPACE_FOR_DIR - (size_t)(buf_p - buf));
- } else {
- *p = NUL;
- }
-
- // Translate unprintable chars and concatenate. Keep some
- // room for the server name. When there is no room (very long
- // file name) use (...).
- if ((size_t)(buf_p - buf) < SPACE_FOR_DIR) {
- char *const tbuf = transstr(buf_p, true);
- const size_t free_space = SPACE_FOR_DIR - (size_t)(buf_p - buf) + 1;
- const size_t dir_len = xstrlcpy(buf_p, tbuf, free_space);
- buf_p += MIN(dir_len, free_space - 1);
- xfree(tbuf);
- } else {
- const size_t free_space = SPACE_FOR_ARGNR - (size_t)(buf_p - buf) + 1;
- const size_t dots_len = xstrlcpy(buf_p, "...", free_space);
- buf_p += MIN(dots_len, free_space - 1);
- }
- *buf_p++ = ')';
- *buf_p = NUL;
- } else {
- *buf_p = NUL;
- }
-
- append_arg_number(curwin, buf_p, (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf)));
-
- xstrlcat(buf_p, " - Nvim", (sizeof(buf) - (size_t)(buf_p - buf)));
-
- if (maxlen > 0) {
- // Make it shorter by removing a bit in the middle.
- if (vim_strsize(buf) > maxlen) {
- trunc_string(buf, buf, maxlen, sizeof(buf));
- }
- }
+ // Format: "fname + (path) (1 of 2) - Nvim".
+ char *default_titlestring = "%t%( %M%)%( (%{expand(\"%:~:h\")})%)%a - Nvim";
+ build_stl_str_hl(curwin, buf, sizeof(buf), default_titlestring,
+ kOptTitlestring, 0, 0, maxlen, NULL, NULL, NULL, NULL);
title_str = buf;
-#undef SPACE_FOR_FNAME
-#undef SPACE_FOR_DIR
-#undef SPACE_FOR_ARGNR
}
}
bool mustset = value_change(title_str, &lasttitle);
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index e6bd63f4f8..d33734ccfe 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -206,7 +206,7 @@ typedef struct {
OptInt wo_winbl;
#define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend'
- LastSet wo_script_ctx[WV_COUNT]; // SCTXs for window-local options
+ LastSet wo_script_ctx[kWinOptCount]; // SCTXs for window-local options
#define w_p_script_ctx w_onebuf_opt.wo_script_ctx
} winopt_T;
@@ -512,7 +512,7 @@ struct file_buffer {
// or contents of the file being edited.
bool b_p_initialized; // set when options initialized
- LastSet b_p_script_ctx[BV_COUNT]; // SCTXs for buffer-local options
+ LastSet b_p_script_ctx[kBufOptCount]; // SCTXs for buffer-local options
int b_p_ai; ///< 'autoindent'
int b_p_ai_nopaste; ///< b_p_ai saved for paste mode
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 700d554821..9b1193b4e0 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -1084,6 +1084,7 @@ int showmatches(expand_T *xp, bool wildmenu)
ui_flush();
cmdline_row = msg_row;
msg_didany = false; // lines_left will be set again
+ msg_ext_set_kind("wildlist");
msg_start(); // prepare for paging
}
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index a690c70875..f1dd08f0e6 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -1390,8 +1390,8 @@ void diff_win_options(win_T *wp, bool addbuf)
}
wp->w_p_fdm_save = xstrdup(wp->w_p_fdm);
}
- set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), OPT_LOCAL, 0, kOptReqWin,
- wp);
+ set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), OPT_LOCAL, 0,
+ kOptScopeWin, wp);
if (!wp->w_p_diff) {
wp->w_p_fen_save = wp->w_p_fen;
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 9acbc05fdf..35f0bde871 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -922,13 +922,12 @@ int eval_expr_typval(const typval_T *expr, bool want_func, typval_T *argv, int a
{
if (expr->v_type == VAR_PARTIAL) {
return eval_expr_partial(expr, argv, argc, rettv);
- } else if (expr->v_type == VAR_FUNC || want_func) {
+ }
+ if (expr->v_type == VAR_FUNC || want_func) {
return eval_expr_func(expr, argv, argc, rettv);
- } else {
- return eval_expr_string(expr, rettv);
}
- return OK;
+ return eval_expr_string(expr, rettv);
}
/// Like eval_to_bool() but using a typval_T instead of a string.
@@ -1368,7 +1367,7 @@ int eval_foldexpr(win_T *wp, int *cp)
const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL);
char *arg = skipwhite(wp->w_p_fde);
- current_sctx = wp->w_p_script_ctx[WV_FDE].script_ctx;
+ current_sctx = wp->w_p_script_ctx[kWinOptFoldexpr].script_ctx;
emsg_off++;
if (use_sandbox) {
@@ -1982,7 +1981,7 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, bool copy, const bool
// handle +=, -=, *=, /=, %= and .=
di = NULL;
- if (eval_variable(lp->ll_name, (int)strlen(lp->ll_name),
+ if (eval_variable(lp->ll_name, (int)lp->ll_name_len,
&tv, &di, true, false) == OK) {
if ((di == NULL
|| (!var_check_ro(di->di_flags, lp->ll_name, TV_CSTRING)
@@ -6857,11 +6856,11 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex
char *temp_result = eval_to_string(expr_start + 1, false, false);
if (temp_result != NULL) {
- retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start)
- + (size_t)(in_end - expr_end) + 1);
- STRCPY(retval, in_start);
- strcat(retval, temp_result);
- strcat(retval, expr_end + 1);
+ size_t retvalsize = (size_t)(expr_start - in_start)
+ + strlen(temp_result)
+ + (size_t)(in_end - expr_end) + 1;
+ retval = xmalloc(retvalsize);
+ vim_snprintf(retval, retvalsize, "%s%s%s", in_start, temp_result, expr_end + 1);
}
xfree(temp_result);
@@ -7881,7 +7880,7 @@ void ex_echo(exarg_T *eap)
char *tofree = encode_tv2echo(&rettv, NULL);
if (*tofree != NUL) {
msg_ext_set_kind("echo");
- msg_multiline(tofree, echo_hl_id, true, false, &need_clear);
+ msg_multiline(cstr_as_string(tofree), echo_hl_id, true, false, &need_clear);
}
xfree(tofree);
}
@@ -8350,9 +8349,10 @@ repeat:
char *const sub = xmemdupz(s, (size_t)(p - s));
char *const str = xmemdupz(*fnamep, *fnamelen);
*usedlen = (size_t)(p + 1 - src);
- s = do_string_sub(str, pat, sub, NULL, flags);
+ size_t slen;
+ s = do_string_sub(str, *fnamelen, pat, sub, NULL, flags, &slen);
*fnamep = s;
- *fnamelen = strlen(s);
+ *fnamelen = slen;
xfree(*bufp);
*bufp = s;
didit = true;
@@ -8391,12 +8391,14 @@ repeat:
/// When "sub" is NULL "expr" is used, must be a VAR_FUNC or VAR_PARTIAL.
/// "flags" can be "g" to do a global substitute.
///
+/// @param ret_len length of returned buffer
+///
/// @return an allocated string, NULL for error.
-char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char *flags)
+char *do_string_sub(char *str, size_t len, char *pat, char *sub, typval_T *expr, const char *flags,
+ size_t *ret_len)
{
regmatch_T regmatch;
garray_T ga;
- char *zero_width = NULL;
// Make 'cpoptions' empty, so that the 'l' flag doesn't work here
char *save_cpo = p_cpo;
@@ -8404,14 +8406,15 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
ga_init(&ga, 1, 200);
- int do_all = (flags[0] == 'g');
-
regmatch.rm_ic = p_ic;
regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
if (regmatch.regprog != NULL) {
- int sublen;
char *tail = str;
- char *end = str + strlen(str);
+ char *end = str + len;
+ bool do_all = (flags[0] == 'g');
+ int sublen;
+ char *zero_width = NULL;
+
while (vim_regexec_nl(&regmatch, str, (colnr_T)(tail - str))) {
// Skip empty match except for first match.
if (regmatch.startp[0] == regmatch.endp[0]) {
@@ -8458,12 +8461,17 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
if (ga.ga_data != NULL) {
STRCPY((char *)ga.ga_data + ga.ga_len, tail);
+ ga.ga_len += (int)(end - tail);
}
vim_regfree(regmatch.regprog);
}
- char *ret = xstrdup(ga.ga_data == NULL ? str : ga.ga_data);
+ if (ga.ga_data != NULL) {
+ str = ga.ga_data;
+ len = (size_t)ga.ga_len;
+ }
+ char *ret = xstrnsave(str, len);
ga_clear(&ga);
if (p_cpo == empty_string_option) {
p_cpo = save_cpo;
@@ -8477,6 +8485,10 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
free_string_option(save_cpo);
}
+ if (ret_len != NULL) {
+ *ret_len = len;
+ }
+
return ret;
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 4828d67428..f700e732a9 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -3540,6 +3540,7 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
+ msg_ext_set_kind("list_cmd");
msg_start();
msg_row = Rows - 1; // for when 'cmdheight' > 1
lines_left = Rows; // avoid more prompt
@@ -7848,8 +7849,8 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|| flg == NULL) {
rettv->vval.v_string = NULL;
} else {
- rettv->vval.v_string = do_string_sub((char *)str, (char *)pat,
- (char *)sub, expr, (char *)flg);
+ rettv->vval.v_string = do_string_sub((char *)str, strlen(str), (char *)pat,
+ (char *)sub, expr, (char *)flg, NULL);
}
}
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 35ad00f373..3ecb446cd6 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -1403,6 +1403,7 @@ static void list_one_var(dictitem_T *v, const char *prefix, int *first)
static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t name_len,
const VarType type, const char *string, int *first)
{
+ msg_ext_set_kind("list_cmd");
// don't use msg() to avoid overwriting "v:statusmsg"
msg_start();
msg_puts(prefix);
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index e937961b44..8cccf08e11 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -189,7 +189,7 @@ void do_ascii(exarg_T *eap)
transchar(c), buf1, buf2, cval, cval, cval);
}
- msg_multiline(IObuff, 0, true, false, &need_clear);
+ msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear);
off += (size_t)utf_ptr2len(data); // needed for overlong ascii?
}
@@ -224,7 +224,7 @@ void do_ascii(exarg_T *eap)
c, c, c);
}
- msg_multiline(IObuff, 0, true, false, &need_clear);
+ msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear);
off += (size_t)utf_ptr2len(data + off); // needed for overlong ascii?
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index e8b9470391..9968f32de1 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -980,8 +980,6 @@ void handle_did_throw(void)
force_abort = true;
}
- msg_ext_set_kind("emsg"); // kind=emsg for :throw, exceptions. #9993
-
if (messages != NULL) {
do {
msglist_T *next = messages->next;
@@ -5507,6 +5505,8 @@ static void ex_tabs(exarg_T *eap)
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
if (got_int) {
break;
+ } else if (!wp->w_config.focusable) {
+ continue;
}
msg_putchar('\n');
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index aeaf448a05..d183978d2d 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1648,7 +1648,7 @@ static char *eval_includeexpr(const char *const ptr, const size_t len)
{
const sctx_T save_sctx = current_sctx;
set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
- current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx;
+ current_sctx = curbuf->b_p_script_ctx[kBufOptIncludeexpr].script_ctx;
char *res = eval_to_string_safe(curbuf->b_p_inex,
was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL),
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index e7231c31ab..c9699cb161 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -1731,7 +1731,7 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo
curwin = wp;
curbuf = wp->w_buffer;
- current_sctx = wp->w_p_script_ctx[WV_FDT].script_ctx;
+ current_sctx = wp->w_p_script_ctx[kWinOptFoldtext].script_ctx;
emsg_off++; // handle exceptions, but don't display errors
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index 92349b5298..02f3ac3257 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -1,6 +1,10 @@
local options_file = arg[1]
+local options_enum_file = arg[2]
+local options_map_file = arg[3]
local opt_fd = assert(io.open(options_file, 'w'))
+local opt_enum_fd = assert(io.open(options_enum_file, 'w'))
+local opt_map_fd = assert(io.open(options_map_file, 'w'))
local w = function(s)
if s:match('^ %.') then
@@ -10,10 +14,129 @@ local w = function(s)
end
end
+--- @param s string
+local function enum_w(s)
+ opt_enum_fd:write(s .. '\n')
+end
+
+--- @param s string
+local function map_w(s)
+ opt_map_fd:write(s .. '\n')
+end
+
--- @module 'nvim.options'
local options = require('options')
+local options_meta = options.options
local cstr = options.cstr
+local valid_scopes = options.valid_scopes
+
+--- Options for each scope.
+--- @type table<string, vim.option_meta[]>
+local scope_options = {}
+for _, scope in ipairs(valid_scopes) do
+ scope_options[scope] = {}
+end
+
+--- @param s string
+--- @return string
+local lowercase_to_titlecase = function(s)
+ return s:sub(1, 1):upper() .. s:sub(2)
+end
+
+-- Generate options enum file
+enum_w('// IWYU pragma: private, include "nvim/option_defs.h"')
+enum_w('')
+
+--- Map of option name to option index
+--- @type table<string, string>
+local option_index = {}
+
+-- Generate option index enum and populate the `option_index` and `scope_option` dicts.
+enum_w('typedef enum {')
+enum_w(' kOptInvalid = -1,')
+
+for i, o in ipairs(options_meta) do
+ local enum_val_name = 'kOpt' .. lowercase_to_titlecase(o.full_name)
+ enum_w((' %s = %u,'):format(enum_val_name, i - 1))
+
+ option_index[o.full_name] = enum_val_name
+
+ if o.abbreviation then
+ option_index[o.abbreviation] = enum_val_name
+ end
+
+ if o.alias then
+ o.alias = type(o.alias) == 'string' and { o.alias } or o.alias
+
+ for _, v in ipairs(o.alias) do
+ option_index[v] = enum_val_name
+ end
+ end
+
+ for _, scope in ipairs(o.scope) do
+ table.insert(scope_options[scope], o)
+ end
+end
+
+enum_w(' // Option count')
+enum_w('#define kOptCount ' .. tostring(#options_meta))
+enum_w('} OptIndex;')
+
+--- @param scope string
+--- @param option_name string
+--- @return string
+local get_scope_option = function(scope, option_name)
+ return ('k%sOpt%s'):format(lowercase_to_titlecase(scope), lowercase_to_titlecase(option_name))
+end
+
+-- Generate option index enum for each scope
+for _, scope in ipairs(valid_scopes) do
+ enum_w('')
+
+ local scope_name = lowercase_to_titlecase(scope)
+ enum_w('typedef enum {')
+ enum_w((' %s = -1,'):format(get_scope_option(scope, 'Invalid')))
+
+ for idx, option in ipairs(scope_options[scope]) do
+ enum_w((' %s = %u,'):format(get_scope_option(scope, option.full_name), idx - 1))
+ end
+
+ enum_w((' // %s option count'):format(scope_name))
+ enum_w(('#define %s %d'):format(get_scope_option(scope, 'Count'), #scope_options[scope]))
+ enum_w(('} %sOptIndex;'):format(scope_name))
+end
+
+-- Generate reverse lookup from option scope index to option index for each scope.
+for _, scope in ipairs(valid_scopes) do
+ enum_w('')
+ enum_w(('EXTERN const OptIndex %s_opt_idx[] INIT( = {'):format(scope))
+ for _, option in ipairs(scope_options[scope]) do
+ local idx = option_index[option.full_name]
+ enum_w((' [%s] = %s,'):format(get_scope_option(scope, option.full_name), idx))
+ end
+ enum_w('});')
+end
+
+opt_enum_fd:close()
+
+-- Generate option index map.
+local hashy = require('generators.hashy')
+local neworder, hashfun = hashy.hashy_hash('find_option', vim.tbl_keys(option_index), function(idx)
+ return ('option_hash_elems[%s].name'):format(idx)
+end)
+
+map_w('static const struct { const char *name; OptIndex opt_idx; } option_hash_elems[] = {')
+
+for _, name in ipairs(neworder) do
+ assert(option_index[name] ~= nil)
+ map_w((' { .name = "%s", .opt_idx = %s },'):format(name, option_index[name]))
+end
+
+map_w('};\n')
+map_w('static ' .. hashfun)
+
+opt_map_fd:close()
local redraw_flags = {
ui_option = 'kOptFlagUIOption',
@@ -35,12 +158,6 @@ local list_flags = {
flagscomma = 'kOptFlagComma|kOptFlagFlagList',
}
---- @param s string
---- @return string
-local lowercase_to_titlecase = function(s)
- return s:sub(1, 1):upper() .. s:sub(2)
-end
-
--- @param o vim.option_meta
--- @return string
local function get_flags(o)
@@ -95,6 +212,12 @@ local function opt_type_enum(opt_type)
return ('kOptValType%s'):format(lowercase_to_titlecase(opt_type))
end
+--- @param scope vim.option_scope
+--- @return string
+local function opt_scope_enum(scope)
+ return ('kOptScope%s'):format(lowercase_to_titlecase(scope))
+end
+
--- @param o vim.option_meta
--- @return string
local function get_type_flags(o)
@@ -110,6 +233,35 @@ local function get_type_flags(o)
return type_flags
end
+--- @param o vim.option_meta
+--- @return string
+local function get_scope_flags(o)
+ local scope_flags = '0'
+
+ for _, scope in ipairs(o.scope) do
+ scope_flags = ('%s | (1 << %s)'):format(scope_flags, opt_scope_enum(scope))
+ end
+
+ return scope_flags
+end
+
+--- @param o vim.option_meta
+--- @return string
+local function get_scope_idx(o)
+ --- @type string[]
+ local strs = {}
+
+ for _, scope in pairs(valid_scopes) do
+ local has_scope = vim.tbl_contains(o.scope, scope)
+ strs[#strs + 1] = (' [%s] = %s'):format(
+ opt_scope_enum(scope),
+ get_scope_option(scope, has_scope and o.full_name or 'Invalid')
+ )
+ end
+
+ return ('{\n%s\n }'):format(table.concat(strs, ',\n'))
+end
+
--- @param c string|string[]
--- @param base_string? string
--- @return string
@@ -166,7 +318,6 @@ end
--- @param d vim.option_value|function
--- @param n string
--- @return string
-
local get_defaults = function(d, n)
if d == nil then
error("option '" .. n .. "' should have a default value")
@@ -174,9 +325,6 @@ local get_defaults = function(d, n)
return get_opt_val(d)
end
---- @type [string,string][]
-local defines = {}
-
--- @param i integer
--- @param o vim.option_meta
local function dump_option(i, o)
@@ -187,42 +335,28 @@ local function dump_option(i, o)
end
w(' .flags=' .. get_flags(o))
w(' .type_flags=' .. get_type_flags(o))
+ w(' .scope_flags=' .. get_scope_flags(o))
+ w(' .scope_idx=' .. get_scope_idx(o))
if o.enable_if then
w(get_cond(o.enable_if))
end
- if o.varname then
- w(' .var=&' .. o.varname)
- elseif o.immutable then
- -- Immutable options can directly point to the default value.
- w((' .var=&options[%u].def_val.data'):format(i - 1))
- elseif #o.scope == 1 and o.scope[1] == 'window' then
- w(' .var=VAR_WIN')
+ local is_window_local = #o.scope == 1 and o.scope[1] == 'win'
+
+ if not is_window_local then
+ if o.varname then
+ w(' .var=&' .. o.varname)
+ elseif o.immutable then
+ -- Immutable options can directly point to the default value.
+ w((' .var=&options[%u].def_val.data'):format(i - 1))
+ else
+ -- Option must be immutable or have a variable.
+ assert(false)
+ end
else
- -- Option must be immutable or have a variable.
- assert(false)
+ w(' .var=NULL')
end
w(' .immutable=' .. (o.immutable and 'true' or 'false'))
- if #o.scope == 1 and o.scope[1] == 'global' then
- w(' .indir=PV_NONE')
- else
- assert(#o.scope == 1 or #o.scope == 2)
- assert(#o.scope == 1 or o.scope[1] == 'global')
- local min_scope = o.scope[#o.scope]
- local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name))
- local pv_name = (
- 'OPT_'
- .. min_scope:sub(1, 3):upper()
- .. '('
- .. (min_scope:sub(1, 1):upper() .. 'V_' .. varname:sub(3):upper())
- .. ')'
- )
- if #o.scope == 2 then
- pv_name = 'OPT_BOTH(' .. pv_name .. ')'
- end
- table.insert(defines, { 'PV_' .. varname:sub(3):upper(), pv_name })
- w(' .indir=' .. pv_name)
- end
if o.cb then
w(' .opt_did_set_cb=' .. o.cb)
end
@@ -235,7 +369,6 @@ local function dump_option(i, o)
w((' .var=&options[%u].def_val.data'):format(i - 1))
-- Option is always immutable on the false branch of `enable_if`.
w(' .immutable=true')
- w(' .indir=PV_NONE')
w('#endif')
end
if o.defaults then
@@ -256,6 +389,7 @@ local function dump_option(i, o)
w(' },')
end
+-- Generate options[] array.
w([[
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
@@ -274,8 +408,3 @@ for i, o in ipairs(options.options) do
dump_option(i, o)
end
w('};')
-w('')
-
-for _, v in ipairs(defines) do
- w('#define ' .. v[1] .. ' ' .. v[2])
-end
diff --git a/src/nvim/generators/gen_options_enum.lua b/src/nvim/generators/gen_options_enum.lua
deleted file mode 100644
index d1419137d3..0000000000
--- a/src/nvim/generators/gen_options_enum.lua
+++ /dev/null
@@ -1,129 +0,0 @@
--- Generates option index enum and map of option name to option index.
--- Handles option full name, short name and aliases.
--- Also generates BV_ and WV_ enum constants.
-
-local options_enum_file = arg[1]
-local options_map_file = arg[2]
-local options_enum_fd = assert(io.open(options_enum_file, 'w'))
-local options_map_fd = assert(io.open(options_map_file, 'w'))
-
---- @param s string
-local function enum_w(s)
- options_enum_fd:write(s .. '\n')
-end
-
---- @param s string
-local function map_w(s)
- options_map_fd:write(s .. '\n')
-end
-
-enum_w('// IWYU pragma: private, include "nvim/option_defs.h"')
-enum_w('')
-
---- @param s string
---- @return string
-local lowercase_to_titlecase = function(s)
- return s:sub(1, 1):upper() .. s:sub(2)
-end
-
---- @type vim.option_meta[]
-local options = require('options').options
-
--- Generate BV_ enum constants.
-enum_w('/// "indir" values for buffer-local options.')
-enum_w('/// These need to be defined globally, so that the BV_COUNT can be used with')
-enum_w('/// b_p_script_stx[].')
-enum_w('enum {')
-
-local bv_val = 0
-
-for _, o in ipairs(options) do
- assert(#o.scope == 1 or #o.scope == 2)
- assert(#o.scope == 1 or o.scope[1] == 'global')
- local min_scope = o.scope[#o.scope]
- if min_scope == 'buffer' then
- local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name))
- local bv_name = 'BV_' .. varname:sub(3):upper()
- enum_w((' %s = %u,'):format(bv_name, bv_val))
- bv_val = bv_val + 1
- end
-end
-
-enum_w((' BV_COUNT = %u, ///< must be the last one'):format(bv_val))
-enum_w('};')
-enum_w('')
-
--- Generate WV_ enum constants.
-enum_w('/// "indir" values for window-local options.')
-enum_w('/// These need to be defined globally, so that the WV_COUNT can be used in the')
-enum_w('/// window structure.')
-enum_w('enum {')
-
-local wv_val = 0
-
-for _, o in ipairs(options) do
- assert(#o.scope == 1 or #o.scope == 2)
- assert(#o.scope == 1 or o.scope[1] == 'global')
- local min_scope = o.scope[#o.scope]
- if min_scope == 'window' then
- local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name))
- local wv_name = 'WV_' .. varname:sub(3):upper()
- enum_w((' %s = %u,'):format(wv_name, wv_val))
- wv_val = wv_val + 1
- end
-end
-
-enum_w((' WV_COUNT = %u, ///< must be the last one'):format(wv_val))
-enum_w('};')
-enum_w('')
-
---- @type { [string]: string }
-local option_index = {}
-
--- Generate option index enum and populate the `option_index` dict.
-enum_w('typedef enum {')
-enum_w(' kOptInvalid = -1,')
-
-for i, o in ipairs(options) do
- local enum_val_name = 'kOpt' .. lowercase_to_titlecase(o.full_name)
- enum_w((' %s = %u,'):format(enum_val_name, i - 1))
-
- option_index[o.full_name] = enum_val_name
-
- if o.abbreviation then
- option_index[o.abbreviation] = enum_val_name
- end
-
- if o.alias then
- o.alias = type(o.alias) == 'string' and { o.alias } or o.alias
-
- for _, v in ipairs(o.alias) do
- option_index[v] = enum_val_name
- end
- end
-end
-
-enum_w(' // Option count, used when iterating through options')
-enum_w('#define kOptIndexCount ' .. tostring(#options))
-enum_w('} OptIndex;')
-enum_w('')
-
-options_enum_fd:close()
-
---- Generate option index map.
-local hashy = require('generators.hashy')
-local neworder, hashfun = hashy.hashy_hash('find_option', vim.tbl_keys(option_index), function(idx)
- return ('option_hash_elems[%s].name'):format(idx)
-end)
-
-map_w('static const struct { const char *name; OptIndex opt_idx; } option_hash_elems[] = {')
-
-for _, name in ipairs(neworder) do
- assert(option_index[name] ~= nil)
- map_w((' { .name = "%s", .opt_idx = %s },'):format(name, option_index[name]))
-end
-
-map_w('};\n')
-map_w('static ' .. hashfun)
-
-options_map_fd:close()
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 65641f120f..cc1b833c3c 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -215,6 +215,7 @@ static const char *highlight_init_both[] = {
"default link LspReferenceRead LspReferenceText",
"default link LspReferenceText Visual",
"default link LspReferenceWrite LspReferenceText",
+ "default link LspReferenceTarget LspReferenceText",
"default link LspSignatureActiveParameter Visual",
"default link SnippetTabstop Visual",
@@ -302,7 +303,7 @@ static const char *highlight_init_both[] = {
"default link @tag.builtin Special",
// :help
- // Higlight "===" and "---" heading delimiters specially.
+ // Highlight "===" and "---" heading delimiters specially.
"default @markup.heading.1.delimiter.vimdoc guibg=bg guifg=bg guisp=fg gui=underdouble,nocombine ctermbg=NONE ctermfg=NONE cterm=underdouble,nocombine",
"default @markup.heading.2.delimiter.vimdoc guibg=bg guifg=bg guisp=fg gui=underline,nocombine ctermbg=NONE ctermfg=NONE cterm=underline,nocombine",
@@ -1000,6 +1001,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
{
// If no argument, list current highlighting.
if (!init && ends_excmd((uint8_t)(*line))) {
+ msg_ext_set_kind("list_cmd");
for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
// TODO(brammool): only call when the group has attributes set
highlight_list_one(i);
@@ -1037,6 +1039,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (id == 0) {
semsg(_(e_highlight_group_name_not_found_str), line);
} else {
+ msg_ext_set_kind("list_cmd");
highlight_list_one(id);
}
return;
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 58215f738c..e487728901 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -1182,7 +1182,7 @@ int get_expr_indent(void)
sandbox++;
}
textlock++;
- current_sctx = curbuf->b_p_script_ctx[BV_INDE].script_ctx;
+ current_sctx = curbuf->b_p_script_ctx[kBufOptIndentexpr].script_ctx;
// Need to make a copy, the 'indentexpr' option could be changed while
// evaluating it.
diff --git a/src/nvim/input.c b/src/nvim/input.c
index 3d3240c59f..0c1a8af45f 100644
--- a/src/nvim/input.c
+++ b/src/nvim/input.c
@@ -223,6 +223,7 @@ int get_number(int colon, bool *mouse_used)
/// the line number.
int prompt_for_number(bool *mouse_used)
{
+ msg_ext_set_kind("number_prompt");
// When using ":silent" assume that <CR> was entered.
if (mouse_used != NULL) {
msg_puts(_("Type number and <Enter> or click with the mouse "
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 15f70fb725..c4fa8b0fff 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -954,41 +954,10 @@ static void nlua_common_free_all_mem(lua_State *lstate)
static void nlua_print_event(void **argv)
{
- char *str = argv[0];
- const size_t len = (size_t)(intptr_t)argv[1] - 1; // exclude final NUL
-
- for (size_t i = 0; i < len;) {
- if (got_int) {
- break;
- }
- const size_t start = i;
- while (i < len) {
- switch (str[i]) {
- case NUL:
- str[i] = NL;
- i++;
- continue;
- case NL:
- // TODO(bfredl): use proper multiline msg? Probably should implement
- // print() in lua in terms of nvim_message(), when it is available.
- str[i] = NUL;
- i++;
- break;
- default:
- i++;
- continue;
- }
- break;
- }
- msg(str + start, 0);
- if (msg_silent == 0) {
- msg_didout = true; // Make blank lines work properly
- }
- }
- if (len && str[len - 1] == NUL) { // Last was newline
- msg("", 0);
- }
- xfree(str);
+ HlMessage msg = KV_INITIAL_VALUE;
+ HlMessageChunk chunk = { { .data = argv[0], .size = (size_t)(intptr_t)argv[1] - 1 }, 0 };
+ kv_push(msg, chunk);
+ msg_multihl(msg, "lua_print", true);
}
/// Print as a Vim message
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 1a6b2c3581..1896f042f2 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -581,6 +581,9 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
const bool has_lhs = (args->lhs[0] != NUL);
const bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop;
const bool do_print = !has_lhs || (maptype != MAPTYPE_UNMAP && !has_rhs);
+ if (do_print) {
+ msg_ext_set_kind("list_cmd");
+ }
// check for :unmap without argument
if (maptype == MAPTYPE_UNMAP && !has_lhs) {
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 65f718f925..b5a8588edd 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1119,7 +1119,7 @@ int utf_char2bytes(const int c, char *const buf)
/// stateful algorithm to determine grapheme clusters. Still available
/// to support some legacy code which hasn't been refactored yet.
///
-/// To check if a char would combine with a preceeding space, use
+/// To check if a char would combine with a preceding space, use
/// utf_iscomposing_first() instead.
///
/// Based on code from Markus Kuhn.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index e8f20916b8..c927a2546c 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -249,35 +249,33 @@ bool msg(const char *s, const int hl_id)
return msg_hl_keep(s, hl_id, false, false);
}
-/// Similar to msg_outtrans, but support newlines and tabs.
-void msg_multiline(const char *s, int hl_id, bool check_int, bool hist, bool *need_clear)
+/// Similar to msg_outtrans_len, but support newlines and tabs.
+void msg_multiline(String str, int hl_id, bool check_int, bool hist, bool *need_clear)
FUNC_ATTR_NONNULL_ALL
{
- const char *next_spec = s;
-
- while (next_spec != NULL) {
+ const char *s = str.data;
+ const char *chunk = s;
+ while ((size_t)(s - str.data) < str.size) {
if (check_int && got_int) {
return;
}
- next_spec = strpbrk(s, "\t\n\r");
-
- if (next_spec != NULL) {
- // Printing all char that are before the char found by strpbrk
- msg_outtrans_len(s, (int)(next_spec - s), hl_id, hist);
+ if (*s == '\n' || *s == TAB || *s == '\r') {
+ // Print all chars before the delimiter
+ msg_outtrans_len(chunk, (int)(s - chunk), hl_id, hist);
- if (*next_spec != TAB && *need_clear) {
+ if (*s != TAB && *need_clear) {
msg_clr_eos();
*need_clear = false;
}
- msg_putchar_hl((uint8_t)(*next_spec), hl_id);
- s = next_spec + 1;
+ msg_putchar_hl((uint8_t)(*s), hl_id);
+ chunk = s + 1;
}
+ s++;
}
- // Print the rest of the message. We know there is no special
- // character because strpbrk returned NULL
- if (*s != NUL) {
- msg_outtrans(s, hl_id, hist);
+ // Print the rest of the message
+ if (*chunk != NUL) {
+ msg_outtrans_len(chunk, (int)(str.size - (size_t)(chunk - str.data)), hl_id, hist);
}
}
@@ -290,7 +288,7 @@ void msg_multihl(HlMessage hl_msg, const char *kind, bool history)
msg_ext_set_kind(kind);
for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
HlMessageChunk chunk = kv_A(hl_msg, i);
- msg_multiline(chunk.text.data, chunk.hl_id, true, false, &need_clear);
+ msg_multiline(chunk.text, chunk.hl_id, true, false, &need_clear);
}
if (history && kv_size(hl_msg)) {
add_msg_hist_multihl(NULL, 0, 0, true, hl_msg);
@@ -349,7 +347,7 @@ bool msg_hl_keep(const char *s, int hl_id, bool keep, bool multiline)
bool need_clear = true;
if (multiline) {
- msg_multiline(s, hl_id, false, false, &need_clear);
+ msg_multiline(cstr_as_string(s), hl_id, false, false, &need_clear);
} else {
msg_outtrans(s, hl_id, false);
}
@@ -752,6 +750,10 @@ bool emsg_multiline(const char *s, bool multiline)
msg_scroll = true;
msg_source(hl_id);
+ if (msg_ext_kind == NULL) {
+ msg_ext_set_kind("emsg");
+ }
+
// Display the error message itself.
msg_nowait = false; // Wait for this msg.
return msg_hl_keep(s, hl_id, false, multiline);
@@ -2689,12 +2691,13 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
// primitive way to compute the current column
if (*s == '\r' || *s == '\n') {
msg_col = 0;
+ msg_didout = false;
} else {
msg_col += cw;
+ msg_didout = true;
}
s += len;
}
- msg_didout = true; // assume that line is not empty
}
/// Show the more-prompt and handle the user response.
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 6324466dcc..b298592683 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -150,25 +150,20 @@ static void redraw_for_cursorline(win_T *wp)
}
}
-/// Redraw when w_virtcol changes and
+/// Redraw when 'concealcursor' is active, or when w_virtcol changes and:
/// - 'cursorcolumn' is set, or
/// - 'cursorlineopt' contains "screenline", or
-/// - 'concealcursor' is active, or
/// - Visual mode is active.
static void redraw_for_cursorcolumn(win_T *wp)
FUNC_ATTR_NONNULL_ALL
{
- if (wp->w_valid & VALID_VIRTCOL) {
- return;
- }
-
// If the cursor moves horizontally when 'concealcursor' is active, then the
// current line needs to be redrawn to calculate the correct cursor position.
if (wp->w_p_cole > 0 && conceal_cursor_line(wp)) {
redrawWinline(wp, wp->w_cursor.lnum);
}
- if (pum_visible()) {
+ if ((wp->w_valid & VALID_VIRTCOL) || pum_visible()) {
return;
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index d2716bf236..55aa385b33 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -5249,6 +5249,12 @@ void nv_g_home_m_cmd(cmdarg_T *cap)
curwin->w_valid &= ~VALID_WCOL;
}
curwin->w_set_curswant = true;
+ if (hasAnyFolding(curwin)) {
+ validate_cheight(curwin);
+ if (curwin->w_cline_folded) {
+ update_curswant_force();
+ }
+ }
adjust_skipcol();
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index efd52f9233..1cfe4cd08b 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -228,7 +228,7 @@ static void set_init_default_backupskip(void)
#endif
{
p = vim_getenv(names[i]);
- plen = 0; // will be calcuated below
+ plen = 0; // will be calculated below
}
if (p != NULL && *p != NUL) {
bool has_trailing_path_sep = false;
@@ -303,7 +303,7 @@ static void set_init_default_cdpath(void)
/// them.
static void set_init_expand_env(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
vimoption_T *opt = &options[opt_idx];
if (opt->flags & kOptFlagNoDefExp) {
continue;
@@ -435,7 +435,7 @@ void set_init_1(bool clean_arg)
static OptVal get_option_default(const OptIndex opt_idx, int opt_flags)
{
vimoption_T *opt = &options[opt_idx];
- bool is_global_local_option = opt->indir & PV_BOTH;
+ bool is_global_local_option = option_is_global_local(opt_idx);
#ifdef UNIX
if (opt_idx == kOptModeline && getuid() == ROOT_UID) {
@@ -461,7 +461,7 @@ static OptVal get_option_default(const OptIndex opt_idx, int opt_flags)
/// This ensures that we don't need to always check if the option default is allocated or not.
static void alloc_options_default(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
options[opt_idx].def_val = optval_copy(options[opt_idx].def_val);
}
}
@@ -500,7 +500,7 @@ static void set_option_default(const OptIndex opt_idx, int opt_flags)
/// @param opt_flags Option flags.
static void set_options_default(int opt_flags)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
if (!(options[opt_idx].flags & kOptFlagNoDefault)) {
set_option_default(opt_idx, opt_flags);
}
@@ -564,16 +564,16 @@ static char *find_dup_item(char *origval, const char *newval, const size_t newva
/// Free all options.
void free_all_options(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
bool hidden = is_option_hidden(opt_idx);
- if (options[opt_idx].indir == PV_NONE || hidden) {
+ if (option_is_global_only(opt_idx) || hidden) {
// global option: free value and default value.
// hidden option: free default value only.
if (!hidden) {
optval_free(optval_from_varp(opt_idx, options[opt_idx].var));
}
- } else if (options[opt_idx].var != VAR_WIN) {
+ } else if (!option_is_window_local(opt_idx)) {
// buffer-local option: free global value.
optval_free(optval_from_varp(opt_idx, options[opt_idx].var));
}
@@ -977,12 +977,12 @@ static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_
// Skip all options that are not window-local (used when showing
// an already loaded buffer in a window).
- if ((opt_flags & OPT_WINONLY) && (opt_idx == kOptInvalid || options[opt_idx].var != VAR_WIN)) {
+ if ((opt_flags & OPT_WINONLY) && (opt_idx == kOptInvalid || !option_is_window_local(opt_idx))) {
return FAIL;
}
// Skip all options that are window-local (used for :vimgrep).
- if ((opt_flags & OPT_NOWIN) && opt_idx != kOptInvalid && options[opt_idx].var == VAR_WIN) {
+ if ((opt_flags & OPT_NOWIN) && opt_idx != kOptInvalid && option_is_window_local(opt_idx)) {
return FAIL;
}
@@ -999,10 +999,7 @@ static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_
// In diff mode some options are overruled. This avoids that
// 'foldmethod' becomes "marker" instead of "diff" and that
// "wrap" gets set.
- if (win->w_p_diff
- && opt_idx != kOptInvalid // shut up coverity warning
- && (options[opt_idx].indir == PV_FDM
- || options[opt_idx].indir == PV_WRAP)) {
+ if (win->w_p_diff && (opt_idx == kOptFoldmethod || opt_idx == kOptWrap)) {
return FAIL;
}
}
@@ -1099,7 +1096,7 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr
vimoption_T *opt = &options[opt_idx];
char *arg = *argp;
// When setting the local value of a global option, the old value may be the global value.
- const bool oldval_is_global = ((int)opt->indir & PV_BOTH) && (opt_flags & OPT_LOCAL);
+ const bool oldval_is_global = option_is_global_local(opt_idx) && (opt_flags & OPT_LOCAL);
OptVal oldval = optval_from_varp(opt_idx, oldval_is_global ? get_varp(opt) : varp);
OptVal newval = NIL_OPTVAL;
@@ -1279,16 +1276,17 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
gotocmdline(true); // cursor at status line
*did_show = true; // remember that we did a line
}
+ msg_ext_set_kind("list_cmd");
showoneopt(&options[opt_idx], opt_flags);
if (p_verbose > 0) {
// Mention where the option was last set.
if (varp == options[opt_idx].var) {
option_last_set_msg(options[opt_idx].last_set);
- } else if ((int)options[opt_idx].indir & PV_WIN) {
- option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]);
- } else if ((int)options[opt_idx].indir & PV_BUF) {
- option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]);
+ } else if (option_has_scope(opt_idx, kOptScopeWin)) {
+ option_last_set_msg(curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)]);
+ } else if (option_has_scope(opt_idx, kOptScopeBuf)) {
+ option_last_set_msg(curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)]);
}
}
@@ -1643,7 +1641,7 @@ static void didset_options2(void)
/// Check for string options that are NULL (normally only termcap options).
void check_options(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
if ((option_has_type(opt_idx, kOptValTypeString)) && options[opt_idx].var != NULL) {
check_string_option((char **)get_varp(&(options[opt_idx])));
}
@@ -1673,24 +1671,25 @@ uint32_t *insecure_flag(win_T *const wp, OptIndex opt_idx, int opt_flags)
{
if (opt_flags & OPT_LOCAL) {
assert(wp != NULL);
- switch ((int)options[opt_idx].indir) {
- case PV_STL:
+ switch (opt_idx) {
+ case kOptStatusline:
return &wp->w_p_stl_flags;
- case PV_WBR:
+ case kOptWinbar:
return &wp->w_p_wbr_flags;
- case PV_FDE:
+ case kOptFoldexpr:
return &wp->w_p_fde_flags;
- case PV_FDT:
+ case kOptFoldtext:
return &wp->w_p_fdt_flags;
- case PV_INDE:
+ case kOptIndentexpr:
return &wp->w_buffer->b_p_inde_flags;
- case PV_FEX:
+ case kOptFormatexpr:
return &wp->w_buffer->b_p_fex_flags;
- case PV_INEX:
+ case kOptIncludeexpr:
return &wp->w_buffer->b_p_inex_flags;
+ default:
+ break;
}
}
-
// Nothing special, return global flags field.
return &options[opt_idx].flags;
}
@@ -1804,7 +1803,6 @@ sctx_T *get_option_sctx(OptIndex opt_idx)
void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx)
{
bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
- int indir = (int)options[opt_idx].indir;
nlua_set_sctx(&script_ctx);
LastSet last_set = {
.script_ctx = script_ctx,
@@ -1818,17 +1816,17 @@ void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx)
// Remember where the option was set. For local options need to do that
// in the buffer or window structure.
- if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) {
+ if (both || (opt_flags & OPT_GLOBAL) || option_is_global_only(opt_idx)) {
options[opt_idx].last_set = last_set;
}
if (both || (opt_flags & OPT_LOCAL)) {
- if (indir & PV_BUF) {
- curbuf->b_p_script_ctx[indir & PV_MASK] = last_set;
- } else if (indir & PV_WIN) {
- curwin->w_p_script_ctx[indir & PV_MASK] = last_set;
+ if (option_has_scope(opt_idx, kOptScopeBuf)) {
+ curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)] = last_set;
+ } else if ((option_has_scope(opt_idx, kOptScopeWin))) {
+ curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = last_set;
if (both) {
// also setting the "all buffers" value
- curwin->w_allbuf_opt.wo_script_ctx[indir & PV_MASK] = last_set;
+ curwin->w_allbuf_opt.wo_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = last_set;
}
}
}
@@ -3267,7 +3265,7 @@ OptVal object_as_optval(Object o, bool *error)
/// Get an allocated string containing a list of valid types for an option.
/// For options with a singular type, it returns the name of the type. For options with multiple
/// possible types, it returns a slash separated list of types. For example, if an option can be a
-/// number, boolean or string, the function returns "Number/Boolean/String"
+/// number, boolean or string, the function returns "number/boolean/string"
static char *option_get_valid_types(OptIndex opt_idx)
{
StringBuilder str = KV_INITIAL_VALUE;
@@ -3299,14 +3297,73 @@ static char *option_get_valid_types(OptIndex opt_idx)
bool is_option_hidden(OptIndex opt_idx)
{
// Hidden options are always immutable and point to their default value
- return opt_idx == kOptInvalid
- ? false
- : (options[opt_idx].immutable && options[opt_idx].var == &options[opt_idx].def_val.data);
+ return opt_idx != kOptInvalid && options[opt_idx].immutable
+ && options[opt_idx].var == &options[opt_idx].def_val.data;
+}
+
+/// Check if option is multitype (supports multiple types).
+static bool option_is_multitype(OptIndex opt_idx)
+{
+ const OptTypeFlags type_flags = get_option(opt_idx)->type_flags;
+ assert(type_flags != 0);
+ return !is_power_of_two(type_flags);
+}
+
+/// Check if option supports a specific type.
+bool option_has_type(OptIndex opt_idx, OptValType type)
+{
+ // Ensure that type flags variable can hold all types.
+ STATIC_ASSERT(kOptValTypeSize <= sizeof(OptTypeFlags) * 8,
+ "Option type_flags cannot fit all option types");
+ // Ensure that the type is valid before accessing type_flags.
+ assert(type > kOptValTypeNil && type < kOptValTypeSize);
+ // Bitshift 1 by the value of type to get the type's corresponding flag, and check if it's set in
+ // the type_flags bit field.
+ return get_option(opt_idx)->type_flags & (1 << type);
}
+/// Check if option supports a specific scope.
+bool option_has_scope(OptIndex opt_idx, OptScope scope)
+{
+ // Ensure that scope flags variable can hold all scopes.
+ STATIC_ASSERT(kOptScopeSize <= sizeof(OptScopeFlags) * 8,
+ "Option scope_flags cannot fit all option scopes");
+ // Ensure that the scope is valid before accessing scope_flags.
+ assert(scope >= kOptScopeGlobal && scope < kOptScopeSize);
+ // Bitshift 1 by the value of scope to get the scope's corresponding flag, and check if it's set
+ // in the scope_flags bit field.
+ return get_option(opt_idx)->scope_flags & (1 << scope);
+}
+
+/// Check if option is global-local.
static inline bool option_is_global_local(OptIndex opt_idx)
{
- return opt_idx == kOptInvalid ? false : (options[opt_idx].indir & PV_BOTH);
+ // Global-local options have at least two types, so their type flag cannot be a power of two.
+ return opt_idx != kOptInvalid && !is_power_of_two(options[opt_idx].scope_flags);
+}
+
+/// Check if option only supports global scope.
+static inline bool option_is_global_only(OptIndex opt_idx)
+{
+ // For an option to be global-only, it has to only have a single scope, which means the scope
+ // flags must be a power of two, and it must have the global scope.
+ return opt_idx != kOptInvalid && is_power_of_two(options[opt_idx].scope_flags)
+ && option_has_scope(opt_idx, kOptScopeGlobal);
+}
+
+/// Check if option only supports window scope.
+static inline bool option_is_window_local(OptIndex opt_idx)
+{
+ // For an option to be window-local it has to only have a single scope, which means the scope
+ // flags must be a power of two, and it must have the window scope.
+ return opt_idx != kOptInvalid && is_power_of_two(options[opt_idx].scope_flags)
+ && option_has_scope(opt_idx, kOptScopeWin);
+}
+
+/// Get option index for scope.
+ssize_t option_scope_idx(OptIndex opt_idx, OptScope scope)
+{
+ return options[opt_idx].scope_idx[scope];
}
/// Get option flags.
@@ -3357,7 +3414,7 @@ static OptVal get_option_unset_value(OptIndex opt_idx)
vimoption_T *opt = &options[opt_idx];
// For global-local options, use the unset value of the local value.
- if (opt->indir & PV_BOTH) {
+ if (option_is_global_local(opt_idx)) {
// String global-local options always use an empty string for the unset value.
if (option_has_type(opt_idx, kOptValTypeString)) {
return STATIC_CSTR_AS_OPTVAL("");
@@ -3389,7 +3446,7 @@ static bool is_option_local_value_unset(OptIndex opt_idx)
vimoption_T *opt = get_option(opt_idx);
// Local value of option that isn't global-local is always considered set.
- if (!((int)opt->indir & PV_BOTH)) {
+ if (!option_is_global_local(opt_idx)) {
return false;
}
@@ -3748,10 +3805,10 @@ void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set
/// @param set_sid Script ID. Special values:
/// 0: Use current script ID.
/// SID_NONE: Don't set script ID.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param[in] from Target buffer/window.
void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid,
- OptReqScope req_scope, void *const from)
+ OptScope req_scope, void *const from)
{
buf_T *save_curbuf = curbuf;
win_T *save_curwin = curwin;
@@ -3760,15 +3817,15 @@ void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T
// side-effects when setting an option directly. Just change the values of curbuf and curwin if
// needed, no need to properly switch the window / buffer.
switch (req_scope) {
- case kOptReqGlobal:
+ case kOptScopeGlobal:
break;
- case kOptReqBuf:
- curbuf = (buf_T *)from;
- break;
- case kOptReqWin:
+ case kOptScopeWin:
curwin = (win_T *)from;
curbuf = curwin->w_buffer;
break;
+ case kOptScopeBuf:
+ curbuf = (buf_T *)from;
+ break;
}
set_option_direct(opt_idx, value, opt_flags, set_sid);
@@ -3855,16 +3912,17 @@ void set_option_value_give_err(const OptIndex opt_idx, OptVal value, int opt_fla
/// Switch current context to get/set option value for window/buffer.
///
/// @param[out] ctx Current context. switchwin_T for window and aco_save_T for buffer.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param[in] from Target buffer/window.
/// @param[out] err Error message, if any.
///
/// @return true if context was switched, false otherwise.
-static bool switch_option_context(void *const ctx, OptReqScope req_scope, void *const from,
- Error *err)
+static bool switch_option_context(void *const ctx, OptScope req_scope, void *const from, Error *err)
{
switch (req_scope) {
- case kOptReqWin: {
+ case kOptScopeGlobal:
+ return false;
+ case kOptScopeWin: {
win_T *const win = (win_T *)from;
switchwin_T *const switchwin = (switchwin_T *)ctx;
@@ -3884,7 +3942,7 @@ static bool switch_option_context(void *const ctx, OptReqScope req_scope, void *
}
return true;
}
- case kOptReqBuf: {
+ case kOptScopeBuf: {
buf_T *const buf = (buf_T *)from;
aco_save_T *const aco = (aco_save_T *)ctx;
@@ -3894,76 +3952,44 @@ static bool switch_option_context(void *const ctx, OptReqScope req_scope, void *
aucmd_prepbuf(aco, buf);
return true;
}
- case kOptReqGlobal:
- return false;
}
UNREACHABLE;
}
/// Restore context after getting/setting option for window/buffer. See switch_option_context() for
/// params.
-static void restore_option_context(void *const ctx, OptReqScope req_scope)
+static void restore_option_context(void *const ctx, OptScope req_scope)
{
switch (req_scope) {
- case kOptReqWin:
+ case kOptScopeGlobal:
+ break;
+ case kOptScopeWin:
restore_win_noblock((switchwin_T *)ctx, true);
break;
- case kOptReqBuf:
+ case kOptScopeBuf:
aucmd_restbuf((aco_save_T *)ctx);
break;
- case kOptReqGlobal:
- break;
}
}
-/// Get attributes for an option.
-///
-/// @param opt_idx Option index in options[] table.
-///
-/// @return Option attributes.
-/// 0 for hidden or unknown option.
-/// See SOPT_* in option_defs.h for other flags.
-int get_option_attrs(OptIndex opt_idx)
-{
- if (opt_idx == kOptInvalid) {
- return 0;
- }
-
- vimoption_T *opt = get_option(opt_idx);
-
- int attrs = 0;
-
- if (opt->indir == PV_NONE || (opt->indir & PV_BOTH)) {
- attrs |= SOPT_GLOBAL;
- }
- if (opt->indir & PV_WIN) {
- attrs |= SOPT_WIN;
- } else if (opt->indir & PV_BUF) {
- attrs |= SOPT_BUF;
- }
-
- assert(attrs != 0);
- return attrs;
-}
-
/// Get option value for buffer / window.
///
/// @param opt_idx Option index in options[] table.
/// @param[out] flagsp Set to the option flags (see OptFlags) (if not NULL).
/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination).
/// @param[out] hidden Whether option is hidden.
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param[in] from Target buffer/window.
/// @param[out] err Error message, if any.
///
/// @return Option value. Must be freed by caller.
-OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptReqScope req_scope,
- void *const from, Error *err)
+OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptScope req_scope, void *const from,
+ Error *err)
{
switchwin_T switchwin;
aco_save_T aco;
- void *ctx = req_scope == kOptReqWin ? (void *)&switchwin
- : (req_scope == kOptReqBuf ? (void *)&aco : NULL);
+ void *ctx = req_scope == kOptScopeWin ? (void *)&switchwin
+ : (req_scope == kOptScopeBuf ? (void *)&aco : NULL);
bool switched = switch_option_context(ctx, req_scope, from, err);
if (ERROR_SET(err)) {
@@ -3985,17 +4011,17 @@ OptVal get_option_value_for(OptIndex opt_idx, int scope, const OptReqScope req_s
/// @param opt_idx Option index in options[] table.
/// @param[in] value Option value.
/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
-/// @param req_scope Requested option scope. See OptReqScope in option.h.
+/// @param req_scope Requested option scope. See OptScope in option.h.
/// @param[in] from Target buffer/window.
/// @param[out] err Error message, if any.
void set_option_value_for(const char *name, OptIndex opt_idx, OptVal value, const int opt_flags,
- const OptReqScope req_scope, void *const from, Error *err)
+ const OptScope req_scope, void *const from, Error *err)
FUNC_ATTR_NONNULL_ARG(1)
{
switchwin_T switchwin;
aco_save_T aco;
- void *ctx = req_scope == kOptReqWin ? (void *)&switchwin
- : (req_scope == kOptReqBuf ? (void *)&aco : NULL);
+ void *ctx = req_scope == kOptScopeWin ? (void *)&switchwin
+ : (req_scope == kOptScopeBuf ? (void *)&aco : NULL);
bool switched = switch_option_context(ctx, req_scope, from, err);
if (ERROR_SET(err)) {
@@ -4023,6 +4049,7 @@ static void showoptions(bool all, int opt_flags)
vimoption_T **items = xmalloc(sizeof(vimoption_T *) * OPTION_COUNT);
+ msg_ext_set_kind("list_cmd");
// Highlight title
if (opt_flags & OPT_GLOBAL) {
msg_puts_title(_("\n--- Global option values ---"));
@@ -4040,7 +4067,7 @@ static void showoptions(bool all, int opt_flags)
// collect the items in items[]
int item_count = 0;
vimoption_T *opt;
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
opt = &options[opt_idx];
// apply :filter /pat/
if (message_filtered(opt->fullname)) {
@@ -4049,7 +4076,7 @@ static void showoptions(bool all, int opt_flags)
void *varp = NULL;
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) {
- if (opt->indir != PV_NONE) {
+ if (!option_is_global_only(opt_idx)) {
varp = get_varp_scope(opt, opt_flags);
}
} else {
@@ -4124,7 +4151,7 @@ static int optval_default(OptIndex opt_idx, void *varp)
/// Send update to UIs with values of UI relevant options
void ui_refresh_options(void)
{
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
uint32_t flags = options[opt_idx].flags;
if (!(flags & kOptFlagUIOption)) {
continue;
@@ -4204,13 +4231,13 @@ int makeset(FILE *fd, int opt_flags, int local_only)
// kOptFlagPriMkrc flag and once without.
for (int pri = 1; pri >= 0; pri--) {
vimoption_T *opt;
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
opt = &options[opt_idx];
if (!(opt->flags & kOptFlagNoMkrc)
&& ((pri == 1) == ((opt->flags & kOptFlagPriMkrc) != 0))) {
// skip global option when only doing locals
- if (opt->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) {
+ if (option_is_global_only(opt_idx) && !(opt_flags & OPT_GLOBAL)) {
continue;
}
@@ -4237,21 +4264,19 @@ int makeset(FILE *fd, int opt_flags, int local_only)
int round = 2;
void *varp_local = NULL; // fresh value
- if (opt->indir != PV_NONE) {
- if (opt->var == VAR_WIN) {
- // skip window-local option when only doing globals
- if (!(opt_flags & OPT_LOCAL)) {
- continue;
- }
- // When fresh value of window-local option is not at the
- // default, need to write it too.
- if (!(opt_flags & OPT_GLOBAL) && !local_only) {
- void *varp_fresh = get_varp_scope(opt, OPT_GLOBAL); // local value
- if (!optval_default(opt_idx, varp_fresh)) {
- round = 1;
- varp_local = varp;
- varp = varp_fresh;
- }
+ if (option_is_window_local(opt_idx)) {
+ // skip window-local option when only doing globals
+ if (!(opt_flags & OPT_LOCAL)) {
+ continue;
+ }
+ // When fresh value of window-local option is not at the
+ // default, need to write it too.
+ if (!(opt_flags & OPT_GLOBAL) && !local_only) {
+ void *varp_fresh = get_varp_scope(opt, OPT_GLOBAL); // local value
+ if (!optval_default(opt_idx, varp_fresh)) {
+ round = 1;
+ varp_local = varp;
+ varp = varp_fresh;
}
}
}
@@ -4267,9 +4292,9 @@ int makeset(FILE *fd, int opt_flags, int local_only)
}
bool do_endif = false;
- // Don't set 'syntax' and 'filetype' again if the value is
- // already right, avoids reloading the syntax file.
- if (opt->indir == PV_SYN || opt->indir == PV_FT) {
+ // Don't set 'syntax' and 'filetype' again if the value is already right, avoids reloading
+ // the syntax file.
+ if (opt_idx == kOptSyntax || opt_idx == kOptFiletype) {
if (fprintf(fd, "if &%s != '%s'", opt->fullname,
*(char **)(varp)) < 0
|| put_eol(fd) < 0) {
@@ -4325,7 +4350,7 @@ static int put_set(FILE *fd, char *cmd, OptIndex opt_idx, void *varp)
char *name = opt->fullname;
uint64_t flags = opt->flags;
- if ((opt->indir & PV_BOTH) && varp != opt->var
+ if (option_is_global_local(opt_idx) && varp != opt->var
&& optval_equal(value, get_option_unset_value(opt_idx))) {
// Processing unset local value of global-local option. Do nothing.
return OK;
@@ -4430,76 +4455,80 @@ static int put_set(FILE *fd, char *cmd, OptIndex opt_idx, void *varp)
void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win)
{
- if ((scope & OPT_GLOBAL) && p->indir != PV_NONE) {
- if (p->var == VAR_WIN) {
+ OptIndex opt_idx = get_opt_idx(p);
+
+ if ((scope & OPT_GLOBAL) && !option_is_global_only(opt_idx)) {
+ if (option_is_window_local(opt_idx)) {
return GLOBAL_WO(get_varp_from(p, buf, win));
}
return p->var;
}
- if ((scope & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) {
- switch ((int)p->indir) {
- case PV_FP:
+
+ if ((scope & OPT_LOCAL) && option_is_global_local(opt_idx)) {
+ switch (opt_idx) {
+ case kOptFormatprg:
return &(buf->b_p_fp);
- case PV_FFU:
+ case kOptFindfunc:
return &(buf->b_p_ffu);
- case PV_EFM:
+ case kOptErrorformat:
return &(buf->b_p_efm);
- case PV_GP:
+ case kOptGrepprg:
return &(buf->b_p_gp);
- case PV_MP:
+ case kOptMakeprg:
return &(buf->b_p_mp);
- case PV_EP:
+ case kOptEqualprg:
return &(buf->b_p_ep);
- case PV_KP:
+ case kOptKeywordprg:
return &(buf->b_p_kp);
- case PV_PATH:
+ case kOptPath:
return &(buf->b_p_path);
- case PV_AR:
+ case kOptAutoread:
return &(buf->b_p_ar);
- case PV_TAGS:
+ case kOptTags:
return &(buf->b_p_tags);
- case PV_TC:
+ case kOptTagcase:
return &(buf->b_p_tc);
- case PV_SISO:
+ case kOptSidescrolloff:
return &(win->w_p_siso);
- case PV_SO:
+ case kOptScrolloff:
return &(win->w_p_so);
- case PV_DEF:
+ case kOptDefine:
return &(buf->b_p_def);
- case PV_INC:
+ case kOptInclude:
return &(buf->b_p_inc);
- case PV_COT:
+ case kOptCompleteopt:
return &(buf->b_p_cot);
- case PV_DICT:
+ case kOptDictionary:
return &(buf->b_p_dict);
- case PV_TSR:
+ case kOptThesaurus:
return &(buf->b_p_tsr);
- case PV_TSRFU:
+ case kOptThesaurusfunc:
return &(buf->b_p_tsrfu);
- case PV_TFU:
+ case kOptTagfunc:
return &(buf->b_p_tfu);
- case PV_SBR:
+ case kOptShowbreak:
return &(win->w_p_sbr);
- case PV_STL:
+ case kOptStatusline:
return &(win->w_p_stl);
- case PV_WBR:
+ case kOptWinbar:
return &(win->w_p_wbr);
- case PV_UL:
+ case kOptUndolevels:
return &(buf->b_p_ul);
- case PV_LW:
+ case kOptLispwords:
return &(buf->b_p_lw);
- case PV_BKC:
+ case kOptBackupcopy:
return &(buf->b_p_bkc);
- case PV_MENC:
+ case kOptMakeencoding:
return &(buf->b_p_menc);
- case PV_FCS:
+ case kOptFillchars:
return &(win->w_p_fcs);
- case PV_LCS:
+ case kOptListchars:
return &(win->w_p_lcs);
- case PV_VE:
+ case kOptVirtualedit:
return &(win->w_p_ve);
+ default:
+ abort();
}
- return NULL; // "cannot happen"
}
return get_varp_from(p, buf, win);
}
@@ -4521,291 +4550,290 @@ void *get_option_varp_scope_from(OptIndex opt_idx, int scope, buf_T *buf, win_T
void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
{
- // hidden options always use the same var pointer
- if (is_option_hidden(get_opt_idx(p))) {
- return p->var;
- }
+ OptIndex opt_idx = get_opt_idx(p);
- switch ((int)p->indir) {
- case PV_NONE:
+ // Hidden options and global-only options always use the same var pointer
+ if (is_option_hidden(opt_idx) || option_is_global_only(opt_idx)) {
return p->var;
+ }
+ switch (opt_idx) {
// global option with local value: use local value if it's been set
- case PV_EP:
+ case kOptEqualprg:
return *buf->b_p_ep != NUL ? &buf->b_p_ep : p->var;
- case PV_KP:
+ case kOptKeywordprg:
return *buf->b_p_kp != NUL ? &buf->b_p_kp : p->var;
- case PV_PATH:
+ case kOptPath:
return *buf->b_p_path != NUL ? &(buf->b_p_path) : p->var;
- case PV_AR:
+ case kOptAutoread:
return buf->b_p_ar >= 0 ? &(buf->b_p_ar) : p->var;
- case PV_TAGS:
+ case kOptTags:
return *buf->b_p_tags != NUL ? &(buf->b_p_tags) : p->var;
- case PV_TC:
+ case kOptTagcase:
return *buf->b_p_tc != NUL ? &(buf->b_p_tc) : p->var;
- case PV_SISO:
+ case kOptSidescrolloff:
return win->w_p_siso >= 0 ? &(win->w_p_siso) : p->var;
- case PV_SO:
+ case kOptScrolloff:
return win->w_p_so >= 0 ? &(win->w_p_so) : p->var;
- case PV_BKC:
+ case kOptBackupcopy:
return *buf->b_p_bkc != NUL ? &(buf->b_p_bkc) : p->var;
- case PV_DEF:
+ case kOptDefine:
return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var;
- case PV_INC:
+ case kOptInclude:
return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var;
- case PV_COT:
+ case kOptCompleteopt:
return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var;
- case PV_DICT:
+ case kOptDictionary:
return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var;
- case PV_TSR:
+ case kOptThesaurus:
return *buf->b_p_tsr != NUL ? &(buf->b_p_tsr) : p->var;
- case PV_TSRFU:
+ case kOptThesaurusfunc:
return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var;
- case PV_FP:
+ case kOptFormatprg:
return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var;
- case PV_FFU:
+ case kOptFindfunc:
return *buf->b_p_ffu != NUL ? &(buf->b_p_ffu) : p->var;
- case PV_EFM:
+ case kOptErrorformat:
return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var;
- case PV_GP:
+ case kOptGrepprg:
return *buf->b_p_gp != NUL ? &(buf->b_p_gp) : p->var;
- case PV_MP:
+ case kOptMakeprg:
return *buf->b_p_mp != NUL ? &(buf->b_p_mp) : p->var;
- case PV_SBR:
+ case kOptShowbreak:
return *win->w_p_sbr != NUL ? &(win->w_p_sbr) : p->var;
- case PV_STL:
+ case kOptStatusline:
return *win->w_p_stl != NUL ? &(win->w_p_stl) : p->var;
- case PV_WBR:
+ case kOptWinbar:
return *win->w_p_wbr != NUL ? &(win->w_p_wbr) : p->var;
- case PV_UL:
+ case kOptUndolevels:
return buf->b_p_ul != NO_LOCAL_UNDOLEVEL ? &(buf->b_p_ul) : p->var;
- case PV_LW:
+ case kOptLispwords:
return *buf->b_p_lw != NUL ? &(buf->b_p_lw) : p->var;
- case PV_MENC:
+ case kOptMakeencoding:
return *buf->b_p_menc != NUL ? &(buf->b_p_menc) : p->var;
- case PV_FCS:
+ case kOptFillchars:
return *win->w_p_fcs != NUL ? &(win->w_p_fcs) : p->var;
- case PV_LCS:
+ case kOptListchars:
return *win->w_p_lcs != NUL ? &(win->w_p_lcs) : p->var;
- case PV_VE:
+ case kOptVirtualedit:
return *win->w_p_ve != NUL ? &win->w_p_ve : p->var;
- case PV_ARAB:
+ case kOptArabic:
return &(win->w_p_arab);
- case PV_LIST:
+ case kOptList:
return &(win->w_p_list);
- case PV_SPELL:
+ case kOptSpell:
return &(win->w_p_spell);
- case PV_CUC:
+ case kOptCursorcolumn:
return &(win->w_p_cuc);
- case PV_CUL:
+ case kOptCursorline:
return &(win->w_p_cul);
- case PV_CULOPT:
+ case kOptCursorlineopt:
return &(win->w_p_culopt);
- case PV_CC:
+ case kOptColorcolumn:
return &(win->w_p_cc);
- case PV_DIFF:
+ case kOptDiff:
return &(win->w_p_diff);
- case PV_FDC:
+ case kOptFoldcolumn:
return &(win->w_p_fdc);
- case PV_FEN:
+ case kOptFoldenable:
return &(win->w_p_fen);
- case PV_FDI:
+ case kOptFoldignore:
return &(win->w_p_fdi);
- case PV_FDL:
+ case kOptFoldlevel:
return &(win->w_p_fdl);
- case PV_FDM:
+ case kOptFoldmethod:
return &(win->w_p_fdm);
- case PV_FML:
+ case kOptFoldminlines:
return &(win->w_p_fml);
- case PV_FDN:
+ case kOptFoldnestmax:
return &(win->w_p_fdn);
- case PV_FDE:
+ case kOptFoldexpr:
return &(win->w_p_fde);
- case PV_FDT:
+ case kOptFoldtext:
return &(win->w_p_fdt);
- case PV_FMR:
+ case kOptFoldmarker:
return &(win->w_p_fmr);
- case PV_NU:
+ case kOptNumber:
return &(win->w_p_nu);
- case PV_RNU:
+ case kOptRelativenumber:
return &(win->w_p_rnu);
- case PV_NUW:
+ case kOptNumberwidth:
return &(win->w_p_nuw);
- case PV_WFB:
+ case kOptWinfixbuf:
return &(win->w_p_wfb);
- case PV_WFH:
+ case kOptWinfixheight:
return &(win->w_p_wfh);
- case PV_WFW:
+ case kOptWinfixwidth:
return &(win->w_p_wfw);
- case PV_PVW:
+ case kOptPreviewwindow:
return &(win->w_p_pvw);
- case PV_RL:
+ case kOptRightleft:
return &(win->w_p_rl);
- case PV_RLC:
+ case kOptRightleftcmd:
return &(win->w_p_rlc);
- case PV_SCROLL:
+ case kOptScroll:
return &(win->w_p_scr);
- case PV_SMS:
+ case kOptSmoothscroll:
return &(win->w_p_sms);
- case PV_WRAP:
+ case kOptWrap:
return &(win->w_p_wrap);
- case PV_LBR:
+ case kOptLinebreak:
return &(win->w_p_lbr);
- case PV_BRI:
+ case kOptBreakindent:
return &(win->w_p_bri);
- case PV_BRIOPT:
+ case kOptBreakindentopt:
return &(win->w_p_briopt);
- case PV_SCBIND:
+ case kOptScrollbind:
return &(win->w_p_scb);
- case PV_CRBIND:
+ case kOptCursorbind:
return &(win->w_p_crb);
- case PV_COCU:
+ case kOptConcealcursor:
return &(win->w_p_cocu);
- case PV_COLE:
+ case kOptConceallevel:
return &(win->w_p_cole);
- case PV_AI:
+ case kOptAutoindent:
return &(buf->b_p_ai);
- case PV_BIN:
+ case kOptBinary:
return &(buf->b_p_bin);
- case PV_BOMB:
+ case kOptBomb:
return &(buf->b_p_bomb);
- case PV_BH:
+ case kOptBufhidden:
return &(buf->b_p_bh);
- case PV_BT:
+ case kOptBuftype:
return &(buf->b_p_bt);
- case PV_BL:
+ case kOptBuflisted:
return &(buf->b_p_bl);
- case PV_CHANNEL:
+ case kOptChannel:
return &(buf->b_p_channel);
- case PV_CI:
+ case kOptCopyindent:
return &(buf->b_p_ci);
- case PV_CIN:
+ case kOptCindent:
return &(buf->b_p_cin);
- case PV_CINK:
+ case kOptCinkeys:
return &(buf->b_p_cink);
- case PV_CINO:
+ case kOptCinoptions:
return &(buf->b_p_cino);
- case PV_CINSD:
+ case kOptCinscopedecls:
return &(buf->b_p_cinsd);
- case PV_CINW:
+ case kOptCinwords:
return &(buf->b_p_cinw);
- case PV_COM:
+ case kOptComments:
return &(buf->b_p_com);
- case PV_CMS:
+ case kOptCommentstring:
return &(buf->b_p_cms);
- case PV_CPT:
+ case kOptComplete:
return &(buf->b_p_cpt);
#ifdef BACKSLASH_IN_FILENAME
- case PV_CSL:
+ case kOptCompleteslash:
return &(buf->b_p_csl);
#endif
- case PV_CFU:
+ case kOptCompletefunc:
return &(buf->b_p_cfu);
- case PV_OFU:
+ case kOptOmnifunc:
return &(buf->b_p_ofu);
- case PV_EOF:
+ case kOptEndoffile:
return &(buf->b_p_eof);
- case PV_EOL:
+ case kOptEndofline:
return &(buf->b_p_eol);
- case PV_FIXEOL:
+ case kOptFixendofline:
return &(buf->b_p_fixeol);
- case PV_ET:
+ case kOptExpandtab:
return &(buf->b_p_et);
- case PV_FENC:
+ case kOptFileencoding:
return &(buf->b_p_fenc);
- case PV_FF:
+ case kOptFileformat:
return &(buf->b_p_ff);
- case PV_FT:
+ case kOptFiletype:
return &(buf->b_p_ft);
- case PV_FO:
+ case kOptFormatoptions:
return &(buf->b_p_fo);
- case PV_FLP:
+ case kOptFormatlistpat:
return &(buf->b_p_flp);
- case PV_IMI:
+ case kOptIminsert:
return &(buf->b_p_iminsert);
- case PV_IMS:
+ case kOptImsearch:
return &(buf->b_p_imsearch);
- case PV_INF:
+ case kOptInfercase:
return &(buf->b_p_inf);
- case PV_ISK:
+ case kOptIskeyword:
return &(buf->b_p_isk);
- case PV_INEX:
+ case kOptIncludeexpr:
return &(buf->b_p_inex);
- case PV_INDE:
+ case kOptIndentexpr:
return &(buf->b_p_inde);
- case PV_INDK:
+ case kOptIndentkeys:
return &(buf->b_p_indk);
- case PV_FEX:
+ case kOptFormatexpr:
return &(buf->b_p_fex);
- case PV_LISP:
+ case kOptLisp:
return &(buf->b_p_lisp);
- case PV_LOP:
+ case kOptLispoptions:
return &(buf->b_p_lop);
- case PV_ML:
+ case kOptModeline:
return &(buf->b_p_ml);
- case PV_MPS:
+ case kOptMatchpairs:
return &(buf->b_p_mps);
- case PV_MA:
+ case kOptModifiable:
return &(buf->b_p_ma);
- case PV_MOD:
+ case kOptModified:
return &(buf->b_changed);
- case PV_NF:
+ case kOptNrformats:
return &(buf->b_p_nf);
- case PV_PI:
+ case kOptPreserveindent:
return &(buf->b_p_pi);
- case PV_QE:
+ case kOptQuoteescape:
return &(buf->b_p_qe);
- case PV_RO:
+ case kOptReadonly:
return &(buf->b_p_ro);
- case PV_SCBK:
+ case kOptScrollback:
return &(buf->b_p_scbk);
- case PV_SI:
+ case kOptSmartindent:
return &(buf->b_p_si);
- case PV_STS:
+ case kOptSofttabstop:
return &(buf->b_p_sts);
- case PV_SUA:
+ case kOptSuffixesadd:
return &(buf->b_p_sua);
- case PV_SWF:
+ case kOptSwapfile:
return &(buf->b_p_swf);
- case PV_SMC:
+ case kOptSynmaxcol:
return &(buf->b_p_smc);
- case PV_SYN:
+ case kOptSyntax:
return &(buf->b_p_syn);
- case PV_SPC:
+ case kOptSpellcapcheck:
return &(win->w_s->b_p_spc);
- case PV_SPF:
+ case kOptSpellfile:
return &(win->w_s->b_p_spf);
- case PV_SPL:
+ case kOptSpelllang:
return &(win->w_s->b_p_spl);
- case PV_SPO:
+ case kOptSpelloptions:
return &(win->w_s->b_p_spo);
- case PV_SW:
+ case kOptShiftwidth:
return &(buf->b_p_sw);
- case PV_TFU:
+ case kOptTagfunc:
return &(buf->b_p_tfu);
- case PV_TS:
+ case kOptTabstop:
return &(buf->b_p_ts);
- case PV_TW:
+ case kOptTextwidth:
return &(buf->b_p_tw);
- case PV_UDF:
+ case kOptUndofile:
return &(buf->b_p_udf);
- case PV_WM:
+ case kOptWrapmargin:
return &(buf->b_p_wm);
- case PV_VSTS:
+ case kOptVarsofttabstop:
return &(buf->b_p_vsts);
- case PV_VTS:
+ case kOptVartabstop:
return &(buf->b_p_vts);
- case PV_KMAP:
+ case kOptKeymap:
return &(buf->b_p_keymap);
- case PV_SCL:
+ case kOptSigncolumn:
return &(win->w_p_scl);
- case PV_WINHL:
+ case kOptWinhighlight:
return &(win->w_p_winhl);
- case PV_WINBL:
+ case kOptWinblend:
return &(win->w_p_winbl);
- case PV_STC:
+ case kOptStatuscolumn:
return &(win->w_p_stc);
default:
iemsg(_("E356: get_varp ERROR"));
@@ -5008,26 +5036,8 @@ void didset_window_options(win_T *wp, bool valid_cursor)
wp->w_grid_alloc.blending = wp->w_p_winbl > 0;
}
-/// Index into the options table for a buffer-local option enum.
-static OptIndex buf_opt_idx[BV_COUNT];
#define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].last_set
-/// Initialize buf_opt_idx[] if not done already.
-static void init_buf_opt_idx(void)
-{
- static bool did_init_buf_opt_idx = false;
-
- if (did_init_buf_opt_idx) {
- return;
- }
- did_init_buf_opt_idx = true;
- for (OptIndex i = 0; i < kOptIndexCount; i++) {
- if (options[i].indir & PV_BUF) {
- buf_opt_idx[options[i].indir & PV_MASK] = i;
- }
- }
-}
-
/// Copy global option values to local options for one buffer.
/// Used when creating a new buffer and sometimes when entering a buffer.
/// flags:
@@ -5065,7 +5075,6 @@ void buf_copy_options(buf_T *buf, int flags)
if (should_copy || (flags & BCO_ALWAYS)) {
CLEAR_FIELD(buf->b_p_script_ctx);
- init_buf_opt_idx();
// Don't copy the options specific to a help buffer when
// BCO_NOHELP is given or the options were initialized already
// (jumping back to a help file with CTRL-T or CTRL-O)
@@ -5101,61 +5110,61 @@ void buf_copy_options(buf_T *buf, int flags)
}
buf->b_p_ai = p_ai;
- COPY_OPT_SCTX(buf, BV_AI);
+ COPY_OPT_SCTX(buf, kBufOptAutoindent);
buf->b_p_ai_nopaste = p_ai_nopaste;
buf->b_p_sw = p_sw;
- COPY_OPT_SCTX(buf, BV_SW);
+ COPY_OPT_SCTX(buf, kBufOptShiftwidth);
buf->b_p_scbk = p_scbk;
- COPY_OPT_SCTX(buf, BV_SCBK);
+ COPY_OPT_SCTX(buf, kBufOptScrollback);
buf->b_p_tw = p_tw;
- COPY_OPT_SCTX(buf, BV_TW);
+ COPY_OPT_SCTX(buf, kBufOptTextwidth);
buf->b_p_tw_nopaste = p_tw_nopaste;
buf->b_p_tw_nobin = p_tw_nobin;
buf->b_p_wm = p_wm;
- COPY_OPT_SCTX(buf, BV_WM);
+ COPY_OPT_SCTX(buf, kBufOptWrapmargin);
buf->b_p_wm_nopaste = p_wm_nopaste;
buf->b_p_wm_nobin = p_wm_nobin;
buf->b_p_bin = p_bin;
- COPY_OPT_SCTX(buf, BV_BIN);
+ COPY_OPT_SCTX(buf, kBufOptBinary);
buf->b_p_bomb = p_bomb;
- COPY_OPT_SCTX(buf, BV_BOMB);
+ COPY_OPT_SCTX(buf, kBufOptBomb);
buf->b_p_et = p_et;
- COPY_OPT_SCTX(buf, BV_ET);
+ COPY_OPT_SCTX(buf, kBufOptExpandtab);
buf->b_p_fixeol = p_fixeol;
- COPY_OPT_SCTX(buf, BV_FIXEOL);
+ COPY_OPT_SCTX(buf, kBufOptFixendofline);
buf->b_p_et_nobin = p_et_nobin;
buf->b_p_et_nopaste = p_et_nopaste;
buf->b_p_ml = p_ml;
- COPY_OPT_SCTX(buf, BV_ML);
+ COPY_OPT_SCTX(buf, kBufOptModeline);
buf->b_p_ml_nobin = p_ml_nobin;
buf->b_p_inf = p_inf;
- COPY_OPT_SCTX(buf, BV_INF);
+ COPY_OPT_SCTX(buf, kBufOptInfercase);
if (cmdmod.cmod_flags & CMOD_NOSWAPFILE) {
buf->b_p_swf = false;
} else {
buf->b_p_swf = p_swf;
- COPY_OPT_SCTX(buf, BV_SWF);
+ COPY_OPT_SCTX(buf, kBufOptSwapfile);
}
buf->b_p_cpt = xstrdup(p_cpt);
- COPY_OPT_SCTX(buf, BV_CPT);
+ COPY_OPT_SCTX(buf, kBufOptComplete);
#ifdef BACKSLASH_IN_FILENAME
buf->b_p_csl = xstrdup(p_csl);
- COPY_OPT_SCTX(buf, BV_CSL);
+ COPY_OPT_SCTX(buf, kBufOptCompleteslash);
#endif
buf->b_p_cfu = xstrdup(p_cfu);
- COPY_OPT_SCTX(buf, BV_CFU);
+ COPY_OPT_SCTX(buf, kBufOptCompletefunc);
set_buflocal_cfu_callback(buf);
buf->b_p_ofu = xstrdup(p_ofu);
- COPY_OPT_SCTX(buf, BV_OFU);
+ COPY_OPT_SCTX(buf, kBufOptOmnifunc);
set_buflocal_ofu_callback(buf);
buf->b_p_tfu = xstrdup(p_tfu);
- COPY_OPT_SCTX(buf, BV_TFU);
+ COPY_OPT_SCTX(buf, kBufOptTagfunc);
set_buflocal_tfu_callback(buf);
buf->b_p_sts = p_sts;
- COPY_OPT_SCTX(buf, BV_STS);
+ COPY_OPT_SCTX(buf, kBufOptSofttabstop);
buf->b_p_sts_nopaste = p_sts_nopaste;
buf->b_p_vsts = xstrdup(p_vsts);
- COPY_OPT_SCTX(buf, BV_VSTS);
+ COPY_OPT_SCTX(buf, kBufOptVarsofttabstop);
if (p_vsts && p_vsts != empty_string_option) {
tabstop_set(p_vsts, &buf->b_p_vsts_array);
} else {
@@ -5163,75 +5172,75 @@ void buf_copy_options(buf_T *buf, int flags)
}
buf->b_p_vsts_nopaste = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : NULL;
buf->b_p_com = xstrdup(p_com);
- COPY_OPT_SCTX(buf, BV_COM);
+ COPY_OPT_SCTX(buf, kBufOptComments);
buf->b_p_cms = xstrdup(p_cms);
- COPY_OPT_SCTX(buf, BV_CMS);
+ COPY_OPT_SCTX(buf, kBufOptCommentstring);
buf->b_p_fo = xstrdup(p_fo);
- COPY_OPT_SCTX(buf, BV_FO);
+ COPY_OPT_SCTX(buf, kBufOptFormatoptions);
buf->b_p_flp = xstrdup(p_flp);
- COPY_OPT_SCTX(buf, BV_FLP);
+ COPY_OPT_SCTX(buf, kBufOptFormatlistpat);
buf->b_p_nf = xstrdup(p_nf);
- COPY_OPT_SCTX(buf, BV_NF);
+ COPY_OPT_SCTX(buf, kBufOptNrformats);
buf->b_p_mps = xstrdup(p_mps);
- COPY_OPT_SCTX(buf, BV_MPS);
+ COPY_OPT_SCTX(buf, kBufOptMatchpairs);
buf->b_p_si = p_si;
- COPY_OPT_SCTX(buf, BV_SI);
+ COPY_OPT_SCTX(buf, kBufOptSmartindent);
buf->b_p_channel = 0;
buf->b_p_ci = p_ci;
- COPY_OPT_SCTX(buf, BV_CI);
+ COPY_OPT_SCTX(buf, kBufOptCopyindent);
buf->b_p_cin = p_cin;
- COPY_OPT_SCTX(buf, BV_CIN);
+ COPY_OPT_SCTX(buf, kBufOptCindent);
buf->b_p_cink = xstrdup(p_cink);
- COPY_OPT_SCTX(buf, BV_CINK);
+ COPY_OPT_SCTX(buf, kBufOptCinkeys);
buf->b_p_cino = xstrdup(p_cino);
- COPY_OPT_SCTX(buf, BV_CINO);
+ COPY_OPT_SCTX(buf, kBufOptCinoptions);
buf->b_p_cinsd = xstrdup(p_cinsd);
- COPY_OPT_SCTX(buf, BV_CINSD);
+ COPY_OPT_SCTX(buf, kBufOptCinscopedecls);
buf->b_p_lop = xstrdup(p_lop);
- COPY_OPT_SCTX(buf, BV_LOP);
+ COPY_OPT_SCTX(buf, kBufOptLispoptions);
// Don't copy 'filetype', it must be detected
buf->b_p_ft = empty_string_option;
buf->b_p_pi = p_pi;
- COPY_OPT_SCTX(buf, BV_PI);
+ COPY_OPT_SCTX(buf, kBufOptPreserveindent);
buf->b_p_cinw = xstrdup(p_cinw);
- COPY_OPT_SCTX(buf, BV_CINW);
+ COPY_OPT_SCTX(buf, kBufOptCinwords);
buf->b_p_lisp = p_lisp;
- COPY_OPT_SCTX(buf, BV_LISP);
+ COPY_OPT_SCTX(buf, kBufOptLisp);
// Don't copy 'syntax', it must be set
buf->b_p_syn = empty_string_option;
buf->b_p_smc = p_smc;
- COPY_OPT_SCTX(buf, BV_SMC);
+ COPY_OPT_SCTX(buf, kBufOptSynmaxcol);
buf->b_s.b_syn_isk = empty_string_option;
buf->b_s.b_p_spc = xstrdup(p_spc);
- COPY_OPT_SCTX(buf, BV_SPC);
+ COPY_OPT_SCTX(buf, kBufOptSpellcapcheck);
compile_cap_prog(&buf->b_s);
buf->b_s.b_p_spf = xstrdup(p_spf);
- COPY_OPT_SCTX(buf, BV_SPF);
+ COPY_OPT_SCTX(buf, kBufOptSpellfile);
buf->b_s.b_p_spl = xstrdup(p_spl);
- COPY_OPT_SCTX(buf, BV_SPL);
+ COPY_OPT_SCTX(buf, kBufOptSpelllang);
buf->b_s.b_p_spo = xstrdup(p_spo);
- COPY_OPT_SCTX(buf, BV_SPO);
+ COPY_OPT_SCTX(buf, kBufOptSpelloptions);
buf->b_s.b_p_spo_flags = spo_flags;
buf->b_p_inde = xstrdup(p_inde);
- COPY_OPT_SCTX(buf, BV_INDE);
+ COPY_OPT_SCTX(buf, kBufOptIndentexpr);
buf->b_p_indk = xstrdup(p_indk);
- COPY_OPT_SCTX(buf, BV_INDK);
+ COPY_OPT_SCTX(buf, kBufOptIndentkeys);
buf->b_p_fp = empty_string_option;
buf->b_p_fex = xstrdup(p_fex);
- COPY_OPT_SCTX(buf, BV_FEX);
+ COPY_OPT_SCTX(buf, kBufOptFormatexpr);
buf->b_p_sua = xstrdup(p_sua);
- COPY_OPT_SCTX(buf, BV_SUA);
+ COPY_OPT_SCTX(buf, kBufOptSuffixesadd);
buf->b_p_keymap = xstrdup(p_keymap);
- COPY_OPT_SCTX(buf, BV_KMAP);
+ COPY_OPT_SCTX(buf, kBufOptKeymap);
buf->b_kmap_state |= KEYMAP_INIT;
// This isn't really an option, but copying the langmap and IME
// state from the current buffer is better than resetting it.
buf->b_p_iminsert = p_iminsert;
- COPY_OPT_SCTX(buf, BV_IMI);
+ COPY_OPT_SCTX(buf, kBufOptIminsert);
buf->b_p_imsearch = p_imsearch;
- COPY_OPT_SCTX(buf, BV_IMS);
+ COPY_OPT_SCTX(buf, kBufOptImsearch);
// options that are normally global but also have a local value
// are not copied, start using the global value
@@ -5252,16 +5261,16 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_def = empty_string_option;
buf->b_p_inc = empty_string_option;
buf->b_p_inex = xstrdup(p_inex);
- COPY_OPT_SCTX(buf, BV_INEX);
+ COPY_OPT_SCTX(buf, kBufOptIncludeexpr);
buf->b_p_cot = empty_string_option;
buf->b_cot_flags = 0;
buf->b_p_dict = empty_string_option;
buf->b_p_tsr = empty_string_option;
buf->b_p_tsrfu = empty_string_option;
buf->b_p_qe = xstrdup(p_qe);
- COPY_OPT_SCTX(buf, BV_QE);
+ COPY_OPT_SCTX(buf, kBufOptQuoteescape);
buf->b_p_udf = p_udf;
- COPY_OPT_SCTX(buf, BV_UDF);
+ COPY_OPT_SCTX(buf, kBufOptUndofile);
buf->b_p_lw = empty_string_option;
buf->b_p_menc = empty_string_option;
@@ -5278,12 +5287,12 @@ void buf_copy_options(buf_T *buf, int flags)
}
} else {
buf->b_p_isk = xstrdup(p_isk);
- COPY_OPT_SCTX(buf, BV_ISK);
+ COPY_OPT_SCTX(buf, kBufOptIskeyword);
did_isk = true;
buf->b_p_ts = p_ts;
- COPY_OPT_SCTX(buf, BV_TS);
+ COPY_OPT_SCTX(buf, kBufOptTabstop);
buf->b_p_vts = xstrdup(p_vts);
- COPY_OPT_SCTX(buf, BV_VTS);
+ COPY_OPT_SCTX(buf, kBufOptVartabstop);
if (p_vts && p_vts != empty_string_option && !buf->b_p_vts_array) {
tabstop_set(p_vts, &buf->b_p_vts_array);
} else {
@@ -5294,7 +5303,7 @@ void buf_copy_options(buf_T *buf, int flags)
clear_string_option(&buf->b_p_bt);
}
buf->b_p_ma = p_ma;
- COPY_OPT_SCTX(buf, BV_MA);
+ COPY_OPT_SCTX(buf, kBufOptModifiable);
}
}
@@ -5645,7 +5654,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM
}
}
char *str;
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
str = options[opt_idx].fullname;
if (is_option_hidden(opt_idx)) {
continue;
@@ -6306,11 +6315,11 @@ dict_T *get_winbuf_options(const int bufopt)
{
dict_T *const d = tv_dict_alloc();
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
vimoption_T *opt = &options[opt_idx];
- if ((bufopt && (opt->indir & PV_BUF))
- || (!bufopt && (opt->indir & PV_WIN))) {
+ if ((bufopt && (option_has_scope(opt_idx, kOptScopeBuf)))
+ || (!bufopt && (option_has_scope(opt_idx, kOptScopeWin)))) {
void *varp = get_varp(opt);
if (varp != NULL) {
@@ -6353,8 +6362,8 @@ Dict get_vimoption(String name, int scope, buf_T *buf, win_T *win, Arena *arena,
Dict get_all_vimoptions(Arena *arena)
{
- Dict retval = arena_dict(arena, kOptIndexCount);
- for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
+ Dict retval = arena_dict(arena, kOptCount);
+ for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) {
Dict opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin, arena);
PUT_C(retval, options[opt_idx].fullname, DICT_OBJ(opt_dict));
}
@@ -6363,15 +6372,16 @@ Dict get_all_vimoptions(Arena *arena)
static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *win, Arena *arena)
{
+ OptIndex opt_idx = get_opt_idx(opt);
Dict dict = arena_dict(arena, 13);
PUT_C(dict, "name", CSTR_AS_OBJ(opt->fullname));
PUT_C(dict, "shortname", CSTR_AS_OBJ(opt->shortname));
const char *scope;
- if (opt->indir & PV_BUF) {
+ if (option_has_scope(opt_idx, kOptScopeBuf)) {
scope = "buf";
- } else if (opt->indir & PV_WIN) {
+ } else if (option_has_scope(opt_idx, kOptScopeWin)) {
scope = "win";
} else {
scope = "global";
@@ -6380,7 +6390,7 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w
PUT_C(dict, "scope", CSTR_AS_OBJ(scope));
// welcome to the jungle
- PUT_C(dict, "global_local", BOOLEAN_OBJ(opt->indir & PV_BOTH));
+ PUT_C(dict, "global_local", BOOLEAN_OBJ(option_is_global_local(opt_idx)));
PUT_C(dict, "commalist", BOOLEAN_OBJ(opt->flags & kOptFlagComma));
PUT_C(dict, "flaglist", BOOLEAN_OBJ(opt->flags & kOptFlagFlagList));
@@ -6391,11 +6401,11 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w
last_set = opt->last_set;
} else {
// Scope is either OPT_LOCAL or a fallback mode was requested.
- if (opt->indir & PV_BUF) {
- last_set = buf->b_p_script_ctx[opt->indir & PV_MASK];
+ if (option_has_scope(opt_idx, kOptScopeBuf)) {
+ last_set = buf->b_p_script_ctx[opt->scope_idx[kOptScopeBuf]];
}
- if (opt->indir & PV_WIN) {
- last_set = win->w_p_script_ctx[opt->indir & PV_MASK];
+ if (option_has_scope(opt_idx, kOptScopeWin)) {
+ last_set = win->w_p_script_ctx[opt->scope_idx[kOptScopeWin]];
}
if (req_scope != OPT_LOCAL && last_set.script_ctx.sc_sid == 0) {
last_set = opt->last_set;
@@ -6412,24 +6422,3 @@ static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *w
return dict;
}
-
-/// Check if option is multitype (supports multiple types).
-static bool option_is_multitype(OptIndex opt_idx)
-{
- const OptTypeFlags type_flags = get_option(opt_idx)->type_flags;
- assert(type_flags != 0);
- return !is_power_of_two(type_flags);
-}
-
-/// Check if option supports a specific type.
-bool option_has_type(OptIndex opt_idx, OptValType type)
-{
- // Ensure that type flags variable can hold all types.
- STATIC_ASSERT(kOptValTypeSize <= sizeof(OptTypeFlags) * 8,
- "Option type_flags cannot fit all option types");
- // Ensure that the type is valid before accessing type_flags.
- assert(type > kOptValTypeNil && type < kOptValTypeSize);
- // Bitshift 1 by the value of type to get the type's corresponding flag, and check if it's set in
- // the type_flags bit field.
- return get_option(opt_idx)->type_flags & (1 << type);
-}
diff --git a/src/nvim/option.h b/src/nvim/option.h
index 138d90da97..cba5b00d95 100644
--- a/src/nvim/option.h
+++ b/src/nvim/option.h
@@ -13,56 +13,6 @@
#include "nvim/option_defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h" // IWYU pragma: keep
-/// The options that are local to a window or buffer have "indir" set to one of
-/// these values. Special values:
-/// PV_NONE: global option.
-/// PV_WIN is added: window-local option
-/// PV_BUF is added: buffer-local option
-/// PV_BOTH is added: global option which also has a local value.
-enum {
- PV_BOTH = 0x1000,
- PV_WIN = 0x2000,
- PV_BUF = 0x4000,
- PV_MASK = 0x0fff,
-};
-#define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x))
-#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x))
-#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x))
-
-/// WV_ and BV_ values get typecasted to this for the "indir" field
-typedef enum {
- PV_NONE = 0,
- PV_MAXVAL = 0xffff, ///< to avoid warnings for value out of range
-} idopt_T;
-
-// Options local to a window have a value local to a buffer and global to all
-// buffers. Indicate this by setting "var" to VAR_WIN.
-#define VAR_WIN ((char *)-1)
-
-typedef struct {
- char *fullname; ///< full option name
- char *shortname; ///< permissible abbreviation
- uint32_t flags; ///< see above
- OptTypeFlags type_flags; ///< option type flags, see OptValType
- void *var; ///< global option: pointer to variable;
- ///< window-local option: VAR_WIN;
- ///< buffer-local option: global value
- idopt_T indir; ///< global option: PV_NONE;
- ///< local option: indirect option index
- bool immutable; ///< option is immutable, trying to set its value will give an error.
-
- /// callback function to invoke after an option is modified to validate and
- /// apply the new value.
- opt_did_set_cb_T opt_did_set_cb;
-
- /// callback function to invoke when expanding possible values on the
- /// cmdline. Only useful for string options.
- opt_expand_cb_T opt_expand_cb;
-
- OptVal def_val; ///< default value
- LastSet last_set; ///< script in which the option was last set
-} vimoption_T;
-
/// flags for buf_copy_options()
enum {
BCO_ENTER = 1, ///< going to enter the buffer
@@ -85,13 +35,6 @@ typedef enum {
OPT_SKIPRTP = 0x80, ///< "skiprtp" in 'sessionoptions'
} OptionSetFlags;
-/// Return value from get_option_attrs().
-enum {
- SOPT_GLOBAL = 0x01, ///< Option has global value
- SOPT_WIN = 0x02, ///< Option has window-local value
- SOPT_BUF = 0x04, ///< Option has buffer-local value
-};
-
/// Get name of OptValType as a string.
static inline const char *optval_type_get_name(const OptValType type)
{
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index e32edbf727..832e03148a 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -54,12 +54,20 @@ typedef enum {
kOptValTypeNumber,
kOptValTypeString,
} OptValType;
-
/// Always update this whenever a new option type is added.
#define kOptValTypeSize (kOptValTypeString + 1)
-
typedef uint32_t OptTypeFlags;
+/// Scopes that an option can support.
+typedef enum {
+ kOptScopeGlobal = 0, ///< Request global option value
+ kOptScopeWin, ///< Request window-local option value
+ kOptScopeBuf, ///< Request buffer-local option value
+} OptScope;
+/// Always update this whenever a new option scope is added.
+#define kOptScopeSize (kOptScopeBuf + 1)
+typedef uint8_t OptScopeFlags;
+
typedef union {
// boolean options are actually tri-states because they have a third "None" value.
TriState boolean;
@@ -161,9 +169,26 @@ typedef struct {
/// caller.
typedef int (*opt_expand_cb_T)(optexpand_T *args, int *numMatches, char ***matches);
-/// Requested option scopes for various functions in option.c
-typedef enum {
- kOptReqGlobal = 0, ///< Request global option value
- kOptReqWin = 1, ///< Request window-local option value
- kOptReqBuf = 2, ///< Request buffer-local option value
-} OptReqScope;
+typedef struct {
+ char *fullname; ///< full option name
+ char *shortname; ///< permissible abbreviation
+ uint32_t flags; ///< see above
+ OptTypeFlags type_flags; ///< option type flags, see OptValType
+ OptScopeFlags scope_flags; ///< option scope flags, see OptScope
+ void *var; ///< global option: pointer to variable;
+ ///< window-local option: NULL;
+ ///< buffer-local option: global value
+ ssize_t scope_idx[kOptScopeSize]; ///< index of option at every scope.
+ bool immutable; ///< option is immutable, trying to set it will give an error.
+
+ /// callback function to invoke after an option is modified to validate and
+ /// apply the new value.
+ opt_did_set_cb_T opt_did_set_cb;
+
+ /// callback function to invoke when expanding possible values on the
+ /// cmdline. Only useful for string options.
+ opt_expand_cb_T opt_expand_cb;
+
+ OptVal def_val; ///< default value
+ LastSet last_set; ///< script in which the option was last set
+} vimoption_T;
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 6fab0621f9..d61cba892b 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -7,7 +7,6 @@
--- @field alias? string|string[]
--- @field short_desc? string|fun(): string
--- @field varname? string
---- @field pv_name? string
--- @field type vim.option_type|vim.option_type[]
--- @field immutable? boolean
--- @field list? 'comma'|'onecomma'|'commacolon'|'onecommacolon'|'flags'|'flagscomma'
@@ -41,7 +40,7 @@
--- @field doc? string Default to show in options.txt
--- @field meta? integer|boolean|string Default to use in Lua meta files
---- @alias vim.option_scope 'global'|'buffer'|'window'
+--- @alias vim.option_scope 'global'|'buf'|'win'
--- @alias vim.option_type 'boolean'|'number'|'string'
--- @alias vim.option_value boolean|number|string
@@ -81,6 +80,8 @@ end
-- luacheck: ignore 621
return {
cstr = cstr,
+ --- @type string[]
+ valid_scopes = { 'global', 'buf', 'win' },
--- @type vim.option_meta[]
--- The order of the options MUST be alphabetic for ":set all".
options = {
@@ -173,7 +174,7 @@ return {
]=],
full_name = 'arabic',
redraw = { 'curswant' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('Arabic as a default second language'),
type = 'boolean',
},
@@ -236,7 +237,7 @@ return {
a different way.
]=],
full_name = 'autoindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('take indent for new line from previous line'),
type = 'boolean',
varname = 'p_ai',
@@ -256,7 +257,7 @@ return {
<
]=],
full_name = 'autoread',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('autom. read file when changed outside of Vim'),
type = 'boolean',
varname = 'p_ar',
@@ -457,7 +458,7 @@ return {
expand_cb = 'expand_set_backupcopy',
full_name = 'backupcopy',
list = 'onecomma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_("make backup as a copy, don't rename the file"),
type = 'string',
varname = 'p_bkc',
@@ -667,7 +668,7 @@ return {
]=],
full_name = 'binary',
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('read/write/edit file in binary mode'),
type = 'boolean',
varname = 'p_bin',
@@ -695,7 +696,7 @@ return {
full_name = 'bomb',
no_mkrc = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('a Byte Order Mark to the file'),
type = 'boolean',
varname = 'p_bomb',
@@ -729,7 +730,7 @@ return {
]=],
full_name = 'breakindent',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('wrapped line repeats indent'),
type = 'boolean',
},
@@ -771,7 +772,7 @@ return {
full_name = 'breakindentopt',
list = 'onecomma',
redraw = { 'current_buffer' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_("settings for 'breakindent'"),
type = 'string',
},
@@ -823,7 +824,7 @@ return {
expand_cb = 'expand_set_bufhidden',
full_name = 'bufhidden',
noglob = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('what to do when buffer is no longer in window'),
type = 'string',
varname = 'p_bh',
@@ -841,7 +842,7 @@ return {
]=],
full_name = 'buflisted',
noglob = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('whether the buffer shows up in the buffer list'),
tags = { 'E85' },
type = 'boolean',
@@ -900,7 +901,7 @@ return {
expand_cb = 'expand_set_buftype',
full_name = 'buftype',
noglob = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
tags = { 'E382' },
short_desc = N_('special type of buffer'),
type = 'string',
@@ -1015,7 +1016,7 @@ return {
full_name = 'channel',
no_mkrc = true,
nodefault = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('Channel connected to the buffer'),
type = 'number',
varname = 'p_channel',
@@ -1093,7 +1094,7 @@ return {
option or 'indentexpr'.
]=],
full_name = 'cindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('do C program indenting'),
type = 'boolean',
varname = 'p_cin',
@@ -1111,7 +1112,7 @@ return {
]=],
full_name = 'cinkeys',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("keys that trigger indent when 'cindent' is set"),
type = 'string',
varname = 'p_cink',
@@ -1128,7 +1129,7 @@ return {
]=],
full_name = 'cinoptions',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("how to do indenting when 'cindent' is set"),
type = 'string',
varname = 'p_cino',
@@ -1146,7 +1147,7 @@ return {
]=],
full_name = 'cinscopedecls',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("words that are recognized by 'cino-g'"),
type = 'string',
varname = 'p_cinsd',
@@ -1165,7 +1166,7 @@ return {
]=],
full_name = 'cinwords',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("words where 'si' and 'cin' add an indent"),
type = 'string',
varname = 'p_cinw',
@@ -1267,7 +1268,7 @@ return {
full_name = 'colorcolumn',
list = 'onecomma',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('columns to highlight'),
type = 'string',
},
@@ -1312,7 +1313,7 @@ return {
]=],
full_name = 'comments',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('patterns that can start a comment line'),
tags = { 'E524', 'E525' },
type = 'string',
@@ -1328,7 +1329,7 @@ return {
Used for |commenting| and to add markers for folding, see |fold-marker|.
]=],
full_name = 'commentstring',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('template for comments; used for fold marker'),
tags = { 'E537' },
type = 'string',
@@ -1385,7 +1386,7 @@ return {
expand_cb = 'expand_set_complete',
full_name = 'complete',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('specify how Insert mode completion works'),
tags = { 'E535' },
type = 'string',
@@ -1407,7 +1408,7 @@ return {
]=],
full_name = 'completefunc',
func = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
short_desc = N_('function to be used for Insert mode completion'),
type = 'string',
@@ -1483,7 +1484,7 @@ return {
expand_cb = 'expand_set_completeopt',
full_name = 'completeopt',
list = 'onecomma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('options for Insert mode completion'),
type = 'string',
varname = 'p_cot',
@@ -1508,7 +1509,7 @@ return {
enable_if = 'BACKSLASH_IN_FILENAME',
expand_cb = 'expand_set_completeslash',
full_name = 'completeslash',
- scope = { 'buffer' },
+ scope = { 'buf' },
type = 'string',
varname = 'p_csl',
},
@@ -1537,7 +1538,7 @@ return {
full_name = 'concealcursor',
list = 'flags',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('whether concealable text is hidden in cursor line'),
type = 'string',
},
@@ -1566,7 +1567,7 @@ return {
]=],
full_name = 'conceallevel',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('whether concealable text is shown or hidden'),
type = 'number',
},
@@ -1604,7 +1605,7 @@ return {
See 'preserveindent'.
]=],
full_name = 'copyindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("make 'autoindent' use existing indent structure"),
type = 'boolean',
varname = 'p_ci',
@@ -1865,8 +1866,7 @@ return {
taken into account.
]=],
full_name = 'cursorbind',
- pv_name = 'p_crbind',
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('move cursor in window as it moves in other windows'),
type = 'boolean',
},
@@ -1885,7 +1885,7 @@ return {
]=],
full_name = 'cursorcolumn',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('highlight the screen column of the cursor'),
type = 'boolean',
},
@@ -1900,7 +1900,7 @@ return {
]=],
full_name = 'cursorline',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('highlight the screen line of the cursor'),
type = 'boolean',
},
@@ -1928,7 +1928,7 @@ return {
full_name = 'cursorlineopt',
list = 'onecomma',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_("settings for 'cursorline'"),
type = 'string',
},
@@ -1979,7 +1979,7 @@ return {
<
]=],
full_name = 'define',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('pattern to be used to find a macro definition'),
type = 'string',
varname = 'p_def',
@@ -2036,7 +2036,7 @@ return {
full_name = 'dictionary',
list = 'onecomma',
normal_dname_chars = true,
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('list of file names used for keyword completion'),
type = 'string',
varname = 'p_dict',
@@ -2051,7 +2051,7 @@ return {
full_name = 'diff',
noglob = true,
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('diff mode for the current window'),
type = 'boolean',
},
@@ -2377,7 +2377,7 @@ return {
full_name = 'endoffile',
no_mkrc = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('write CTRL-Z for last line in file'),
type = 'boolean',
varname = 'p_eof',
@@ -2403,7 +2403,7 @@ return {
full_name = 'endofline',
no_mkrc = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('write <EOL> for last line in file'),
type = 'boolean',
varname = 'p_eol',
@@ -2448,7 +2448,7 @@ return {
]=],
expand = true,
full_name = 'equalprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('external program to use for "=" command'),
type = 'string',
@@ -2504,7 +2504,7 @@ return {
]=],
full_name = 'errorformat',
list = 'onecomma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('description of the lines in the error file'),
type = 'string',
varname = 'p_efm',
@@ -2540,7 +2540,7 @@ return {
on, use CTRL-V<Tab>. See also |:retab| and |ins-expandtab|.
]=],
full_name = 'expandtab',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('use spaces when <Tab> is inserted'),
type = 'boolean',
varname = 'p_et',
@@ -2614,7 +2614,7 @@ return {
full_name = 'fileencoding',
no_mkrc = true,
redraw = { 'statuslines', 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('file encoding for multi-byte text'),
tags = { 'E213' },
type = 'string',
@@ -2710,7 +2710,7 @@ return {
full_name = 'fileformat',
no_mkrc = true,
redraw = { 'curswant', 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('file format used for file I/O'),
type = 'string',
varname = 'p_ff',
@@ -2829,7 +2829,7 @@ return {
full_name = 'filetype',
noglob = true,
normal_fname_chars = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('type of file, used for autocommands'),
type = 'string',
varname = 'p_ft',
@@ -2904,7 +2904,7 @@ return {
full_name = 'fillchars',
list = 'onecomma',
redraw = { 'current_window' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('characters to use for displaying special items'),
type = 'string',
varname = 'p_fcs',
@@ -2962,7 +2962,7 @@ return {
]=],
full_name = 'findfunc',
func = true,
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('function called for :find'),
tags = { 'E1514' },
@@ -2984,7 +2984,7 @@ return {
]=],
full_name = 'fixendofline',
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('make sure last line in file has <EOL>'),
type = 'boolean',
varname = 'p_fixeol',
@@ -3024,7 +3024,7 @@ return {
expand_cb = 'expand_set_foldcolumn',
full_name = 'foldcolumn',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('width of the column used to indicate folds'),
type = 'string',
},
@@ -3042,7 +3042,7 @@ return {
]=],
full_name = 'foldenable',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('set to display all folds open'),
type = 'boolean',
},
@@ -3067,7 +3067,7 @@ return {
full_name = 'foldexpr',
modelineexpr = true,
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('expression used when \'foldmethod\' is "expr"'),
type = 'string',
},
@@ -3083,7 +3083,7 @@ return {
]=],
full_name = 'foldignore',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('ignore lines when \'foldmethod\' is "indent"'),
type = 'string',
},
@@ -3100,7 +3100,7 @@ return {
]=],
full_name = 'foldlevel',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('close folds with a level higher than this'),
type = 'number',
},
@@ -3139,7 +3139,7 @@ return {
full_name = 'foldmarker',
list = 'onecomma',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('markers used when \'foldmethod\' is "marker"'),
tags = { 'E536' },
type = 'string',
@@ -3160,7 +3160,7 @@ return {
expand_cb = 'expand_set_foldmethod',
full_name = 'foldmethod',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('folding type'),
type = 'string',
},
@@ -3179,7 +3179,7 @@ return {
]=],
full_name = 'foldminlines',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('minimum number of lines for a fold to be closed'),
type = 'number',
},
@@ -3194,7 +3194,7 @@ return {
]=],
full_name = 'foldnestmax',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('maximum fold depth'),
type = 'number',
},
@@ -3267,7 +3267,7 @@ return {
full_name = 'foldtext',
modelineexpr = true,
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('expression used to display for a closed fold'),
type = 'string',
},
@@ -3319,7 +3319,7 @@ return {
]=],
full_name = 'formatexpr',
modelineexpr = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('expression used with "gq" command'),
type = 'string',
varname = 'p_fex',
@@ -3339,7 +3339,7 @@ return {
character and white space.
]=],
full_name = 'formatlistpat',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('pattern used to recognize a list header'),
type = 'string',
varname = 'p_flp',
@@ -3359,7 +3359,7 @@ return {
expand_cb = 'expand_set_formatoptions',
full_name = 'formatoptions',
list = 'flags',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('how automatic formatting is to be done'),
type = 'string',
varname = 'p_fo',
@@ -3382,7 +3382,7 @@ return {
]=],
expand = true,
full_name = 'formatprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('name of external program used with "gq" command'),
type = 'string',
@@ -3490,7 +3490,7 @@ return {
]=],
expand = true,
full_name = 'grepprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('program to use for ":grep"'),
type = 'string',
@@ -4132,8 +4132,7 @@ return {
It is also used for the argument of commands like "r" and "f".
]=],
full_name = 'iminsert',
- pv_name = 'p_imi',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('use :lmap or IM in Insert mode'),
type = 'number',
varname = 'p_iminsert',
@@ -4155,8 +4154,7 @@ return {
option to a valid keymap name.
]=],
full_name = 'imsearch',
- pv_name = 'p_ims',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('use :lmap or IM when typing a search pattern'),
type = 'number',
varname = 'p_imsearch',
@@ -4203,7 +4201,7 @@ return {
See |option-backslash| about including spaces and backslashes.
]=],
full_name = 'include',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('pattern to be used to find an include file'),
type = 'string',
varname = 'p_inc',
@@ -4245,7 +4243,7 @@ return {
]=],
full_name = 'includeexpr',
modelineexpr = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('expression used to process an include line'),
type = 'string',
varname = 'p_inex',
@@ -4340,7 +4338,7 @@ return {
]=],
full_name = 'indentexpr',
modelineexpr = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('expression used to obtain the indent of a line'),
type = 'string',
varname = 'p_inde',
@@ -4357,7 +4355,7 @@ return {
]=],
full_name = 'indentkeys',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_("keys that trigger indenting with 'indentexpr'"),
type = 'string',
varname = 'p_indk',
@@ -4376,7 +4374,7 @@ return {
With 'noinfercase' the match is used as-is.
]=],
full_name = 'infercase',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('adjust case of match for keyword completion'),
type = 'boolean',
varname = 'p_inf',
@@ -4507,7 +4505,7 @@ return {
]=],
full_name = 'iskeyword',
list = 'comma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('characters included in keywords'),
type = 'string',
varname = 'p_isk',
@@ -4608,9 +4606,8 @@ return {
full_name = 'keymap',
normal_fname_chars = true,
pri_mkrc = true,
- pv_name = 'p_kmap',
redraw = { 'statuslines', 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('name of a keyboard mapping'),
type = 'string',
varname = 'p_keymap',
@@ -4662,7 +4659,7 @@ return {
]=],
expand = true,
full_name = 'keywordprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('program to use for the "K" command'),
type = 'string',
@@ -4833,7 +4830,7 @@ return {
]=],
full_name = 'linebreak',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('wrap long lines at a blank'),
type = 'boolean',
},
@@ -4897,7 +4894,7 @@ return {
calling an external program if 'equalprg' is empty.
]=],
full_name = 'lisp',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('indenting for Lisp'),
type = 'boolean',
varname = 'p_lisp',
@@ -4919,8 +4916,7 @@ return {
expand_cb = 'expand_set_lispoptions',
full_name = 'lispoptions',
list = 'onecomma',
- pv_name = 'p_lop',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('options for lisp indenting'),
type = 'string',
varname = 'p_lop',
@@ -4938,8 +4934,7 @@ return {
]=],
full_name = 'lispwords',
list = 'onecomma',
- pv_name = 'p_lw',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('words that change how lisp indenting works'),
type = 'string',
varname = 'p_lispwords',
@@ -4966,7 +4961,7 @@ return {
]=],
full_name = 'list',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('<Tab> and <EOL>'),
type = 'boolean',
},
@@ -5077,7 +5072,7 @@ return {
full_name = 'listchars',
list = 'onecomma',
redraw = { 'current_window' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('characters for displaying in list mode'),
type = 'string',
varname = 'p_lcs',
@@ -5158,7 +5153,7 @@ return {
]=],
expand_cb = 'expand_set_encoding',
full_name = 'makeencoding',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('Converts the output of external commands'),
type = 'string',
varname = 'p_menc',
@@ -5185,7 +5180,7 @@ return {
]=],
expand = true,
full_name = 'makeprg',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('program to use for the ":make" command'),
type = 'string',
@@ -5215,7 +5210,7 @@ return {
]=],
full_name = 'matchpairs',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('pairs of characters that "%" can match'),
type = 'string',
varname = 'p_mps',
@@ -5377,7 +5372,7 @@ return {
no lines are checked. See |modeline|.
]=],
full_name = 'modeline',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('recognize modelines at start or end of file'),
type = 'boolean',
varname = 'p_ml',
@@ -5425,7 +5420,7 @@ return {
]=],
full_name = 'modifiable',
noglob = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('changes to the text are not possible'),
tags = { 'E21' },
type = 'boolean',
@@ -5461,7 +5456,7 @@ return {
full_name = 'modified',
no_mkrc = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('buffer has been modified'),
type = 'boolean',
varname = 'p_mod',
@@ -5821,7 +5816,7 @@ return {
expand_cb = 'expand_set_nrformats',
full_name = 'nrformats',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('number formats recognized for CTRL-A command'),
type = 'string',
varname = 'p_nf',
@@ -5855,7 +5850,7 @@ return {
]=],
full_name = 'number',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('print the line number in front of each line'),
type = 'boolean',
},
@@ -5877,7 +5872,7 @@ return {
]=],
full_name = 'numberwidth',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('number of columns used for the line number'),
type = 'number',
},
@@ -5899,7 +5894,7 @@ return {
]=],
full_name = 'omnifunc',
func = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
short_desc = N_('function for filetype-specific completion'),
type = 'string',
@@ -6102,7 +6097,7 @@ return {
expand = true,
full_name = 'path',
list = 'comma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('list of directories searched with "gf" et.al.'),
tags = { 'E343', 'E345', 'E347', 'E854' },
type = 'string',
@@ -6126,7 +6121,7 @@ return {
Use |:retab| to clean up white space.
]=],
full_name = 'preserveindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('preserve the indent structure when reindenting'),
type = 'boolean',
varname = 'p_pi',
@@ -6156,7 +6151,7 @@ return {
full_name = 'previewwindow',
noglob = true,
redraw = { 'statuslines' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('identifies the preview window'),
tags = { 'E590' },
type = 'boolean',
@@ -6275,7 +6270,7 @@ return {
text "foo\"bar\\" considered to be one string.
]=],
full_name = 'quoteescape',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('escape characters used in a string'),
type = 'string',
varname = 'p_qe',
@@ -6297,7 +6292,7 @@ return {
full_name = 'readonly',
noglob = true,
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('disallow writing the buffer'),
type = 'boolean',
varname = 'p_ro',
@@ -6413,7 +6408,7 @@ return {
]=],
full_name = 'relativenumber',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('show relative line number in front of each line'),
type = 'boolean',
},
@@ -6470,7 +6465,7 @@ return {
]=],
full_name = 'rightleft',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('window is right-to-left oriented'),
type = 'boolean',
},
@@ -6490,7 +6485,7 @@ return {
expand_cb = 'expand_set_rightleftcmd',
full_name = 'rightleftcmd',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('commands for which editing works right-to-left'),
type = 'string',
},
@@ -6672,8 +6667,7 @@ return {
]=],
full_name = 'scroll',
no_mkrc = true,
- pv_name = 'p_scroll',
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('lines to scroll with CTRL-U and CTRL-D'),
type = 'number',
},
@@ -6695,7 +6689,7 @@ return {
]=],
full_name = 'scrollback',
redraw = { 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('lines to scroll with CTRL-U and CTRL-D'),
type = 'number',
varname = 'p_scbk',
@@ -6716,8 +6710,7 @@ return {
with scroll-binding, but ":split file" does not.
]=],
full_name = 'scrollbind',
- pv_name = 'p_scbind',
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('scroll in window as other windows scroll'),
type = 'boolean',
},
@@ -6754,7 +6747,7 @@ return {
< For scrolling horizontally see 'sidescrolloff'.
]=],
full_name = 'scrolloff',
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('minimum nr. of lines above and below cursor'),
type = 'number',
varname = 'p_so',
@@ -7404,7 +7397,7 @@ return {
function to get the effective shiftwidth value.
]=],
full_name = 'shiftwidth',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('number of spaces to use for (auto)indent step'),
type = 'number',
varname = 'p_sw',
@@ -7502,7 +7495,7 @@ return {
]=],
full_name = 'showbreak',
redraw = { 'all_windows' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('string to use at the start of wrapped lines'),
tags = { 'E595' },
type = 'string',
@@ -7676,7 +7669,7 @@ return {
<
]=],
full_name = 'sidescrolloff',
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('min. nr. of columns to left and right of cursor'),
type = 'number',
varname = 'p_siso',
@@ -7706,7 +7699,7 @@ return {
expand_cb = 'expand_set_signcolumn',
full_name = 'signcolumn',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('when to display the sign column'),
type = 'string',
},
@@ -7752,7 +7745,7 @@ return {
right.
]=],
full_name = 'smartindent',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('smart autoindenting for C programs'),
type = 'boolean',
varname = 'p_si',
@@ -7792,9 +7785,8 @@ return {
NOTE: partly implemented, doesn't work yet for |gj| and |gk|.
]=],
full_name = 'smoothscroll',
- pv_name = 'p_sms',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_("scroll by screen lines when 'wrap' is set"),
type = 'boolean',
},
@@ -7819,7 +7811,7 @@ return {
to anything other than an empty string.
]=],
full_name = 'softtabstop',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('number of spaces that <Tab> uses while editing'),
type = 'number',
varname = 'p_sts',
@@ -7833,7 +7825,7 @@ return {
]=],
full_name = 'spell',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('spell checking'),
type = 'boolean',
},
@@ -7854,7 +7846,7 @@ return {
]=],
full_name = 'spellcapcheck',
redraw = { 'current_buffer', 'highlight_only' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('pattern to locate end of a sentence'),
type = 'string',
varname = 'p_spc',
@@ -7890,7 +7882,7 @@ return {
expand = true,
full_name = 'spellfile',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
short_desc = N_('files where |zg| and |zw| store words'),
type = 'string',
@@ -7943,7 +7935,7 @@ return {
full_name = 'spelllang',
list = 'onecomma',
redraw = { 'current_buffer', 'highlight_only' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('language(s) to do spell checking for'),
type = 'string',
varname = 'p_spl',
@@ -7968,7 +7960,7 @@ return {
full_name = 'spelloptions',
list = 'onecomma',
redraw = { 'current_buffer', 'highlight_only' },
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
type = 'string',
varname = 'p_spo',
@@ -8189,7 +8181,7 @@ return {
]=],
full_name = 'statuscolumn',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
secure = true,
short_desc = N_('custom format for the status column'),
type = 'string',
@@ -8413,7 +8405,7 @@ return {
full_name = 'statusline',
modelineexpr = true,
redraw = { 'statuslines' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('custom format for the status line'),
tags = { 'E540', 'E542' },
type = 'string',
@@ -8454,7 +8446,7 @@ return {
]=],
full_name = 'suffixesadd',
list = 'onecomma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('suffixes added when searching for a file'),
type = 'string',
varname = 'p_sua',
@@ -8485,7 +8477,7 @@ return {
]=],
full_name = 'swapfile',
redraw = { 'statuslines' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('whether to use a swapfile for a buffer'),
type = 'boolean',
varname = 'p_swf',
@@ -8545,7 +8537,7 @@ return {
]=],
full_name = 'synmaxcol',
redraw = { 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('maximum column to find syntax items'),
type = 'number',
varname = 'p_smc',
@@ -8582,7 +8574,7 @@ return {
full_name = 'syntax',
noglob = true,
normal_fname_chars = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('syntax to be loaded for current buffer'),
type = 'string',
varname = 'p_syn',
@@ -8705,7 +8697,7 @@ return {
]=],
full_name = 'tabstop',
redraw = { 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('number of spaces that <Tab> in file uses'),
type = 'number',
varname = 'p_ts',
@@ -8784,7 +8776,7 @@ return {
]=],
expand_cb = 'expand_set_tagcase',
full_name = 'tagcase',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('how to handle case when searching in tags files'),
type = 'string',
varname = 'p_tc',
@@ -8805,7 +8797,7 @@ return {
]=],
full_name = 'tagfunc',
func = true,
- scope = { 'buffer' },
+ scope = { 'buf' },
secure = true,
short_desc = N_('function used to perform tag searches'),
type = 'string',
@@ -8862,7 +8854,7 @@ return {
expand = true,
full_name = 'tags',
list = 'onecomma',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('list of file names used by the tag command'),
tags = { 'E433' },
type = 'string',
@@ -9002,7 +8994,7 @@ return {
]=],
full_name = 'textwidth',
redraw = { 'current_buffer', 'highlight_only' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('maximum width of text that is being inserted'),
type = 'number',
varname = 'p_tw',
@@ -9031,7 +9023,7 @@ return {
full_name = 'thesaurus',
list = 'onecomma',
normal_dname_chars = true,
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('list of thesaurus files for keyword completion'),
type = 'string',
varname = 'p_tsr',
@@ -9051,7 +9043,7 @@ return {
]=],
full_name = 'thesaurusfunc',
func = true,
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
secure = true,
short_desc = N_('function used for thesaurus completion'),
type = 'string',
@@ -9165,6 +9157,10 @@ return {
expanded according to the rules used for 'statusline'. If it contains
an invalid '%' format, the value is used as-is and no error or warning
will be given when the value is set.
+
+ The default behaviour is equivalent to: >vim
+ set titlestring=%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim
+ <
This option cannot be set in a modeline when 'modelineexpr' is off.
Example: >vim
@@ -9285,7 +9281,7 @@ return {
When 'undofile' is turned off the undo file is NOT deleted.
]=],
full_name = 'undofile',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('save undo information in a file'),
type = 'boolean',
varname = 'p_udf',
@@ -9314,7 +9310,7 @@ return {
Also see |clear-undo|.
]=],
full_name = 'undolevels',
- scope = { 'global', 'buffer' },
+ scope = { 'global', 'buf' },
short_desc = N_('maximum number of changes that can be undone'),
type = 'number',
varname = 'p_ul',
@@ -9401,7 +9397,7 @@ return {
]=],
full_name = 'varsofttabstop',
list = 'comma',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('list of numbers of spaces that <Tab> uses while editing'),
type = 'string',
varname = 'p_vsts',
@@ -9424,7 +9420,7 @@ return {
full_name = 'vartabstop',
list = 'comma',
redraw = { 'current_buffer' },
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('list of numbers of spaces that <Tab> in file uses'),
type = 'string',
varname = 'p_vts',
@@ -9570,7 +9566,7 @@ return {
full_name = 'virtualedit',
list = 'onecomma',
redraw = { 'curswant' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('when to use virtual editing'),
type = 'string',
varname = 'p_ve',
@@ -9917,7 +9913,7 @@ return {
full_name = 'winbar',
modelineexpr = true,
redraw = { 'statuslines' },
- scope = { 'global', 'window' },
+ scope = { 'global', 'win' },
short_desc = N_('custom format for the window bar'),
type = 'string',
varname = 'p_wbr',
@@ -9935,7 +9931,7 @@ return {
]=],
full_name = 'winblend',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('Controls transparency level for floating windows'),
type = 'number',
},
@@ -9974,8 +9970,7 @@ return {
command has a "!" modifier, it can force switching buffers.
]=],
full_name = 'winfixbuf',
- pv_name = 'p_wfb',
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('pin a window to a specific buffer'),
type = 'boolean',
},
@@ -9990,7 +9985,7 @@ return {
]=],
full_name = 'winfixheight',
redraw = { 'statuslines' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('keep window height when opening/closing windows'),
type = 'boolean',
},
@@ -10004,7 +9999,7 @@ return {
]=],
full_name = 'winfixwidth',
redraw = { 'statuslines' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('keep window width when opening/closing windows'),
type = 'boolean',
},
@@ -10065,7 +10060,7 @@ return {
full_name = 'winhighlight',
list = 'onecommacolon',
redraw = { 'current_window', 'highlight_only' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('Setup window-local highlights'),
type = 'string',
},
@@ -10156,7 +10151,7 @@ return {
]=],
full_name = 'wrap',
redraw = { 'current_window' },
- scope = { 'window' },
+ scope = { 'win' },
short_desc = N_('lines wrap and continue on the next line'),
type = 'boolean',
},
@@ -10173,7 +10168,7 @@ return {
See also 'formatoptions' and |ins-textwidth|.
]=],
full_name = 'wrapmargin',
- scope = { 'buffer' },
+ scope = { 'buf' },
short_desc = N_('chars from the right where wrapping starts'),
type = 'number',
varname = 'p_wm',
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index 7df6a1a5d7..d1951d4f96 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -880,7 +880,7 @@ static void pum_adjust_info_position(win_T *wp, int height, int width)
/// Used for nvim__complete_set
///
/// @param selected the selected compl item.
-/// @parma info Info string.
+/// @param info Info string.
/// @return a win_T pointer.
win_T *pum_set_info(int selected, char *info)
{
diff --git a/src/nvim/search.c b/src/nvim/search.c
index debc5697d1..159ab35f6f 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1203,6 +1203,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen
// Compute msg_row early.
msg_start();
+ msg_ext_set_kind("search_cmd");
// Get the offset, so we know how long it is.
if (!cmd_silent
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index b37f01e769..0ddf4ffa38 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -516,6 +516,7 @@ void spell_suggest(int count)
spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit,
true, need_cap, true);
+ msg_ext_set_kind("list_cmd");
if (GA_EMPTY(&sug.su_ga)) {
msg(_("Sorry, no suggestions"), 0);
} else if (count > 0) {
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index ba64633df7..4e78067d46 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -760,7 +760,9 @@ void draw_tabline(void)
bool modified = false;
for (wincount = 0; wp != NULL; wp = wp->w_next, wincount++) {
- if (bufIsChanged(wp->w_buffer)) {
+ if (!wp->w_config.focusable) {
+ wincount--;
+ } else if (bufIsChanged(wp->w_buffer)) {
modified = true;
}
}
diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c
index 9095d4e8c9..06b3aa0411 100644
--- a/src/nvim/textformat.c
+++ b/src/nvim/textformat.c
@@ -863,7 +863,7 @@ int fex_format(linenr_T lnum, long count, int c)
// Make a copy, the option could be changed while calling it.
char *fex = xstrdup(curbuf->b_p_fex);
- current_sctx = curbuf->b_p_script_ctx[BV_FEX].script_ctx;
+ current_sctx = curbuf->b_p_script_ctx[kBufOptFormatexpr].script_ctx;
// Evaluate the function.
if (use_sandbox) {
diff --git a/src/nvim/tui/termkey/termkey-internal.h b/src/nvim/tui/termkey/termkey-internal.h
index 107591f950..97fae939c5 100644
--- a/src/nvim/tui/termkey/termkey-internal.h
+++ b/src/nvim/tui/termkey/termkey-internal.h
@@ -47,7 +47,7 @@ struct TermKey {
int canonflags;
unsigned char *buffer;
size_t buffstart; // First offset in buffer
- size_t buffcount; // NUMBER of entires valid in buffer
+ size_t buffcount; // NUMBER of entries valid in buffer
size_t buffsize; // Total malloc'ed size
size_t hightide; // Position beyond buffstart at which peekkey() should next start
// normally 0, but see also termkey_interpret_csi
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 7c81110ae9..eba821a53d 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -721,7 +721,7 @@ void ui_call_event(char *name, bool fast, Array args)
// Prompt messages should be shown immediately so must be safe
if (strcmp(name, "msg_show") == 0) {
char *kind = args.items[0].data.string.data;
- fast = !kind || (strncmp(kind, "confirm", 7) != 0 && strcmp(kind, "return_prompt") != 0);
+ fast = !kind || ((strncmp(kind, "confirm", 7) != 0 && strstr(kind, "_prompt") == NULL));
}
map_foreach(&ui_event_cbs, ui_event_ns_id, event_cb, {
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 5f17d3220d..c3f3e075f1 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6755,8 +6755,8 @@ void win_comp_scroll(win_T *wp)
if (wp->w_p_scr != old_w_p_scr) {
// Used by "verbose set scroll".
- wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_sid = SID_WINLAYOUT;
- wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_lnum = 0;
+ wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_sid = SID_WINLAYOUT;
+ wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_lnum = 0;
}
}
diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c
index 4698487708..b8a51d686d 100644
--- a/src/nvim/winfloat.c
+++ b/src/nvim/winfloat.c
@@ -412,8 +412,8 @@ win_T *win_float_create(bool enter, bool new_buf)
return handle_error_and_cleanup(wp, &err);
}
buf->b_p_bl = false; // unlist
- set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0, kOptReqBuf,
- buf);
+ set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0,
+ kOptScopeBuf, buf);
win_set_buf(wp, buf, &err);
if (ERROR_SET(&err)) {
return handle_error_and_cleanup(wp, &err);
diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg
index 50cee638af..91a72fa318 100644
--- a/src/uncrustify.cfg
+++ b/src/uncrustify.cfg
@@ -1,4 +1,4 @@
-# Uncrustify-0.79.0_f
+# Uncrustify-0.80.1_f
#
# General options
@@ -422,6 +422,10 @@ sp_invariant_paren = ignore # ignore/add/remove/force
sp_after_invariant_paren = ignore # ignore/add/remove/force
# Add or remove space before empty statement ';' on 'if', 'for' and 'while'.
+# examples:
+# if (b) <here> ;
+# for (a=1; a<10; a++) <here> ;
+# while (*p++ = ' ') <here> ;
sp_special_semi = ignore # ignore/add/remove/force
# Add or remove space before ';'.
@@ -1103,6 +1107,10 @@ sp_after_emb_cmt = force # ignore/add/remove/force
# Default: 1
sp_num_after_emb_cmt = 1 # unsigned number
+# Embedded comment spacing options have higher priority (== override)
+# than other spacing options (comma, parenthesis, braces, ...)
+sp_emb_cmt_priority = false # true/false
+
# (Java) Add or remove space between an annotation and the open parenthesis.
sp_annotation_paren = ignore # ignore/add/remove/force
@@ -1127,6 +1135,9 @@ force_tab_after_define = false # true/false
# Add or remove space between two strings.
sp_string_string = force # ignore/add/remove/force
+# Add or remove space 'struct' and a type.
+sp_struct_type = ignore # ignore/add/remove/force
+
#
# Indenting options
#
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index c7aa1f48da..3f1e378bc1 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -3582,6 +3582,15 @@ describe('API', function()
command('highlight Special guifg=SlateBlue')
end)
+ it('validation', function()
+ eq("Invalid 'chunk': expected Array, got String", pcall_err(api.nvim_echo, { 'msg' }, 1, {}))
+ eq(
+ 'Invalid chunk: expected Array with 1 or 2 Strings',
+ pcall_err(api.nvim_echo, { { '', '', '' } }, 1, {})
+ )
+ eq('Invalid hl_group: text highlight', pcall_err(api.nvim_echo, { { '', false } }, 1, {}))
+ end)
+
it('should clear cmdline message before echo', function()
feed(':call nvim_echo([["msg"]], v:false, {})<CR>')
screen:expect {
@@ -3606,6 +3615,18 @@ describe('API', function()
msg_a{15:msg_b}{16:msg_c} |
]],
}
+ async_meths.nvim_echo({
+ { 'msg_d' },
+ { 'msg_e', api.nvim_get_hl_id_by_name('Statement') },
+ { 'msg_f', api.nvim_get_hl_id_by_name('Special') },
+ }, true, {})
+ screen:expect {
+ grid = [[
+ ^ |
+ {1:~ }|*6
+ msg_d{15:msg_e}{16:msg_f} |
+ ]],
+ }
end)
it('can show highlighted multiline', function()
diff --git a/test/functional/autocmd/completedone_spec.lua b/test/functional/autocmd/completedone_spec.lua
index 33beb16db2..36dc73842d 100644
--- a/test/functional/autocmd/completedone_spec.lua
+++ b/test/functional/autocmd/completedone_spec.lua
@@ -32,7 +32,7 @@ describe('CompleteDone', function()
feed('<Esc>')
eq('cancel', eval('g:donereason'))
end)
- it('when overriden by another complete()', function()
+ it('when overridden by another complete()', function()
call('complete', call('col', '.'), { 'bar', 'baz' })
eq('cancel', eval('g:donereason'))
end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index e885164c20..f3c477d210 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -277,10 +277,8 @@ describe('startup', function()
-- nvim <vim args> -l foo.lua <vim args>
assert_l_out(
- -- luacheck: ignore 611 (Line contains only whitespaces)
[[
wrap
-
bufs:
nvim args: 7
lua args: { "-c", "set wrap?",
@@ -345,7 +343,7 @@ describe('startup', function()
local screen = Screen.new(25, 3)
-- Remote UI connected by --embed.
-- TODO: a lot of tests in this file already use the new default color scheme.
- -- once we do the batch update of tests to use it, remove this workarond
+ -- once we do the batch update of tests to use it, remove this workaround
screen._default_attr_ids = nil
command([[echo has('ttyin') has('ttyout')]])
screen:expect([[
diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua
index 7110d216f8..82d285cc9a 100644
--- a/test/functional/editor/defaults_spec.lua
+++ b/test/functional/editor/defaults_spec.lua
@@ -172,6 +172,30 @@ describe('default', function()
first line]])
end)
+
+ it('supports dot repetition', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed('[<Space>')
+ n.feed('.')
+ n.expect([[
+
+
+ first line]])
+ end)
+
+ it('supports dot repetition and a count', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed('[<Space>')
+ n.feed('3.')
+ n.expect([[
+
+
+
+
+ first line]])
+ end)
end)
describe(']<Space>', function()
@@ -196,6 +220,29 @@ describe('default', function()
]])
end)
+
+ it('supports dot repetition', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed(']<Space>')
+ n.feed('.')
+ n.expect([[
+ first line
+
+ ]])
+ end)
+
+ it('supports dot repetition and a count', function()
+ n.clear({ args_rm = { '--cmd' } })
+ n.insert([[first line]])
+ n.feed(']<Space>')
+ n.feed('2.')
+ n.expect([[
+ first line
+
+
+ ]])
+ end)
end)
end)
end)
diff --git a/test/functional/legacy/normal_spec.lua b/test/functional/legacy/normal_spec.lua
index 717ebbba70..1ae22a83bd 100644
--- a/test/functional/legacy/normal_spec.lua
+++ b/test/functional/legacy/normal_spec.lua
@@ -102,4 +102,33 @@ describe('normal', function()
]],
})
end)
+
+ -- oldtest: Test_normal_gm()
+ it('gm sets curswant correctly', function()
+ screen:try_resize(75, 10)
+ exec([[
+ call setline(1, repeat([" abcd\tefgh\tij"], 10))
+ call cursor(1, 1)
+ ]])
+ feed('jVjzf')
+ -- gm
+ feed('gmk')
+ eq(18, fn.virtcol('.'))
+ -- g0
+ feed('gj0k')
+ eq(1, fn.virtcol('.'))
+ -- g^
+ feed('jg^k')
+ eq(3, fn.virtcol('.'))
+ exec('call cursor(10, 1)')
+ -- gm
+ feed('gmk')
+ eq(18, fn.virtcol('.'))
+ -- g0
+ feed('gj0k')
+ eq(1, fn.virtcol('.'))
+ -- g^
+ feed('jg^k')
+ eq(3, fn.virtcol('.'))
+ end)
end)
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
index 574c837f92..b6011d5268 100644
--- a/test/functional/lua/filetype_spec.lua
+++ b/test/functional/lua/filetype_spec.lua
@@ -161,6 +161,18 @@ describe('vim.filetype', function()
end
end
end)
+
+ it('.get_option() cleans up buffer on error', function()
+ api.nvim_create_autocmd('FileType', { pattern = 'foo', command = 'lua error()' })
+
+ local buf = api.nvim_get_current_buf()
+
+ exec_lua(function()
+ pcall(vim.filetype.get_option, 'foo', 'lisp')
+ end)
+
+ eq(buf, api.nvim_get_current_buf())
+ end)
end)
describe('filetype.lua', function()
diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua
index afbada007d..3f847ca3be 100644
--- a/test/functional/lua/system_spec.lua
+++ b/test/functional/lua/system_spec.lua
@@ -114,7 +114,7 @@ describe('vim.system', function()
end)
if t.is_os('win') then
- it('can resolve windows command extentions.', function()
+ it('can resolve windows command extensions', function()
t.write_file('test.bat', 'echo hello world')
system_sync({ 'chmod', '+x', 'test.bat' })
system_sync({ './test' })
diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua
index 6d4be4d1f2..f1cf657d78 100644
--- a/test/functional/lua/ui_event_spec.lua
+++ b/test/functional/lua/ui_event_spec.lua
@@ -142,7 +142,7 @@ describe('vim.ui_attach', function()
'msg_history_show',
{
{ 'echomsg', { { 0, 'message1', 0 } } },
- { '', { { 0, 'message2', 0 } } },
+ { 'lua_print', { { 0, 'message2', 0 } } },
{ 'echomsg', { { 0, 'message3', 0 } } },
},
},
@@ -285,6 +285,26 @@ describe('vim.ui_attach', function()
},
},
})
+ feed('<esc>:call inputlist(["Select:", "One", "Two"])<cr>')
+ screen:expect({
+ grid = [[
+ E122: {10:Function} Foo already exists, add !|
+ to replace it |
+ Type number and <Enter> or click with th|
+ e mouse (q or empty cancels): |
+ {1:^~ }|
+ ]],
+ messages = {
+ {
+ content = { { 'Select:\nOne\nTwo\n' } },
+ kind = 'list_cmd',
+ },
+ {
+ content = { { 'Type number and <Enter> or click with the mouse (q or empty cancels): ' } },
+ kind = 'number_prompt',
+ },
+ },
+ })
end)
end)
diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua
index a36cbac568..95fc22b96b 100644
--- a/test/functional/plugin/lsp/testutil.lua
+++ b/test/functional/plugin/lsp/testutil.lua
@@ -182,16 +182,17 @@ function M.test_rpc_server(config)
)
end
local client = setmetatable({}, {
- __index = function(_, name)
+ __index = function(t, name)
-- Workaround for not being able to yield() inside __index for Lua 5.1 :(
-- Otherwise I would just return the value here.
- return function(...)
+ return function(arg1, ...)
+ local ismethod = arg1 == t
return exec_lua(function(...)
- if type(_G.TEST_RPC_CLIENT[name]) == 'function' then
- return _G.TEST_RPC_CLIENT[name](...)
- else
- return _G.TEST_RPC_CLIENT[name]
+ local client = _G.TEST_RPC_CLIENT
+ if type(client[name]) == 'function' then
+ return client[name](ismethod and client or arg1, ...)
end
+ return client[name]
end, ...)
end
end,
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 5222216faf..f14e24bb19 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -232,7 +232,7 @@ describe('LSP', function()
-- client is a dummy object which will queue up commands to be run
-- once the server initializes. It can't accept lua callbacks or
-- other types that may be unserializable for now.
- client.stop()
+ client:stop()
end,
-- If the program timed out, then code will be nil.
on_exit = function(code, signal)
@@ -254,8 +254,8 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_init',
on_init = function(client)
- client.notify('test')
- client.stop()
+ client:notify('test')
+ client:stop()
end,
on_exit = function(code, signal)
eq(101, code, 'exit code') -- See fake-lsp-server.lua
@@ -275,7 +275,7 @@ describe('LSP', function()
test_rpc_server({
test_name = 'basic_init_did_change_configuration',
on_init = function(client, _)
- client.stop()
+ client:stop()
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -333,9 +333,9 @@ describe('LSP', function()
test_name = 'basic_init',
on_init = function(client)
eq(0, client.server_capabilities().textDocumentSync.change)
- client.request('shutdown')
- client.notify('exit')
- client.stop()
+ client:request('shutdown')
+ client:notify('exit')
+ client:stop()
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -377,7 +377,7 @@ describe('LSP', function()
end,
on_init = function(_client)
client = _client
- client.notify('finish')
+ client:notify('finish')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -395,7 +395,7 @@ describe('LSP', function()
return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
end)
)
- client.stop()
+ client:stop()
end
end,
}
@@ -430,7 +430,7 @@ describe('LSP', function()
return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
end)
)
- client.notify('finish')
+ client:notify('finish')
end,
on_handler = function(_, _, ctx)
if ctx.method == 'finish' then
@@ -439,7 +439,7 @@ describe('LSP', function()
return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
end)
eq('basic_init', api.nvim_get_var('lsp_detached'))
- client.stop()
+ client:stop()
end
end,
}
@@ -472,7 +472,7 @@ describe('LSP', function()
return keymap.callback == vim.lsp.buf.hover
end)
)
- client.stop()
+ client:stop()
end
end,
on_exit = function(_, _)
@@ -524,7 +524,7 @@ describe('LSP', function()
eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', BUFFER_1))
eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', BUFFER_2))
eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', BUFFER_2))
- client.stop()
+ client:stop()
end
end,
on_exit = function(_, _)
@@ -554,7 +554,7 @@ describe('LSP', function()
eq('tfu', get_buf_option('tagfunc'))
eq('ofu', get_buf_option('omnifunc'))
eq('fex', get_buf_option('formatexpr'))
- client.stop()
+ client:stop()
end
end,
on_exit = function(_, _)
@@ -711,10 +711,10 @@ describe('LSP', function()
ctx.method,
result
)
- client.notify('workspace/configuration', server_result)
+ client:notify('workspace/configuration', server_result)
end
if ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -756,7 +756,7 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_capabilities',
on_init = function(client)
- client.stop()
+ client:stop()
local full_kind = exec_lua(function()
return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
end)
@@ -798,7 +798,7 @@ describe('LSP', function()
vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
end)
else
- client.stop()
+ client:stop()
end
end,
}
@@ -898,7 +898,7 @@ describe('LSP', function()
end)
end)
else
- client.stop()
+ client:stop()
end
end,
})
@@ -929,20 +929,20 @@ describe('LSP', function()
vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
end)
else
- client.stop()
+ client:stop()
end
end,
}
end)
- it('client.supports_methods() should validate capabilities', function()
+ it('client:supports_methods() should validate capabilities', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
}
test_rpc_server {
test_name = 'capabilities_for_client_supports_method',
on_init = function(client)
- client.stop()
+ client:stop()
local expected_sync_capabilities = {
change = 1,
openClose = true,
@@ -958,11 +958,11 @@ describe('LSP', function()
eq(true, client.server_capabilities().codeLensProvider.resolveProvider)
-- known methods for resolved capabilities
- eq(true, client.supports_method('textDocument/hover'))
- eq(false, client.supports_method('textDocument/definition'))
+ 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'))
+ eq(true, client:supports_method('unknown-method'))
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -989,7 +989,7 @@ describe('LSP', function()
end)
end,
on_init = function(client)
- client.stop()
+ client:stop()
exec_lua(function()
vim.lsp.buf.type_definition()
end)
@@ -1018,7 +1018,7 @@ describe('LSP', function()
end)
end,
on_init = function(client)
- client.stop()
+ client:stop()
exec_lua(function()
vim.lsp.buf.type_definition()
end)
@@ -1042,7 +1042,7 @@ describe('LSP', function()
test_rpc_server {
test_name = 'check_forward_request_cancelled',
on_init = function(_client)
- _client.request('error_code_test')
+ _client:request('error_code_test')
client = _client
end,
on_exit = function(code, signal)
@@ -1053,7 +1053,7 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1072,7 +1072,7 @@ describe('LSP', function()
test_rpc_server {
test_name = 'check_forward_content_modified',
on_init = function(_client)
- _client.request('error_code_test')
+ _client:request('error_code_test')
client = _client
end,
on_exit = function(code, signal)
@@ -1084,10 +1084,10 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, _, ctx }, 'expected handler')
-- if ctx.method == 'error_code_test' then client.notify("finish") end
if ctx.method ~= 'finish' then
- client.notify('finish')
+ client:notify('finish')
end
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1103,13 +1103,13 @@ describe('LSP', function()
test_name = 'check_pending_request_tracked',
on_init = function(_client)
client = _client
- client.request('slow_request')
+ client:request('slow_request')
local request = exec_lua(function()
return _G.TEST_RPC_CLIENT.requests[2]
end)
eq('slow_request', request.method)
eq('pending', request.type)
- client.notify('release')
+ client:notify('release')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1123,10 +1123,10 @@ describe('LSP', function()
return _G.TEST_RPC_CLIENT.requests[2]
end)
eq(nil, request)
- client.notify('finish')
+ client:notify('finish')
end
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1141,14 +1141,14 @@ describe('LSP', function()
test_name = 'check_cancel_request_tracked',
on_init = function(_client)
client = _client
- client.request('slow_request')
- client.cancel_request(2)
+ client:request('slow_request')
+ client:cancel_request(2)
local request = exec_lua(function()
return _G.TEST_RPC_CLIENT.requests[2]
end)
eq('slow_request', request.method)
eq('cancel', request.type)
- client.notify('release')
+ client:notify('release')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1162,7 +1162,7 @@ describe('LSP', function()
end)
eq(nil, request)
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1178,19 +1178,19 @@ describe('LSP', function()
test_name = 'check_tracked_requests_cleared',
on_init = function(_client)
client = _client
- client.request('slow_request')
+ client:request('slow_request')
local request = exec_lua(function()
return _G.TEST_RPC_CLIENT.requests[2]
end)
eq('slow_request', request.method)
eq('pending', request.type)
- client.cancel_request(2)
+ client:cancel_request(2)
request = exec_lua(function()
return _G.TEST_RPC_CLIENT.requests[2]
end)
eq('slow_request', request.method)
eq('cancel', request.type)
- client.notify('release')
+ client:notify('release')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1204,10 +1204,10 @@ describe('LSP', function()
return _G.TEST_RPC_CLIENT.requests[2]
end)
eq(nil, request)
- client.notify('finish')
+ client:notify('finish')
end
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1225,11 +1225,11 @@ describe('LSP', function()
command('let g:requests = 0')
command('autocmd LspRequest * let g:requests+=1')
client = _client
- client.request('slow_request')
+ client:request('slow_request')
eq(1, eval('g:requests'))
- client.cancel_request(2)
+ client:cancel_request(2)
eq(2, eval('g:requests'))
- client.notify('release')
+ client:notify('release')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1240,10 +1240,10 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'slow_request' then
- client.notify('finish')
+ client:notify('finish')
end
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1277,7 +1277,7 @@ describe('LSP', function()
end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- client.notify('finish')
+ client:notify('finish')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1286,7 +1286,7 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1333,11 +1333,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1378,11 +1378,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1428,11 +1428,11 @@ describe('LSP', function()
'boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1479,11 +1479,11 @@ describe('LSP', function()
'boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1529,7 +1529,7 @@ describe('LSP', function()
end,
on_init = function(_client)
client = _client
- eq(true, client.supports_method('textDocument/inlayHint'))
+ eq(true, client:supports_method('textDocument/inlayHint'))
exec_lua(function()
assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
end)
@@ -1545,11 +1545,11 @@ describe('LSP', function()
end)
end
if ctx.method == 'textDocument/inlayHint' then
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1598,11 +1598,11 @@ describe('LSP', function()
'123boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1652,11 +1652,11 @@ describe('LSP', function()
'123boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1699,11 +1699,11 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
n.command('normal! 1Go')
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1752,11 +1752,11 @@ describe('LSP', function()
'boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1806,11 +1806,11 @@ describe('LSP', function()
})
vim.api.nvim_command(_G.BUFFER .. 'bwipeout')
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1830,7 +1830,7 @@ describe('LSP', function()
on_setup = function() end,
on_init = function(_client)
client = _client
- client.stop(true)
+ client:stop(true)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1882,7 +1882,7 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -2348,7 +2348,7 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_init',
on_init = function(client, _)
- client.stop()
+ client:stop()
end,
-- If the program timed out, then code will be nil.
on_exit = function(code, signal)
@@ -3499,7 +3499,7 @@ describe('LSP', function()
}
return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'zig', { '(' })
end)
- -- Note that although the higlight positions below are 0-indexed, the 2nd parameter
+ -- Note that although the highlight positions below are 0-indexed, the 2nd parameter
-- corresponds to the 3rd line because the first line is the ``` from the
-- Markdown block.
local expected = { 3, 4, 3, 11 }
@@ -4284,7 +4284,7 @@ describe('LSP', function()
end)
)
end
- client.stop()
+ client:stop()
end
end,
}
@@ -4331,7 +4331,7 @@ describe('LSP', function()
return type(vim.lsp.commands['dummy2'])
end)
)
- client.stop()
+ client:stop()
end
end,
}
@@ -4372,7 +4372,7 @@ describe('LSP', function()
vim.lsp.buf.code_action()
end)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
})
@@ -4447,7 +4447,7 @@ describe('LSP', function()
return type(vim.lsp.commands['executed_type_annotate'])
end)
)
- client.stop()
+ client:stop()
end
end,
}
@@ -4564,7 +4564,7 @@ describe('LSP', function()
end)
eq({ command = 'Dummy', title = 'Lens1' }, cmd)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4653,7 +4653,7 @@ describe('LSP', function()
end)
eq({ command = 'Dummy', title = 'Lens2' }, response)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4762,7 +4762,7 @@ describe('LSP', function()
return notify_msg
end)
eq('[LSP] Format request failed, no matching language servers.', notify_msg)
- client.stop()
+ client:stop()
end,
}
end)
@@ -4795,7 +4795,7 @@ describe('LSP', function()
end)
eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4836,7 +4836,7 @@ describe('LSP', function()
end)
eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4883,7 +4883,7 @@ describe('LSP', function()
end)
eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4930,7 +4930,7 @@ describe('LSP', function()
end)
eq({ handler_called = true }, result)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -5477,7 +5477,7 @@ describe('LSP', function()
result[#result + 1] = {
method = method,
fname = fname,
- supported = client.supports_method(method, { bufnr = bufnr }),
+ supported = client:supports_method(method, { bufnr = bufnr }),
}
end
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 722442acbd..2b54ea93e0 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -544,7 +544,7 @@ describe('clipboard (with fake clipboard.vim)', function()
]])
feed('gg^<C-v>') -- Goto start of top line enter visual block mode
feed('3ljy^k') -- yank 4x2 block & goto initial location
- feed('P') -- Paste it infront
+ feed('P') -- Paste it before cursor
expect([[
aabbaabbcc
ddeeddeeff
diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua
index 60b2f872fc..43c38d18c0 100644
--- a/test/functional/testnvim.lua
+++ b/test/functional/testnvim.lua
@@ -800,81 +800,6 @@ function M.exec_capture(code)
return M.api.nvim_exec2(code, { output = true }).output
end
---- @param f function
---- @return table<string,any>
-local function get_upvalues(f)
- local i = 1
- local upvalues = {} --- @type table<string,any>
- while true do
- local n, v = debug.getupvalue(f, i)
- if not n then
- break
- end
- upvalues[n] = v
- i = i + 1
- end
- return upvalues
-end
-
---- @param f function
---- @param upvalues table<string,any>
-local function set_upvalues(f, upvalues)
- local i = 1
- while true do
- local n = debug.getupvalue(f, i)
- if not n then
- break
- end
- if upvalues[n] then
- debug.setupvalue(f, i, upvalues[n])
- end
- i = i + 1
- end
-end
-
---- @type fun(f: function): table<string,any>
-_G.__get_upvalues = nil
-
---- @type fun(f: function, upvalues: table<string,any>)
-_G.__set_upvalues = nil
-
---- @param self table<string,function>
---- @param bytecode string
---- @param upvalues table<string,any>
---- @param ... any[]
---- @return any[] result
---- @return table<string,any> upvalues
-local function exec_lua_handler(self, bytecode, upvalues, ...)
- local f = assert(loadstring(bytecode))
- self.set_upvalues(f, upvalues)
- local ret = { f(...) } --- @type any[]
- --- @type table<string,any>
- local new_upvalues = self.get_upvalues(f)
-
- do -- Check return value types for better error messages
- local invalid_types = {
- ['thread'] = true,
- ['function'] = true,
- ['userdata'] = true,
- }
-
- for k, v in pairs(ret) do
- if invalid_types[type(v)] then
- error(
- string.format(
- "Return index %d with value '%s' of type '%s' cannot be serialized over RPC",
- k,
- tostring(v),
- type(v)
- )
- )
- end
- end
- end
-
- return ret, new_upvalues
-end
-
--- Execute Lua code in the wrapped Nvim session.
---
--- When `code` is passed as a function, it is converted into Lua byte code.
@@ -921,52 +846,7 @@ function M.exec_lua(code, ...)
end
assert(session, 'no Nvim session')
-
- if not session.exec_lua_setup then
- assert(
- session:request(
- 'nvim_exec_lua',
- [[
- _G.__test_exec_lua = {
- get_upvalues = loadstring((select(1,...))),
- set_upvalues = loadstring((select(2,...))),
- handler = loadstring((select(3,...)))
- }
- setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua })
- ]],
- { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) }
- )
- )
- session.exec_lua_setup = true
- end
-
- local stat, rv = session:request(
- 'nvim_exec_lua',
- 'return { _G.__test_exec_lua:handler(...) }',
- { string.dump(code), get_upvalues(code), ... }
- )
-
- if not stat then
- error(rv[2])
- end
-
- --- @type any[], table<string,any>
- local ret, upvalues = unpack(rv)
-
- -- Update upvalues
- if next(upvalues) then
- local caller = debug.getinfo(2)
- local f = caller.func
- -- On PUC-Lua, if the function is a tail call, then func will be nil.
- -- In this case we need to use the current function.
- if not f then
- assert(caller.source == '=(tail call)')
- f = debug.getinfo(1).func
- end
- set_upvalues(f, upvalues)
- end
-
- return unpack(ret, 1, table.maxn(ret))
+ return require('test.functional.testnvim.exec_lua')(session, 2, code, ...)
end
function M.get_pathsep()
diff --git a/test/functional/testnvim/exec_lua.lua b/test/functional/testnvim/exec_lua.lua
new file mode 100644
index 0000000000..ddd9905ce7
--- /dev/null
+++ b/test/functional/testnvim/exec_lua.lua
@@ -0,0 +1,148 @@
+--- @param f function
+--- @return table<string,any>
+local function get_upvalues(f)
+ local i = 1
+ local upvalues = {} --- @type table<string,any>
+ while true do
+ local n, v = debug.getupvalue(f, i)
+ if not n then
+ break
+ end
+ upvalues[n] = v
+ i = i + 1
+ end
+ return upvalues
+end
+
+--- @param f function
+--- @param upvalues table<string,any>
+local function set_upvalues(f, upvalues)
+ local i = 1
+ while true do
+ local n = debug.getupvalue(f, i)
+ if not n then
+ break
+ end
+ if upvalues[n] then
+ debug.setupvalue(f, i, upvalues[n])
+ end
+ i = i + 1
+ end
+end
+
+--- @param messages string[]
+--- @param ... ...
+local function add_print(messages, ...)
+ local msg = {} --- @type string[]
+ for i = 1, select('#', ...) do
+ msg[#msg + 1] = tostring(select(i, ...))
+ end
+ table.insert(messages, table.concat(msg, '\t'))
+end
+
+local invalid_types = {
+ ['thread'] = true,
+ ['function'] = true,
+ ['userdata'] = true,
+}
+
+--- @param r any[]
+local function check_returns(r)
+ for k, v in pairs(r) do
+ if invalid_types[type(v)] then
+ error(
+ string.format(
+ "Return index %d with value '%s' of type '%s' cannot be serialized over RPC",
+ k,
+ tostring(v),
+ type(v)
+ ),
+ 2
+ )
+ end
+ end
+end
+
+local M = {}
+
+--- This is run in the context of the remote Nvim instance.
+--- @param bytecode string
+--- @param upvalues table<string,any>
+--- @param ... any[]
+--- @return any[] result
+--- @return table<string,any> upvalues
+--- @return string[] messages
+function M.handler(bytecode, upvalues, ...)
+ local messages = {} --- @type string[]
+ local orig_print = _G.print
+
+ function _G.print(...)
+ add_print(messages, ...)
+ return orig_print(...)
+ end
+
+ local f = assert(loadstring(bytecode))
+
+ set_upvalues(f, upvalues)
+
+ -- Run in pcall so we can return any print messages
+ local ret = { pcall(f, ...) } --- @type any[]
+
+ _G.print = orig_print
+
+ local new_upvalues = get_upvalues(f)
+
+ -- Check return value types for better error messages
+ check_returns(ret)
+
+ return ret, new_upvalues, messages
+end
+
+--- @param session test.Session
+--- @param lvl integer
+--- @param code function
+--- @param ... ...
+local function run(session, lvl, code, ...)
+ local stat, rv = session:request(
+ 'nvim_exec_lua',
+ [[return { require('test.functional.testnvim.exec_lua').handler(...) }]],
+ { string.dump(code), get_upvalues(code), ... }
+ )
+
+ if not stat then
+ error(rv[2], 2)
+ end
+
+ --- @type any[], table<string,any>, string[]
+ local ret, upvalues, messages = unpack(rv)
+
+ for _, m in ipairs(messages) do
+ print(m)
+ end
+
+ if not ret[1] then
+ error(ret[2], 2)
+ end
+
+ -- Update upvalues
+ if next(upvalues) then
+ local caller = debug.getinfo(lvl)
+ local i = 0
+
+ -- On PUC-Lua, if the function is a tail call, then func will be nil.
+ -- In this case we need to use the caller.
+ while not caller.func do
+ i = i + 1
+ caller = debug.getinfo(lvl + i)
+ end
+ set_upvalues(caller.func, upvalues)
+ end
+
+ return unpack(ret, 2, table.maxn(ret))
+end
+
+return setmetatable(M, {
+ __call = function(_, ...)
+ return run(...)
+ end,
+})
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 25f3465d46..9a6dfd8ed1 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -64,7 +64,7 @@ describe('ui/ext_messages', function()
}
end)
- it('msg_show kind=confirm,confirm_sub,emsg,wmsg,quickfix', function()
+ it('msg_show kinds', function()
feed('iline 1\nline 2<esc>')
-- kind=confirm
@@ -172,7 +172,7 @@ describe('ui/ext_messages', function()
},
{
content = { { 'E605: Exception not caught: foo', 9, 7 } },
- kind = '',
+ kind = 'emsg',
},
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
@@ -198,6 +198,48 @@ describe('ui/ext_messages', function()
},
},
}
+
+ -- search_cmd
+ feed('?line<cr>')
+ screen:expect({
+ grid = [[
+ ^line 1 |
+ line 2 |
+ {1:~ }|*3
+ ]],
+ messages = { {
+ content = { { '?line ' } },
+ kind = 'search_cmd',
+ } },
+ })
+
+ -- highlight
+ feed(':hi ErrorMsg<cr>')
+ screen:expect({
+ grid = [[
+ ^line 1 |
+ line 2 |
+ {1:~ }|*3
+ ]],
+ messages = {
+ {
+ content = {
+ { '\nErrorMsg ' },
+ { 'xxx', 9, 7 },
+ { ' ' },
+ { 'ctermfg=', 18, 6 },
+ { '15 ' },
+ { 'ctermbg=', 18, 6 },
+ { '1 ' },
+ { 'guifg=', 18, 6 },
+ { 'White ' },
+ { 'guibg=', 18, 6 },
+ { 'Red' },
+ },
+ kind = 'list_cmd',
+ },
+ },
+ })
end)
it(':echoerr', function()
@@ -408,34 +450,6 @@ describe('ui/ext_messages', function()
}
end)
- it(':hi Group output', function()
- feed(':hi ErrorMsg<cr>')
- screen:expect {
- grid = [[
- ^ |
- {1:~ }|*4
- ]],
- messages = {
- {
- content = {
- { '\nErrorMsg ' },
- { 'xxx', 9, 7 },
- { ' ' },
- { 'ctermfg=', 18, 6 },
- { '15 ' },
- { 'ctermbg=', 18, 6 },
- { '1 ' },
- { 'guifg=', 18, 6 },
- { 'White ' },
- { 'guibg=', 18, 6 },
- { 'Red' },
- },
- kind = '',
- },
- },
- }
- end)
-
it("doesn't crash with column adjustment #10069", function()
feed(':let [x,y] = [1,2]<cr>')
feed(':let x y<cr>')
@@ -445,8 +459,8 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
messages = {
- { content = { { 'x #1' } }, kind = '' },
- { content = { { 'y #2' } }, kind = '' },
+ { content = { { 'x #1' } }, kind = 'list_cmd' },
+ { content = { { 'y #2' } }, kind = 'list_cmd' },
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
kind = 'return_prompt',
@@ -947,7 +961,7 @@ stack traceback:
{ '*', 18, 1 },
{ ' k' },
},
- kind = '',
+ kind = 'list_cmd',
},
},
}
@@ -964,10 +978,12 @@ stack traceback:
^ |
{1:~ }|*6
]],
- messages = { {
- content = { { 'wildmenu wildmode' } },
- kind = '',
- } },
+ messages = {
+ {
+ content = { { 'wildmenu wildmode' } },
+ kind = 'wildlist',
+ },
+ },
cmdline = {
{
firstc = ':',
@@ -983,43 +999,46 @@ stack traceback:
feed('ihelllo<esc>')
feed('z=')
- screen:expect {
+ screen:expect({
grid = [[
- {100:helllo} |
- {1:~ }|*3
- {1:^~ }|
- ]],
+ {100:helllo} |
+ {1:~ }|*3
+ {1:^~ }|
+ ]],
messages = {
{
- content = {
- {
- 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\nType number and <Enter> or click with the mouse (q or empty cancels): ',
- },
- },
- kind = '',
+ content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\n' } },
+ kind = 'list_cmd',
+ },
+ {
+ content = { { 'Type number and <Enter> or click with the mouse (q or empty cancels): ' } },
+ kind = 'number_prompt',
},
},
- }
+ })
feed('1')
- screen:expect {
+ screen:expect({
grid = [[
- {100:helllo} |
- {1:~ }|*3
- {1:^~ }|
- ]],
+ {100:helllo} |
+ {1:~ }|*3
+ {1:^~ }|
+ ]],
messages = {
{
- content = {
- {
- 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\nType number and <Enter> or click with the mouse (q or empty cancels): ',
- },
- },
+ content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\n' } },
+ kind = 'list_cmd',
+ },
+ {
+ content = { { 'Type number and <Enter> or click with the mouse (q or empty cancels): ' } },
+ kind = 'number_prompt',
+ },
+ {
+ content = { { '1' } },
kind = '',
},
- { content = { { '1' } }, kind = '' },
},
- }
+ })
feed('<cr>')
screen:expect {
@@ -1056,7 +1075,7 @@ stack traceback:
{1:~ }|*4
]],
messages = {
- { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = '' },
+ { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = 'list_cmd' },
},
}
@@ -1113,6 +1132,33 @@ stack traceback:
})
eq(showmode, 1)
end)
+
+ it('emits single message for multiline print())', function()
+ exec_lua([[print("foo\nbar\nbaz")]])
+ screen:expect({
+ messages = {
+ {
+ content = { { 'foo\nbar\nbaz' } },
+ kind = 'lua_print',
+ },
+ },
+ })
+ exec_lua([[print(vim.inspect({ foo = "bar" }))]])
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*4
+ ]],
+ messages = {
+ {
+ content = { { '{\n foo = "bar"\n}' } },
+ kind = 'lua_print',
+ },
+ },
+ })
+ exec_lua([[vim.print({ foo = "bar" })]])
+ screen:expect_unchanged()
+ end)
end)
describe('ui/builtin messages', function()
@@ -1848,7 +1894,7 @@ describe('ui/ext_messages', function()
{3:[No Name] }|
]],
messages = {
- { content = { { ' cmdheight=0' } }, kind = '' },
+ { content = { { ' cmdheight=0' } }, kind = 'list_cmd' },
},
})
@@ -1864,7 +1910,7 @@ describe('ui/ext_messages', function()
{3:[No Name] }|
]],
messages = {
- { content = { { ' laststatus=3' } }, kind = '' },
+ { content = { { ' laststatus=3' } }, kind = 'list_cmd' },
},
})
@@ -1884,7 +1930,7 @@ describe('ui/ext_messages', function()
{3:[No Name] }|
]],
messages = {
- { content = { { ' cmdheight=0' } }, kind = '' },
+ { content = { { ' cmdheight=0' } }, kind = 'list_cmd' },
},
})
end)
@@ -2062,8 +2108,6 @@ aliquip ex ea commodo consequat.]]
end)
it('can be quit with Lua #11224 #16537', function()
- -- NOTE: adds "4" to message history, although not displayed initially
- -- (triggered the more prompt).
screen:try_resize(40, 5)
feed(':lua for i=0,10 do print(i) end<cr>')
screen:expect {
@@ -2093,13 +2137,13 @@ aliquip ex ea commodo consequat.]]
{4:-- More --}^ |
]],
}
- feed('j')
+ feed('G')
screen:expect {
grid = [[
- 1 |
- 2 |
- 3 |
- 4 |
+ 7 |
+ 8 |
+ 9 |
+ 10 |
{4:Press ENTER or type command to continue}^ |
]],
}
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index 57d76e54df..80e38d974a 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -198,7 +198,7 @@ describe('Screen', function()
end)
end) -- a region of text (implicit concealing)
- it('cursor position is correct when entering Insert mode with cocu=ni #13916', function()
+ it('cursor position when entering Insert mode with cocu=ni #13916', function()
insert([[foobarfoobarfoobar]])
-- move to end of line
feed('$')
@@ -217,6 +217,37 @@ describe('Screen', function()
{4:-- INSERT --} |
]])
end)
+
+ it('cursor position when scrolling in Normal mode with cocu=n #31271', function()
+ insert(('foo\n'):rep(9) .. 'foofoobarfoofoo' .. ('\nfoo'):rep(9))
+ command('set concealcursor=n')
+ command('syn match Foo /bar/ conceal cchar=&')
+ feed('gg5<C-E>10gg$')
+ screen:expect([[
+ foo |*4
+ foofoo{1:&}foofo^o |
+ foo |*4
+ |
+ ]])
+ feed('zz')
+ screen:expect_unchanged()
+ feed('zt')
+ screen:expect([[
+ foofoo{1:&}foofo^o |
+ foo |*8
+ |
+ ]])
+ feed('zt')
+ screen:expect_unchanged()
+ feed('zb')
+ screen:expect([[
+ foo |*8
+ foofoo{1:&}foofo^o |
+ |
+ ]])
+ feed('zb')
+ screen:expect_unchanged()
+ end)
end) -- match and conceal
describe('let the conceal level be', function()
diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua
index 4c6fd8fbda..6d212823eb 100644
--- a/test/functional/ui/tabline_spec.lua
+++ b/test/functional/ui/tabline_spec.lua
@@ -214,4 +214,43 @@ describe('tabline', function()
api.nvim_input_mouse('middle', 'press', '', 0, 0, 1)
eq({ 1, 1 }, api.nvim_eval('[tabpagenr(), tabpagenr("$")]'))
end)
+
+ it('does not show floats with focusable=false', function()
+ screen:set_default_attr_ids({
+ [1] = { background = Screen.colors.Plum1 },
+ [2] = { underline = true, background = Screen.colors.LightGrey },
+ [3] = { bold = true },
+ [4] = { reverse = true },
+ [5] = { bold = true, foreground = Screen.colors.Blue1 },
+ [6] = { foreground = Screen.colors.Fuchsia, bold = true },
+ [7] = { foreground = Screen.colors.SeaGreen, bold = true },
+ })
+ command('tabnew')
+ api.nvim_open_win(0, false, {
+ focusable = false,
+ relative = 'editor',
+ height = 1,
+ width = 1,
+ row = 0,
+ col = 0,
+ })
+ screen:expect {
+ grid = [[
+ {1: }{2:[No Name] }{3: [No Name] }{4: }{2:X}|
+ ^ |
+ {5:~ }|*2
+ |
+ ]],
+ }
+ command('tabs')
+ screen:expect {
+ grid = [[
+ {6:Tab page 1} |
+ # [No Name] |
+ {6:Tab page 2} |
+ > [No Name] |
+ {7:Press ENTER or type command to continue}^ |
+ ]],
+ }
+ end)
end)
diff --git a/test/old/testdir/test_curswant.vim b/test/old/testdir/test_curswant.vim
index e54cd4b280..c67cca5f7d 100644
--- a/test/old/testdir/test_curswant.vim
+++ b/test/old/testdir/test_curswant.vim
@@ -1,4 +1,7 @@
-" Tests for curswant not changing when setting an option
+" Tests for not changing curswant
+
+source check.vim
+source term_util.vim
func Test_curswant()
new
@@ -19,5 +22,50 @@ func Test_curswant()
let &ttimeoutlen=&ttimeoutlen
call assert_equal(7, winsaveview().curswant)
- enew!
+ bw!
+endfunc
+
+func Test_normal_gm()
+ CheckRunVimInTerminal
+ let lines =<< trim END
+ call setline(1, repeat([" abcd\tefgh\tij"], 10))
+ call cursor(1, 1)
+ END
+ call writefile(lines, 'XtestCurswant', 'D')
+ let buf = RunVimInTerminal('-S XtestCurswant', #{rows: 10})
+ if has("folding")
+ call term_sendkeys(buf, "jVjzf")
+ " gm
+ call term_sendkeys(buf, "gmk")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^18\s\+'})
+ " g0
+ call term_sendkeys(buf, "jg0k")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^1\s\+'})
+ " g^
+ call term_sendkeys(buf, "jg^k")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^3\s\+'})
+ endif
+ call term_sendkeys(buf, ":call cursor(10, 1)\<cr>")
+ " gm
+ call term_sendkeys(buf, "gmk")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call term_wait(buf)
+ call WaitFor({-> term_getline(buf, 10) =~ '^18\s\+'})
+ " g0
+ call term_sendkeys(buf, "g0k")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^1\s\+'})
+ " g^
+ call term_sendkeys(buf, "g^k")
+ call term_sendkeys(buf, ":echo virtcol('.')\<cr>")
+ call WaitFor({-> term_getline(buf, 10) =~ '^3\s\+'})
+ " clean up
+ call StopVimInTerminal(buf)
+ wincmd p
+ wincmd c
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index f70144b379..62e339c1ca 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -144,6 +144,7 @@ func s:GetFilenameChecks() abort
\ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE', 'WORKSPACE.bzlmod'],
\ 'bzr': ['bzr_log.any', 'bzr_log.file'],
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c', 'some-enlightenment/file.cfg', 'file.mdh', 'file.epro'],
+ \ 'c3': ['file.c3', 'file.c3i', 'file.c3t'],
\ 'cabal': ['file.cabal'],
\ 'cabalconfig': ['cabal.config', expand("$HOME/.config/cabal/config")] + s:WhenConfigHome('$XDG_CONFIG_HOME/cabal/config'),
\ 'cabalproject': ['cabal.project', 'cabal.project.local'],
@@ -353,7 +354,7 @@ func s:GetFilenameChecks() abort
\ 'htmlm4': ['file.html.m4'],
\ 'httest': ['file.htt', 'file.htb'],
\ 'hurl': ['file.hurl'],
- \ 'hyprlang': ['hyprlock.conf', 'hyprland.conf', 'hypridle.conf', 'hyprpaper.conf'],
+ \ 'hyprlang': ['hyprlock.conf', 'hyprland.conf', 'hypridle.conf', 'hyprpaper.conf', '/hypr/foo.conf'],
\ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
\ 'ibasic': ['file.iba', 'file.ibi'],
\ 'icemenu': ['/.icewm/menu', 'any/.icewm/menu'],
@@ -392,6 +393,7 @@ func s:GetFilenameChecks() abort
\ 'jsp': ['file.jsp'],
\ 'julia': ['file.jl'],
\ 'just': ['justfile', 'Justfile', '.justfile', 'config.just'],
+ \ 'karel': ['file.kl', 'file.KL'],
\ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file', 'Config.in', 'Config.in.host'],
\ 'kdl': ['file.kdl'],
\ 'kivy': ['file.kv'],
@@ -421,7 +423,7 @@ func s:GetFilenameChecks() abort
\ 'limits': ['/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf', '/etc/limits.conf', '/etc/limits.d/file.conf', '/etc/some-limits.conf', '/etc/some-limits.d/file.conf', 'any/etc/limits', 'any/etc/limits.conf', 'any/etc/limits.d/file.conf', 'any/etc/some-limits.conf', 'any/etc/some-limits.d/file.conf'],
\ 'liquidsoap': ['file.liq'],
\ 'liquid': ['file.liquid'],
- \ 'lisp': ['file.lsp', 'file.lisp', 'file.asd', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc', 'file.stsg', 'any/local/share/supertux2/config'],
+ \ 'lisp': ['file.lsp', 'file.lisp', 'file.asd', 'file.el', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc', 'file.stsg', 'any/local/share/supertux2/config'],
\ 'lite': ['file.lite', 'file.lt'],
\ 'litestep': ['/LiteStep/any/file.rc', 'any/LiteStep/any/file.rc'],
\ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
@@ -504,6 +506,7 @@ func s:GetFilenameChecks() abort
\ 'mplayerconf': ['mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'],
\ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'],
\ 'msidl': ['file.odl', 'file.mof'],
+ \ 'mss': ['file.mss'],
\ 'msql': ['file.msql'],
\ 'mojo': ['file.mojo', 'file.🔥'],
\ 'msmtp': ['.msmtprc'],
@@ -1190,6 +1193,22 @@ func Test_cfg_file()
filetype off
endfunc
+func Test_cl_file()
+ filetype on
+
+ call writefile(['/*', ' * Xfile.cl', ' */', 'int f() {}'], 'Xfile.cl')
+ split Xfile.cl
+ call assert_equal('opencl', &filetype)
+ bwipe!
+
+ call writefile(['()'], 'Xfile.cl')
+ split Xfile.cl
+ call assert_equal('lisp', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
func Test_d_file()
filetype on