aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/autoload/netrw.vim2
-rw-r--r--runtime/autoload/provider/pythonx.vim9
-rw-r--r--runtime/doc/api.txt4
-rw-r--r--runtime/doc/builtin.txt3
-rw-r--r--runtime/doc/change.txt1
-rw-r--r--runtime/doc/deprecated.txt1
-rw-r--r--runtime/doc/develop.txt6
-rw-r--r--runtime/doc/editing.txt20
-rw-r--r--runtime/doc/ft_rust.txt4
-rw-r--r--runtime/doc/insert.txt4
-rw-r--r--runtime/doc/intro.txt2
-rw-r--r--runtime/doc/lsp.txt29
-rw-r--r--runtime/doc/lua.txt80
-rw-r--r--runtime/doc/luaref.txt24
-rw-r--r--runtime/doc/motion.txt132
-rw-r--r--runtime/doc/news.txt12
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt2
-rw-r--r--runtime/doc/options.txt32
-rw-r--r--runtime/doc/starting.txt33
-rw-r--r--runtime/doc/syntax.txt2
-rw-r--r--runtime/doc/treesitter.txt33
-rw-r--r--runtime/doc/usr_02.txt2
-rw-r--r--runtime/doc/vim_diff.txt7
-rw-r--r--runtime/doc/visual.txt1
-rw-r--r--runtime/ftplugin/d.lua1
-rw-r--r--runtime/ftplugin/kotlin.vim33
-rw-r--r--runtime/ftplugin/sh.vim3
-rw-r--r--runtime/indent/kotlin.vim60
-rw-r--r--runtime/lua/nvim/health.lua16
-rw-r--r--runtime/lua/vim/_editor.lua22
-rw-r--r--runtime/lua/vim/_meta.lua1
-rw-r--r--runtime/lua/vim/_meta/api.lua14
-rw-r--r--runtime/lua/vim/_meta/api_keysets.lua1
-rw-r--r--runtime/lua/vim/_meta/builtin.lua6
-rw-r--r--runtime/lua/vim/_meta/json.lua3
-rw-r--r--runtime/lua/vim/_meta/lpeg.lua323
-rw-r--r--runtime/lua/vim/_meta/options.lua32
-rw-r--r--runtime/lua/vim/_meta/vimfn.lua3
-rw-r--r--runtime/lua/vim/_options.lua2
-rw-r--r--runtime/lua/vim/filetype.lua2
-rw-r--r--runtime/lua/vim/func.lua41
-rw-r--r--runtime/lua/vim/func/_memoize.lua59
-rw-r--r--runtime/lua/vim/keymap.lua18
-rw-r--r--runtime/lua/vim/lsp/codelens.lua39
-rw-r--r--runtime/lua/vim/lsp/handlers.lua15
-rw-r--r--runtime/lua/vim/lsp/health.lua9
-rw-r--r--runtime/lua/vim/lsp/util.lua238
-rw-r--r--runtime/lua/vim/secure.lua21
-rw-r--r--runtime/lua/vim/shared.lua153
-rw-r--r--runtime/lua/vim/treesitter.lua5
-rw-r--r--runtime/lua/vim/treesitter/_meta.lua3
-rw-r--r--runtime/lua/vim/treesitter/_query_linter.lua54
-rw-r--r--runtime/lua/vim/treesitter/dev.lua7
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua69
-rw-r--r--runtime/lua/vim/treesitter/query.lua42
-rw-r--r--runtime/lua/vim/uri.lua9
-rw-r--r--runtime/queries/markdown/highlights.scm8
-rw-r--r--runtime/queries/markdown_inline/highlights.scm8
-rw-r--r--runtime/syntax/kotlin.vim157
59 files changed, 1387 insertions, 535 deletions
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index be170d8aec..2dd5cf45bf 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -2951,7 +2951,7 @@ fun! s:NetrwGetFile(readcmd, tfile, method)
" to process this detection correctly.
" call Decho("detect filetype of local version of remote file<".rfile.">",'~'.expand("<slnum>"))
" call Decho("..did_filetype()=".did_filetype())
- setl ft=
+" setl ft=
" call Decho("..initial filetype<".&ft."> for buf#".bufnr()."<".bufname().">")
let iskkeep= &isk
setl isk-=/
diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim
index 6211b457d6..48b96c699a 100644
--- a/runtime/autoload/provider/pythonx.vim
+++ b/runtime/autoload/provider/pythonx.vim
@@ -26,7 +26,7 @@ endfunction
function! s:get_python_candidates(major_version) abort
return {
- \ 3: ['python3', 'python3.10', 'python3.9', 'python3.8', 'python3.7', 'python']
+ \ 3: ['python3', 'python3.12', 'python3.11', 'python3.10', 'python3.9', 'python3.8', 'python3.7', 'python']
\ }[a:major_version]
endfunction
@@ -61,12 +61,11 @@ endfunction
" Returns array: [prog_exitcode, prog_version]
function! s:import_module(prog, module) abort
- let prog_version = system([a:prog, '-c' , printf(
- \ 'import sys; ' .
+ let prog_version = system([a:prog, '-W', 'ignore', '-c', printf(
+ \ 'import sys, importlib.util; ' .
\ 'sys.path = [p for p in sys.path if p != ""]; ' .
\ 'sys.stdout.write(str(sys.version_info[0]) + "." + str(sys.version_info[1])); ' .
- \ 'import pkgutil; ' .
- \ 'exit(2*int(pkgutil.get_loader("%s") is None))',
+ \ 'sys.exit(2 * int(importlib.util.find_spec("%s") is None))',
\ a:module)])
return [v:shell_error, prog_version]
endfunction
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index d30bb4851c..1eebd0bb18 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1507,7 +1507,7 @@ nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()*
• {rhs} Right-hand-side |{rhs}| of the mapping.
• {opts} Optional parameters map: Accepts all |:map-arguments| as keys
except |<buffer>|, values are booleans (default false). Also:
- • "noremap" non-recursive mapping |:noremap|
+ • "noremap" disables |recursive_mapping|, like |:noremap|
• "desc" human-readable description.
• "callback" Lua function called in place of {rhs}.
• "replace_keycodes" (boolean) When "expr" is true, replace
@@ -3179,6 +3179,8 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
• noautocmd: If true then no buffer-related autocommand
events such as |BufEnter|, |BufLeave| or |BufWinEnter| may
fire from calling this function.
+ • fixed: If true when anchor is NW or SW, the float window
+ would be kept fixed even if the window would be truncated.
Return: ~
Window handle, or 0 on error
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 05db977809..207bf817b0 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -3738,7 +3738,7 @@ jobresize({job}, {width}, {height}) *jobresize()*
Fails if the job was not started with `"pty":v:true`.
jobstart({cmd} [, {opts}]) *jobstart()*
- Note: Prefer |vim.system()| in Lua.
+ Note: Prefer |vim.system()| in Lua (unless using the `pty` option).
Spawns {cmd} as a job.
If {cmd} is a List it runs directly (no 'shell').
@@ -7742,6 +7742,7 @@ strutf16len({string} [, {countcc}]) *strutf16len()*
echo strutf16len('😊') " returns 2
echo strutf16len('ą́') " returns 1
echo strutf16len('ą́', v:true) " returns 3
+<
strwidth({string}) *strwidth()*
The result is a Number, which is the number of display cells
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 894557818b..2c47421b02 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -196,6 +196,7 @@ gR Enter Virtual Replace mode: Each character you type
*v_r*
{Visual}r{char} Replace all selected characters by {char}.
+ CTRL-C will be inserted literally.
*v_C*
{Visual}["x]C Delete the highlighted lines [into register x] and
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index 2e9312cf74..407d7ae9fb 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -141,6 +141,7 @@ LSP FUNCTIONS
`progress` of |vim.lsp.client|
- *vim.lsp.get_active_clients()* Use |vim.lsp.get_clients()|
- *vim.lsp.for_each_buffer_client()* Use |vim.lsp.get_clients()|
+- *vim.lsp.util.trim_empty_lines()* Use |vim.split()| with `trimempty` instead.
TREESITTER FUNCTIONS
- *vim.treesitter.language.require_language()* Use |vim.treesitter.language.add()|
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index 71c16659eb..f4c581fabe 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -312,6 +312,12 @@ See also |dev-naming|.
- Avoid functions that depend on cursor position, current buffer, etc. Instead
the function should take a position parameter, buffer parameter, etc.
+Where things go ~
+
+- API (libnvim/RPC): exposes low-level internals, or fundamental things (such
+ as `nvim_exec_lua()`) needed by clients or C consumers.
+- Lua stdlib = high-level functionality that builds on top of the API.
+
NAMING GUIDELINES *dev-naming*
Naming is exceedingly important: the name of a thing is the primary interface
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 2225e6e753..2f44256138 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -539,10 +539,10 @@ set to "dos", otherwise it is set to "unix". When 'fileformats' includes
"mac".
If the 'fileformat' option is set to "dos" on non-MS-Windows systems the
-message "[dos format]" is shown to remind you that something unusual is
-happening. On MS-Windows systems you get the message "[unix format]" if
-'fileformat' is set to "unix". On all systems but the Macintosh you get the
-message "[mac format]" if 'fileformat' is set to "mac".
+message "[dos]" is shown to remind you that something unusual is happening. On
+MS-Windows systems you get the message "[unix]" if 'fileformat' is set to
+"unix". On all systems you get the message "[mac]" if 'fileformat' is set to
+"mac".
If the 'fileformats' option is empty and DOS format is used, but while reading
a file some lines did not end in <CR><NL>, "[CR missing]" will be included in
@@ -820,12 +820,10 @@ by the shell before executing the find program.
When there is an argument list you can see which file you are editing in the
title of the window (if there is one and 'title' is on) and with the file
message you get with the "CTRL-G" command. You will see something like
- (file 4 of 11)
-If 'shortmess' contains 'f' it will be
(4 of 11)
If you are not really editing the file at the current position in the argument
list it will be
- (file (4) of 11)
+ ((4) of 11)
This means that you are position 4 in the argument list, but not editing the
fourth file in the argument list. This happens when you do ":e file".
@@ -1058,14 +1056,14 @@ lost the original file.
*DOS-format-write*
If the 'fileformat' is "dos", <CR><NL> is used for <EOL>. This is default
-for Windows. On other systems the message "[dos format]" is shown to
+for Windows. On other systems the message "[dos]" is shown to
remind you that an unusual <EOL> was used.
*Unix-format-write*
If the 'fileformat' is "unix", <NL> is used for <EOL>. On Windows
-the message "[unix format]" is shown.
+the message "[unix]" is shown.
*Mac-format-write*
-If the 'fileformat' is "mac", <CR> is used for <EOL>. On non-Mac systems the
-message "[mac format]" is shown.
+If the 'fileformat' is "mac", <CR> is used for <EOL>. The
+message "[mac]" is shown.
See also |file-formats| and the 'fileformat' and 'fileformats' options.
diff --git a/runtime/doc/ft_rust.txt b/runtime/doc/ft_rust.txt
index b912f732b6..083b6f579f 100644
--- a/runtime/doc/ft_rust.txt
+++ b/runtime/doc/ft_rust.txt
@@ -467,8 +467,8 @@ rust.vim Debugging ~
register.
:RustInfoToFile [filename] *:RustInfoToFile*
- Saves debugging info of the Vim Rust plugin to the the given
- file, overwritting it.
+ Saves debugging info of the Vim Rust plugin to the given file,
+ overwriting it.
==============================================================================
MAPPINGS *rust-mappings*
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index 0fa5ffd598..ce2ec36ca3 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -1093,11 +1093,11 @@ To get basic "autocompletion" without installing a plugin, try this script: >lua
vim.api.nvim_create_autocmd("InsertCharPre", {
buffer = vim.api.nvim_get_current_buf(),
callback = function()
- if vim.fn.pumvisible() == 1 then
+ if vim.fn.pumvisible() == 1 or vim.fn.state("m") == "m" then
return
end
local char = vim.v.char
- if vim.tbl_contains(triggers, char) then
+ if vim.list_contains(triggers, char) then
local key = vim.keycode("<C-x><C-n>")
vim.api.nvim_feedkeys(key, "m", false)
end
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index 975aff6bf6..299c18ac2e 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -536,7 +536,7 @@ CTRL-O in Insert mode you get a beep but you are still in Insert mode, type
Visual *2 ^G c C -- : --
Select *5 ^O ^G *6 -- -- --
Insert <Esc> -- -- <Insert> -- --
- Replace <Esc> -- -- <Insert> -- --
+ Replace <Esc> -- -- <Insert> -- --
Command-line `*3` -- -- :start -- --
Ex :vi -- -- -- -- --
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 5103cc223f..23902f8bc3 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -1430,7 +1430,7 @@ display({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.display()*
Display the lenses using virtual text
Parameters: ~
- • {lenses} (table) of lenses to display (`CodeLens[] | null`)
+ • {lenses} lsp.CodeLens[]|nil lenses to display
• {bufnr} (integer)
• {client_id} (integer)
@@ -1442,7 +1442,7 @@ get({bufnr}) *vim.lsp.codelens.get()*
buffer.
Return: ~
- (table) (`CodeLens[]`)
+ lsp.CodeLens[]
*vim.lsp.codelens.on_codelens()*
on_codelens({err}, {result}, {ctx}, {_})
@@ -1464,7 +1464,7 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()*
Store lenses for a specific buffer and client
Parameters: ~
- • {lenses} (table) of lenses to store (`CodeLens[] | null`)
+ • {lenses} lsp.CodeLens[]|nil lenses to store
• {bufnr} (integer)
• {client_id} (integer)
@@ -1678,20 +1678,24 @@ convert_input_to_markdown_lines({input}, {contents})
window for `textDocument/hover`, for parsing the result of
`textDocument/signatureHelp`, and potentially others.
+ Note that if the input is of type `MarkupContent` and its kind is
+ `plaintext`, then the corresponding value is returned without further
+ modifications.
+
Parameters: ~
• {input} (`MarkedString` | `MarkedString[]` | `MarkupContent`)
• {contents} (table|nil) List of strings to extend with converted
lines. Defaults to {}.
Return: ~
- (table) {contents} extended with lines of converted markdown.
+ string[] extended with lines of converted markdown.
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
*vim.lsp.util.convert_signature_help_to_markdown_lines()*
convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers})
- Converts `textDocument/SignatureHelp` response to markdown lines.
+ Converts `textDocument/signatureHelp` response to markdown lines.
Parameters: ~
• {signature_help} (table) Response of `textDocument/SignatureHelp`
@@ -1908,10 +1912,6 @@ open_floating_preview({contents}, {syntax}, {opts})
height when wrap is enabled
• max_width: (integer) maximal width of floating window
• max_height: (integer) maximal height of floating window
- • pad_top: (integer) number of lines to pad contents at
- top
- • pad_bottom: (integer) number of lines to pad contents at
- bottom
• focus_id: (string) if a popup with this id is opened,
then focus it
• close_events: (table) list of events that closes the
@@ -2005,8 +2005,6 @@ stylize_markdown({bufnr}, {contents}, {opts})
• wrap_at character to wrap at for computing height
• max_width maximal width of floating window
• max_height maximal height of floating window
- • pad_top number of lines to pad contents at top
- • pad_bottom number of lines to pad contents at bottom
• separator insert separator after code block
Return: ~
@@ -2035,15 +2033,6 @@ text_document_completion_list_to_complete_items({result}, {prefix})
See also: ~
• complete-items
-trim_empty_lines({lines}) *vim.lsp.util.trim_empty_lines()*
- Removes empty lines from the beginning and end.
-
- Parameters: ~
- • {lines} (table) list of lines to trim
-
- Return: ~
- (table) trimmed list of lines
-
*vim.lsp.util.try_trim_markdown_code_blocks()*
try_trim_markdown_code_blocks({lines})
Accepts markdown lines and tries to reduce them to a filetype if they
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 6cfec45523..7e888a2375 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -956,12 +956,12 @@ vim.rpcrequest({channel}, {method}, {args}, {...}) *vim.rpcrequest()*
• {args} any[]|nil
• {...} any|nil
-vim.schedule({callback}) *vim.schedule()*
- Schedules {callback} to be invoked soon by the main event-loop. Useful to
- avoid |textlock| or other temporary restrictions.
+vim.schedule({fn}) *vim.schedule()*
+ Schedules {fn} to be invoked soon by the main event-loop. Useful to avoid
+ |textlock| or other temporary restrictions.
Parameters: ~
- • {callback} fun()
+ • {fn} (function)
vim.str_byteindex({str}, {index}, {use_utf16}) *vim.str_byteindex()*
Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not
@@ -1680,7 +1680,7 @@ vim.print({...}) *vim.print()*
"Pretty prints" the given arguments and returns them unmodified.
Example: >lua
- local hl_normal = vim.print(vim.api.nvim_get_hl_by_name('Normal', true))
+ local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' }))
<
Return: ~
@@ -1714,11 +1714,20 @@ vim.region({bufnr}, {pos1}, {pos2}, {regtype}, {inclusive})
`endcol` is exclusive, and whole lines are returned as
`{startcol,endcol} = {0,-1}`.
-vim.schedule_wrap({cb}) *vim.schedule_wrap()*
- Defers callback `cb` until the Nvim API is safe to call.
+vim.schedule_wrap({fn}) *vim.schedule_wrap()*
+ Returns a function which calls {fn} via |vim.schedule()|.
+
+ The returned function passes all arguments to {fn}.
+
+ Example: >lua
+ function notify_readable(_err, readable)
+ vim.notify("readable? " .. tostring(readable))
+ end
+ vim.uv.fs_access(vim.fn.stdpath("config"), "R", vim.schedule_wrap(notify_readable))
+<
Parameters: ~
- • {cb} (function)
+ • {fn} (function)
Return: ~
(function)
@@ -1880,25 +1889,22 @@ vim.deepcopy({orig}) *vim.deepcopy()*
Return: ~
(table) Table of copied keys and (nested) values.
-vim.defaulttable({create}) *vim.defaulttable()*
- Creates a table whose members are automatically created when accessed, if
- they don't already exist.
+vim.defaulttable({createfn}) *vim.defaulttable()*
+ Creates a table whose missing keys are provided by {createfn} (like
+ Python's "defaultdict").
- They mimic defaultdict in python.
-
- If {create} is `nil`, this will create a defaulttable whose constructor
- function is this function, effectively allowing to create nested tables on
- the fly: >lua
+ If {createfn} is `nil` it defaults to defaulttable() itself, so accessing
+ nested keys creates nested tables: >lua
local a = vim.defaulttable()
a.b.c = 1
<
Parameters: ~
- • {create} function?(key:any):any The function called to create a
- missing value.
+ • {createfn} function?(key:any):any Provides the value for a missing
+ `key`.
Return: ~
- (table) Empty table with metamethod
+ (table) Empty table with `__index` metamethod.
vim.endswith({s}, {suffix}) *vim.endswith()*
Tests if `s` ends with `suffix`.
@@ -2061,13 +2067,13 @@ vim.Ringbuf:push({item}) *Ringbuf:push()*
• {item} any
vim.spairs({t}) *vim.spairs()*
- Enumerate a table sorted by its keys.
+ Enumerates key-value pairs of a table, ordered by key.
Parameters: ~
• {t} (table) Dict-like table
Return: ~
- (function) iterator over sorted keys and their values
+ (function) |for-in| iterator over sorted keys and their values
See also: ~
• Based on https://github.com/premake/premake-core/blob/master/src/base/table.lua
@@ -2232,12 +2238,14 @@ vim.tbl_get({o}, {...}) *vim.tbl_get()*
any Nested value indexed by key (if it exists), else nil
vim.tbl_isarray({t}) *vim.tbl_isarray()*
- Tests if a Lua table can be treated as an array (a table indexed by
- integers).
+ Tests if `t` is an "array": a table indexed only by integers (potentially non-contiguous).
+
+ If the indexes start from 1 and are contiguous then the array is also a
+ list. |vim.tbl_islist()|
- Empty table `{}` is assumed to be an array, unless it was created by
- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result,
- for example from |rpcrequest()| or |vim.fn|.
+ Empty table `{}` is an array, unless it was created by |vim.empty_dict()|
+ or returned as a dict-like |API| or Vimscript result, for example from
+ |rpcrequest()| or |vim.fn|.
Parameters: ~
• {t} (table)
@@ -2245,6 +2253,9 @@ vim.tbl_isarray({t}) *vim.tbl_isarray()*
Return: ~
(boolean) `true` if array-like table, else `false`.
+ See also: ~
+ • https://github.com/openresty/luajit2#tableisarray
+
vim.tbl_isempty({t}) *vim.tbl_isempty()*
Checks if a table is empty.
@@ -2258,12 +2269,12 @@ vim.tbl_isempty({t}) *vim.tbl_isempty()*
• https://github.com/premake/premake-core/blob/master/src/base/table.lua
vim.tbl_islist({t}) *vim.tbl_islist()*
- Tests if a Lua table can be treated as a list (a table indexed by
- consecutive integers starting from 1).
+ Tests if `t` is a "list": a table indexed only by contiguous integers starting from 1 (what |lua-length| calls a "regular
+ array").
- Empty table `{}` is assumed to be an list, unless it was created by
- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result,
- for example from |rpcrequest()| or |vim.fn|.
+ Empty table `{}` is a list, unless it was created by |vim.empty_dict()| or
+ returned as a dict-like |API| or Vimscript result, for example from
+ |rpcrequest()| or |vim.fn|.
Parameters: ~
• {t} (table)
@@ -2271,6 +2282,9 @@ vim.tbl_islist({t}) *vim.tbl_islist()*
Return: ~
(boolean) `true` if list-like table, else `false`.
+ See also: ~
+ • |vim.tbl_isarray()|
+
vim.tbl_keys({t}) *vim.tbl_keys()*
Return a list of all keys used in a table. However, the order of the
return table of keys is not guaranteed.
@@ -2738,7 +2752,7 @@ vim.keymap.del({modes}, {lhs}, {opts}) *vim.keymap.del()*
Parameters: ~
• {opts} (table|nil) A table of optional arguments:
- • "buffer": (number|boolean) Remove a mapping from the given
+ • "buffer": (integer|boolean) Remove a mapping from the given
buffer. When `0` or `true`, use the current buffer.
See also: ~
@@ -2772,7 +2786,7 @@ vim.keymap.set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()*
• "noremap": inverse of "remap" (see below).
• Also accepts:
- • "buffer": (number|boolean) Creates buffer-local mapping,
+ • "buffer": (integer|boolean) Creates buffer-local mapping,
`0` or `true` for current buffer.
• "remap": (boolean) Make the mapping recursive. Inverse of
"noremap". Defaults to `false`.
diff --git a/runtime/doc/luaref.txt b/runtime/doc/luaref.txt
index 341f620a8d..467b5760cf 100644
--- a/runtime/doc/luaref.txt
+++ b/runtime/doc/luaref.txt
@@ -568,8 +568,7 @@ Binary operators comprise arithmetic operators (see |lua-arithmetic|),
relational operators (see |lua-relational|), logical operators (see
|lua-logicalop|), and the concatenation operator (see |lua-concat|).
Unary operators comprise the unary minus (see |lua-arithmetic|), the unary
-`not` (see |lua-logicalop|), and the unary length operator (see
-|lua-length|).
+`not` (see |lua-logicalop|), and the unary length operator (see |lua-length|).
Both function calls and vararg expressions may result in multiple values. If
the expression is used as a statement (see |lua-funcstatement|)
@@ -690,7 +689,7 @@ according to the rules mentioned in |lua-coercion|. Otherwise, the
"concat" metamethod is called (see |lua-metatable|).
------------------------------------------------------------------------------
-2.5.5 The Length Operator *lua-length*
+2.5.5 The Length Operator *lua-#* *lua-length*
The length operator is denoted by the unary operator `#`. The length of a
string is its number of bytes (that is, the usual meaning of string length
@@ -3505,7 +3504,7 @@ luaL_where *luaL_where()*
This function is used to build a prefix for error messages.
==============================================================================
-5 STANDARD LIBRARIES *lua-Lib*
+5 STANDARD LIBRARIES *lua-lib*
The standard libraries provide useful functions that are implemented directly
through the C API. Some of these functions provide essential services to the
@@ -3653,8 +3652,8 @@ next({table} [, {index}]) *next()*
argument is absent, then it is interpreted as `nil`. In particular,
you can use `next(t)` to check whether a table is empty.
- The order in which the indices are enumerated is not specified, `even
- for` `numeric indices`. (To traverse a table in numeric order, use a
+ The order in which the indices are enumerated is not specified, even
+ for numeric indices. (To traverse a table in numeric order, use a
numerical `for` or the |ipairs()| function.)
The behavior of `next` is `undefined` if, during the traversal, you
@@ -3759,7 +3758,7 @@ unpack({list} [, {i} [, {j}]]) *unpack()*
<
except that the above code can be written only for a fixed number of
elements. By default, {i} is 1 and {j} is the length of the list, as
- defined by the length operator(see |lua-length|).
+ defined by the length operator (see |lua-length|).
_VERSION *_VERSION*
A global variable (not a function) that holds a string containing the
@@ -4299,12 +4298,11 @@ table.remove({table} [, {pos}]) *table.remove()*
table.sort({table} [, {comp}]) *table.sort()*
Sorts table elements in a given order, `in-place`, from `table[1]` to
- `table[n]`, where `n` is the length of the table (see
- |lua-length|). If {comp} is given, then it must be a function
- that receives two table elements, and returns true when the first is
- less than the second (so that `not comp(a[i+1],a[i])` will be true
- after the sort). If {comp} is not given, then the standard Lua
- operator `<` is used instead.
+ `table[n]`, where `n` is the length of the table (see |lua-length|).
+ If {comp} is given, then it must be a function that receives two table
+ elements, and returns true when the first is less than the second (so
+ that `not comp(a[i+1],a[i])` will be true after the sort). If {comp}
+ is not given, then the standard Lua operator `<` is used instead.
The sort algorithm is `not` stable, that is, elements considered equal by the
given order may have their relative positions changed by the sort.
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index 05244cde91..5e18595d22 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -660,6 +660,7 @@ i` *v_i`* *i`*
Special case: With a count of 2 the quotes are
included, but no extra white space as with a"/a'/a`.
+ *o_object-select*
When used after an operator:
For non-block objects:
For the "a" commands: The operator applies to the object and the white
@@ -675,6 +676,7 @@ For a block object:
the surrounding braces are excluded. For the "a" commands, the braces
are included.
+ *v_object-select*
When used in Visual mode:
When start and end of the Visual area are the same (just after typing "v"):
One object is selected, the same as for using an operator.
@@ -1048,14 +1050,14 @@ can go to cursor positions before older jumps, and back again. Thus you can
move up and down the list. There is a separate jump list for each window.
The maximum number of entries is fixed at 100.
-For example, after three jump commands you have this jump list:
-
- jump line col file/text ~
- 3 1 0 some text ~
- 2 70 0 another line ~
- 1 1154 23 end. ~
- > ~
+For example, after three jump commands you have this jump list: >
+ jump line col file/text
+ 3 1 0 some text
+ 2 70 0 another line
+ 1 1154 23 end.
+ >
+<
The "file/text" column shows the file name, or the text at the jump if it is
in the current file (an indent is removed and a long line is truncated to fit
in the window).
@@ -1064,14 +1066,14 @@ The marker ">" indicates the current position in the jumplist. It may not be
shown when filtering the |:jumps| command using |:filter|
You are currently in line 1167. If you then use the CTRL-O command, the
-cursor is put in line 1154. This results in:
-
- jump line col file/text ~
- 2 1 0 some text ~
- 1 70 0 another line ~
- > 0 1154 23 end. ~
- 1 1167 0 foo bar ~
+cursor is put in line 1154. This results in: >
+ jump line col file/text
+ 2 1 0 some text
+ 1 70 0 another line
+ > 0 1154 23 end.
+ 1 1167 0 foo bar
+<
The pointer will be set at the last used jump position. The next CTRL-O
command will use the entry above it, the next CTRL-I command will use the
entry below it. If the pointer is below the last entry, this indicates that
@@ -1095,15 +1097,15 @@ command. You can explicitly add a jump by setting the ' mark with "m'". Note
that calling setpos() does not do this.
After the CTRL-O command that got you into line 1154 you could give another
-jump command (e.g., "G"). The jump list would then become:
-
- jump line col file/text ~
- 4 1 0 some text ~
- 3 70 0 another line ~
- 2 1167 0 foo bar ~
- 1 1154 23 end. ~
- > ~
-
+jump command (e.g., "G"). The jump list would then become: >
+
+ jump line col file/text
+ 4 1 0 some text
+ 3 70 0 another line
+ 2 1167 0 foo bar
+ 1 1154 23 end.
+ >
+<
The line numbers will be adjusted for deleted and inserted lines. This fails
if you stop editing a file without writing, like with ":n!".
@@ -1113,60 +1115,44 @@ If you have included the ' item in the 'shada' option the jumplist will be
stored in the ShaDa file and restored when starting Vim.
*jumplist-stack*
-When jumpoptions includes "stack", the jumplist behaves like the history in a
-web browser and like the tag stack. When jumping to a new location from the
-middle of the jumplist, the locations after the current position will be
-discarded.
-
-This behavior corresponds to the following situation in a web browser.
-Navigate to first.com, second.com, third.com, fourth.com and then fifth.com.
-Then navigate backwards twice so that third.com is displayed. At that point,
-the history is:
-- first.com
-- second.com
-- third.com <--
-- fourth.com
-- fifth.com
-
-Finally, navigate to a different webpage, new.com. The history is
-- first.com
-- second.com
-- third.com
-- new.com <--
-
-When the jumpoptions includes "stack", this is the behavior of Nvim as well.
-That is, given a jumplist like the following in which CTRL-O has been used to
-move back three times to location X
-
- jump line col file/text
- 2 1260 8 src/nvim/mark.c <-- location X-2
- 1 685 0 src/nvim/option_defs.h <-- location X-1
-> 0 462 36 src/nvim/option_defs.h <-- location X
- 1 479 39 src/nvim/option_defs.h
- 2 213 2 src/nvim/mark.c
- 3 181 0 src/nvim/mark.c
-
+When 'jumpoptions' option includes "stack", the jumplist behaves like the tag
+stack. When jumping to a new location from the middle of the jumplist, the
+locations after the current position will be discarded. With this option set
+you can move through a tree of jump locations. When going back up a branch and
+then down another branch, CTRL-O still takes you further up the tree.
+
+Given a jumplist like the following in which CTRL-O has been used to move back
+three times to location X: >
+
+ jump line col file/text
+ 2 1260 8 mark.c <-- location X-2
+ 1 685 0 eval.c <-- location X-1
+ > 0 462 36 eval.c <-- location X
+ 1 479 39 eval.c
+ 2 213 2 mark.c
+ 3 181 0 mark.c
+<
jumping to (new) location Y results in the locations after the current
-locations being removed:
-
- jump line col file/text
- 3 1260 8 src/nvim/mark.c
- 2 685 0 src/nvim/option_defs.h
- 1 462 36 src/nvim/option_defs.h <-- location X
->
+locations being removed: >
+ jump line col file/text
+ 3 1260 8 mark.c <-- location X-2
+ 2 685 0 eval.c <-- location X-1
+ 1 462 36 eval.c <-- location X
+ >
+<
Then, when yet another location Z is jumped to, the new location Y appears
directly after location X in the jumplist and location X remains in the same
-position relative to the locations (X-1, X-2, etc., ...) that had been before it
-prior to the original jump from X to Y:
-
- jump line col file/text
- 4 1260 8 src/nvim/mark.c <-- location X-2
- 3 685 0 src/nvim/option_defs.h <-- location X-1
- 2 462 36 src/nvim/option_defs.h <-- location X
- 1 100 0 src/nvim/option_defs.h <-- location Y
->
-
+position relative to the locations (X-1, X-2, etc., ...) that had been before
+it prior to the original jump from X to Y: >
+
+ jump line col file/text
+ 4 1260 8 mark.c <-- location X-2
+ 3 685 0 eval.c <-- location X-1
+ 2 462 36 eval.c <-- location X
+ 1 100 0 buffer.c <-- location Y
+ >
+<
CHANGE LIST JUMPS *changelist* *change-list-jumps* *E664*
When making a change the cursor position is remembered. One position is
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 7c971097fb..05a2d35f9a 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -232,6 +232,11 @@ The following changes to existing APIs or features add new behavior.
In addition, |nvim_buf_get_extmarks()| has gained an "overlap" option to
return such ranges even if they started before the specified position.
+• LSP hover and signature help now use Treesitter for highlighting of Markdown
+ content.
+ Note that syntax highlighting of code examples requires a matching parser
+ and may be affected by custom queries.
+
==============================================================================
REMOVED FEATURES *news-removed*
@@ -242,6 +247,12 @@ The following deprecated functions or APIs were removed.
• Support for legacy treesitter injection queries is removed.
+• Removed 'shortmess' flags:
+ - |shm-f|. Always uses "(3 of 5)", never "(file 3 of 5)"
+ - |shm-i|. Always use "[noeol]".
+ - |shm-x|. Always use "[dos]", "[unix]" and "[mac]"
+ - |shm-n|. Always use "[New]".
+
==============================================================================
DEPRECATIONS *news-deprecations*
@@ -267,6 +278,7 @@ release.
- |vim.lsp.util.get_progress_messages()| Use |vim.lsp.status()| instead.
- |vim.lsp.get_active_clients()| Use |vim.lsp.get_clients()| instead.
- |vim.lsp.for_each_buffer_client()| Use |vim.lsp.get_clients()| instead.
+ - |vim.lsp.util.trim_empty_lines()| Use |vim.split()| with `trimempty` instead.
• `vim.loop` has been renamed to `vim.uv`.
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index d0d535566d..0cfeb3dcb7 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -482,7 +482,7 @@ The function will be called with the list of arguments so far, and a second
argument that is the name of the pty.
*gdb-version*
Only debuggers fully compatible with gdb will work. Vim uses the GDB/MI
-interface. The "new-ui" command requires gdb version 7.12 or later. if you
+interface. The "new-ui" command requires gdb version 7.12 or later. If you
get this error:
Undefined command: "new-ui". Try "help".~
Then your gdb is too old.
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index e1518c58bb..0bbbc95141 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2465,8 +2465,8 @@ A jump table for the options with a short description can be found at |Q_op|.
and the value of that item:
item default Used for ~
- stl ' ' or '^' statusline of the current window
- stlnc ' ' or '=' statusline of the non-current windows
+ stl ' ' statusline of the current window
+ stlnc ' ' statusline of the non-current windows
wbr ' ' window bar
horiz '─' or '-' horizontal separators |:split|
horizup '┴' or '-' upwards facing horizontal separator
@@ -2485,9 +2485,7 @@ A jump table for the options with a short description can be found at |Q_op|.
eob '~' empty lines at the end of a buffer
lastline '@' 'display' contains lastline/truncate
- Any one that is omitted will fall back to the default. For "stl" and
- "stlnc" the space will be used when there is highlighting, '^' or '='
- otherwise.
+ Any one that is omitted will fall back to the default.
Note that "horiz", "horizup", "horizdown", "vertleft", "vertright" and
"verthoriz" are only used when 'laststatus' is 3, since only vertical
@@ -3235,9 +3233,8 @@ A jump table for the options with a short description can be found at |Q_op|.
*'ignorecase'* *'ic'* *'noignorecase'* *'noic'*
'ignorecase' 'ic' boolean (default off)
global
- Ignore case in search patterns. Also used when searching in the tags
- file.
- Also see 'smartcase' and 'tagcase'.
+ Ignore case in search patterns, completion, and when searching the tags file.
+ See also 'smartcase' and 'tagcase'.
Can be overruled by using "\c" or "\C" in the pattern, see
|/ignorecase|.
@@ -3570,12 +3567,11 @@ A jump table for the options with a short description can be found at |Q_op|.
'jumpoptions' 'jop' string (default "")
global
List of words that change the behavior of the |jumplist|.
- stack Make the jumplist behave like the tagstack or like a
- web browser. Relative location of entries in the
- jumplist is preserved at the cost of discarding
- subsequent entries when navigating backwards in the
- jumplist and then jumping to a location.
- |jumplist-stack|
+ stack Make the jumplist behave like the tagstack.
+ Relative location of entries in the jumplist is
+ preserved at the cost of discarding subsequent entries
+ when navigating backwards in the jumplist and then
+ jumping to a location. |jumplist-stack|
view When moving through the jumplist, |changelist|,
|alternate-file| or using |mark-motions| try to
@@ -5387,23 +5383,17 @@ A jump table for the options with a short description can be found at |Q_op|.
function to get the effective shiftwidth value.
*'shortmess'* *'shm'* *E1336*
-'shortmess' 'shm' string (default "filnxtToOCF")
+'shortmess' 'shm' string (default "ltToOCF")
global
This option helps to avoid all the |hit-enter| prompts caused by file
messages, for example with CTRL-G, and to avoid some other messages.
It is a list of flags:
flag meaning when present ~
- f use "(3 of 5)" instead of "(file 3 of 5)" *shm-f*
- i use "[noeol]" instead of "[Incomplete last line]" *shm-i*
l use "999L, 888B" instead of "999 lines, 888 bytes" *shm-l*
m use "[+]" instead of "[Modified]" *shm-m*
- n use "[New]" instead of "[New File]" *shm-n*
r use "[RO]" instead of "[readonly]" *shm-r*
w use "[w]" instead of "written" for file write message *shm-w*
and "[a]" instead of "appended" for ':w >> file' command
- x use "[dos]" instead of "[dos format]", "[unix]" *shm-x*
- instead of "[unix format]" and "[mac]" instead of "[mac
- format]"
a all of the above abbreviations *shm-a*
o overwrite message for writing a file with subsequent *shm-o*
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 5f6e932693..17d5b4668d 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -1362,9 +1362,9 @@ paths.
*base-directories* *xdg*
The "base" (root) directories conform to the XDG Base Directory Specification.
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
-The $XDG_CONFIG_HOME, $XDG_DATA_HOME, $XDG_RUNTIME_DIR, and $XDG_STATE_HOME
-environment variables are used if defined, else default values (listed below)
-are used.
+The $XDG_CONFIG_HOME, $XDG_DATA_HOME, $XDG_RUNTIME_DIR, $XDG_STATE_HOME,
+$XDG_CACHE_HOME, $XDG_CONFIG_DIRS and $XDG_DATA_DIRS environment variables
+are used if defined, else default values (listed below) are used.
CONFIG DIRECTORY (DEFAULT) ~
*$XDG_CONFIG_HOME* Nvim: stdpath("config")
@@ -1386,9 +1386,32 @@ STATE DIRECTORY (DEFAULT) ~
Unix: ~/.local/state ~/.local/state/nvim
Windows: ~/AppData/Local ~/AppData/Local/nvim-data
+CACHE DIRECTORY (DEFAULT) ~
+ *$XDG_CACHE_HOME* Nvim: stdpath("cache")
+ Unix: ~/.cache ~/.cache/nvim
+ Windows: ~/AppData/Local/Temp ~/AppData/Local/Temp/nvim-data
+
+LOG FILE (DEFAULT) ~
+ `$NVIM_LOG_FILE` Nvim: stdpath("log")
+ Unix: ~/.local/state/nvim ~/.local/state/nvim/log
+ Windows: ~/AppData/Local/nvim-data ~/AppData/Local/nvim-data/log
+
+ADDITIONAL CONFIGS DIRECTORY (DEFAULT) ~
+ *$XDG_CONFIG_DIRS* Nvim: stdpath("config_dirs")
+ Unix: /etc/xdg/ /etc/xdg/nvim
+ Windows: Not applicable Not applicable
+
+ADDITIONAL DATA DIRECTORY (DEFAULT) ~
+ *$XDG_DATA_DIRS* Nvim: stdpath("data_dirs")
+ Unix: /usr/local/share /usr/local/share/nvim
+ /usr/share /usr/share/nvim
+ Windows: Not applicable Not applicable
+
Note: Throughout the help pages these defaults are used as placeholders, e.g.
"~/.config" is understood to mean "$XDG_CONFIG_HOME or ~/.config".
+Note: The log file directory is controlled by `$XDG_STATE_HOME`.
+
NVIM_APPNAME *$NVIM_APPNAME*
The standard directories can be further configured by the `$NVIM_APPNAME`
environment variable. This variable controls the sub-directory that Nvim will
@@ -1408,8 +1431,8 @@ LOG FILE *log* *$NVIM_LOG_FILE* *E5430*
Besides 'debug' and 'verbose', Nvim keeps a general log file for internal
debugging, plugins and RPC clients. >
:echo $NVIM_LOG_FILE
-By default, the file is located at stdpath("log")/log unless that path
-is inaccessible or if $NVIM_LOG_FILE was set before |startup|.
+By default, the file is located at stdpath("log")/log ($XDG_STATE_HOME/nvim/log)
+unless that path is inaccessible or if $NVIM_LOG_FILE was set before |startup|.
vim:noet:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index c15b41f9aa..e1053b54f1 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -5322,8 +5322,6 @@ SpellRare Word that is recognized by the spellchecker as one that is
StatusLine Status line of current window.
*hl-StatusLineNC*
StatusLineNC Status lines of not-current windows.
- Note: If this is equal to "StatusLine", Vim will use "^^^" in
- the status line of the current window.
*hl-TabLine*
TabLine Tab pages line, not active tab page label.
*hl-TabLineFill*
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index e1e280c4db..34971c7acf 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -854,12 +854,14 @@ add_predicate({name}, {handler}, {force})
• {force} (boolean|nil)
edit({lang}) *vim.treesitter.query.edit()*
- Open a window for live editing of a treesitter query.
+ Opens a live editor to query the buffer you started from.
- Can also be shown with `:EditQuery`. *:EditQuery*
+ Can also be shown with *:EditQuery*.
- Note that the editor opens a scratch buffer, and so queries aren't
- persisted on disk.
+ If you move the cursor to a capture name ("@foo"), text matching the
+ capture is highlighted in the source buffer. The query editor is a scratch
+ buffer, use `:write` to save it. You can find example queries at
+ `$VIMRUNTIME/queries/`.
Parameters: ~
• {lang} (string|nil) language to open the query editor for. If
@@ -1101,10 +1103,12 @@ LanguageTree:for_each_tree({fn}) *LanguageTree:for_each_tree()*
• {fn} fun(tree: TSTree, ltree: LanguageTree)
LanguageTree:included_regions() *LanguageTree:included_regions()*
- Gets the set of included regions
+ Gets the set of included regions managed by this LanguageTree . This can be different from the regions set by injection query, because a
+ partial |LanguageTree:parse()| drops the regions outside the requested
+ range.
Return: ~
- Range6[][]
+ table<integer, Range6[]>
LanguageTree:invalidate({reload}) *LanguageTree:invalidate()*
Invalidates this parser and all its children
@@ -1113,10 +1117,12 @@ LanguageTree:invalidate({reload}) *LanguageTree:invalidate()*
• {reload} (boolean|nil)
LanguageTree:is_valid({exclude_children}) *LanguageTree:is_valid()*
- Determines whether this tree is valid. If the tree is invalid, call `parse()` . This will return the updated tree.
+ Returns whether this LanguageTree is valid, i.e., |LanguageTree:trees()| reflects the latest state of the
+ source. If invalid, user should call |LanguageTree:parse()|.
Parameters: ~
- • {exclude_children} (boolean|nil)
+ • {exclude_children} (boolean|nil) whether to ignore the validity of
+ children (default `false`)
Return: ~
(boolean)
@@ -1165,7 +1171,7 @@ LanguageTree:parse({range}) *LanguageTree:parse()*
injections).
Return: ~
- TSTree[]
+ table<integer, TSTree>
*LanguageTree:register_cbs()*
LanguageTree:register_cbs({cbs}, {recursive})
@@ -1207,7 +1213,12 @@ LanguageTree:tree_for_range({range}, {opts})
TSTree|nil
LanguageTree:trees() *LanguageTree:trees()*
- Returns all trees this language tree contains. Does not include child
- languages.
+ Returns all trees of the regions parsed by this parser. Does not include
+ child languages. The result is list-like if
+ • this LanguageTree is the root, in which case the result is empty or a singleton list; or
+ • the root LanguageTree is fully parsed.
+
+ Return: ~
+ table<integer, TSTree>
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
diff --git a/runtime/doc/usr_02.txt b/runtime/doc/usr_02.txt
index 259bb41200..1fc612de26 100644
--- a/runtime/doc/usr_02.txt
+++ b/runtime/doc/usr_02.txt
@@ -40,7 +40,7 @@ blank window. This is what your screen will look like:
|~ |
|~ |
|~ |
- |"file.txt" [New file] |
+ |"file.txt" [New] |
+---------------------------------------+
('#' is the cursor position.)
<
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index ab5e795c16..e636746616 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -45,7 +45,7 @@ Defaults *nvim-defaults*
- 'directory' defaults to ~/.local/state/nvim/swap// (|xdg|), auto-created
- 'display' defaults to "lastline"
- 'encoding' is UTF-8 (cf. 'fileencoding' for file-content encoding)
-- 'fillchars' defaults (in effect) to "vert:│,fold:·,sep:│"
+- 'fillchars' defaults (in effect) to "vert:│,fold:·,foldsep:│"
- 'formatoptions' defaults to "tcqj"
- 'fsync' is disabled
- 'hidden' is enabled
@@ -534,6 +534,10 @@ Vimscript compatibility:
`shell_error` does not alias to |v:shell_error|
`this_session` does not alias to |v:this_session|
+UI/Display:
+ 'statusline' always uses the "stl" and "stlnc" fields of 'fillchars', even
+ if they are the same and |hl-StatusLine| and |hl-StatusLineNC| are equal.
+
Working directory (Vim implemented some of these after Nvim):
- |DirChanged| and |DirChangedPre| can be triggered when switching to another
window or tab.
@@ -727,6 +731,7 @@ Options:
Everything is allowed in 'exrc' files since they must be explicitly marked
trusted.
*'shelltype'*
+ 'shortmess' flags: *shm-f* *shm-n* *shm-x* *shm-i* (behave like always on)
*'shortname'* *'sn'* *'noshortname'* *'nosn'*
*'swapsync'* *'sws'*
*'termencoding'* *'tenc'* (Vim 7.4.852 also removed this for Windows)
diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt
index 6ca486e8cf..0d1ea937c0 100644
--- a/runtime/doc/visual.txt
+++ b/runtime/doc/visual.txt
@@ -169,6 +169,7 @@ If you want to highlight exactly the same area as the last time, you can use
CTRL-C In Visual mode: Stop Visual mode. When insert mode is
pending (the mode message shows
"-- (insert) VISUAL --"), it is also stopped.
+ On MS-Windows, you may need to press CTRL-Break.
==============================================================================
3. Changing the Visual area *visual-change*
diff --git a/runtime/ftplugin/d.lua b/runtime/ftplugin/d.lua
new file mode 100644
index 0000000000..b4e68148f5
--- /dev/null
+++ b/runtime/ftplugin/d.lua
@@ -0,0 +1 @@
+vim.bo.commentstring = '/*%s*/'
diff --git a/runtime/ftplugin/kotlin.vim b/runtime/ftplugin/kotlin.vim
new file mode 100644
index 0000000000..b21de603ea
--- /dev/null
+++ b/runtime/ftplugin/kotlin.vim
@@ -0,0 +1,33 @@
+" Vim filetype plugin file
+" Language: Kotlin
+" Maintainer: Alexander Udalov
+" URL: https://github.com/udalov/kotlin-vim
+" Last Change: 7 November 2021
+" 2023 Sep 17 by Vim Project (browsefilter)
+
+if exists('b:did_ftplugin') | finish | endif
+let b:did_ftplugin = 1
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
+setlocal commentstring=//\ %s
+
+setlocal formatoptions-=t formatoptions+=croqnl
+silent! setlocal formatoptions+=j
+
+setlocal includeexpr=substitute(v:fname,'\\.','/','g')
+setlocal suffixesadd=.kt
+
+let b:undo_ftplugin = "setlocal comments< commentstring< ".
+ \ "formatoptions< includeexpr< suffixesadd<"
+
+if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
+ let b:browsefilter = "Kotlin Source Files (*.kt, *kts)\t*.kt;*.kts\n" .
+ \ "All Files (*.*)\t*.*\n"
+ let b:undo_ftplugin .= " | unlet! b:browsefilter"
+endif
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
diff --git a/runtime/ftplugin/sh.vim b/runtime/ftplugin/sh.vim
index 4409f3f90c..c227838d18 100644
--- a/runtime/ftplugin/sh.vim
+++ b/runtime/ftplugin/sh.vim
@@ -39,8 +39,7 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
let b:undo_ftplugin ..= " | unlet! b:browsefilter"
endif
-if (exists("b:is_bash") && (b:is_bash == 1)) ||
- \ (exists("b:is_sh") && (b:is_sh == 1))
+if (exists("b:is_bash") && (b:is_bash == 1))
if !has("gui_running") && executable("less")
command! -buffer -nargs=1 Help silent exe '!bash -c "{ help "<args>" 2>/dev/null || man "<args>"; } | LESS= less"' | redraw!
elseif has('terminal')
diff --git a/runtime/indent/kotlin.vim b/runtime/indent/kotlin.vim
new file mode 100644
index 0000000000..590a5074d1
--- /dev/null
+++ b/runtime/indent/kotlin.vim
@@ -0,0 +1,60 @@
+" Vim indent file
+" Language: Kotlin
+" Maintainer: Alexander Udalov
+" URL: https://github.com/udalov/kotlin-vim
+" Last Change: 7 November 2021
+" 2023 Sep 17 by Vim Project (undo_indent)
+
+if exists('b:did_indent')
+ finish
+endif
+let b:did_indent = 1
+
+setlocal cinoptions& cinoptions+=j1,L0
+setlocal indentexpr=GetKotlinIndent()
+setlocal indentkeys=0},0),!^F,o,O,e,<CR>
+setlocal autoindent " TODO ?
+
+let b:undo_indent = "setlocal autoindent< cinoptions< indentexpr< indentkeys<"
+
+" TODO teach it to count bracket balance, etc.
+function! GetKotlinIndent()
+ if v:lnum == 0
+ return 0
+ endif
+
+ let prev_num = prevnonblank(v:lnum - 1)
+ let prev = getline(prev_num)
+ let prev_indent = indent(prev_num)
+ let cur = getline(v:lnum)
+
+ if cur =~ '^\s*\*'
+ return cindent(v:lnum)
+ endif
+
+ if prev =~ '^\s*\*/'
+ let st = prev
+ while st > 1
+ if getline(st) =~ '^\s*/\*'
+ break
+ endif
+ let st = st - 1
+ endwhile
+ return indent(st)
+ endif
+
+ let prev_open_paren = prev =~ '^.*(\s*$'
+ let cur_close_paren = cur =~ '^\s*).*$'
+ let prev_open_brace = prev =~ '^.*\({\|->\)\s*$'
+ let cur_close_brace = cur =~ '^\s*}.*$'
+
+ if prev_open_paren && !cur_close_paren || prev_open_brace && !cur_close_brace
+ return prev_indent + shiftwidth()
+ endif
+
+ if cur_close_paren && !prev_open_paren || cur_close_brace && !prev_open_brace
+ return prev_indent - shiftwidth()
+ endif
+
+ return prev_indent
+endfunction
diff --git a/runtime/lua/nvim/health.lua b/runtime/lua/nvim/health.lua
index 7ccb082a40..6b6370fa19 100644
--- a/runtime/lua/nvim/health.lua
+++ b/runtime/lua/nvim/health.lua
@@ -54,15 +54,19 @@ local function check_config()
health.start('Configuration')
local ok = true
- local vimrc = (
- empty(vim.env.MYVIMRC) and vim.fn.stdpath('config') .. '/init.vim' or vim.env.MYVIMRC
- )
- if not filereadable(vimrc) then
+ local init_lua = vim.fn.stdpath('config') .. '/init.lua'
+ local init_vim = vim.fn.stdpath('config') .. '/init.vim'
+ local vimrc = empty(vim.env.MYVIMRC) and init_lua or vim.env.MYVIMRC
+
+ if not filereadable(vimrc) and not filereadable(init_vim) then
ok = false
local has_vim = filereadable(vim.fn.expand('~/.vimrc'))
health.warn(
- (-1 == vim.fn.getfsize(vimrc) and 'Missing' or 'Unreadable') .. ' user config file: ' .. vimrc,
- { has_vim and ':help nvim-from-vim' or ':help init.vim' }
+ ('%s user config file: %s'):format(
+ -1 == vim.fn.getfsize(vimrc) and 'Missing' or 'Unreadable',
+ vimrc
+ ),
+ { has_vim and ':help nvim-from-vim' or ':help config' }
)
end
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 0215cae0cb..7f09fc8038 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -29,6 +29,7 @@ for k, v in pairs({
treesitter = true,
filetype = true,
loader = true,
+ func = true,
F = true,
lsp = true,
highlight = true,
@@ -315,18 +316,29 @@ do
end
end
---- Defers callback `cb` until the Nvim API is safe to call.
+--- Returns a function which calls {fn} via |vim.schedule()|.
+---
+--- The returned function passes all arguments to {fn}.
+---
+--- Example:
+---
+--- ```lua
+--- function notify_readable(_err, readable)
+--- vim.notify("readable? " .. tostring(readable))
+--- end
+--- vim.uv.fs_access(vim.fn.stdpath("config"), "R", vim.schedule_wrap(notify_readable))
+--- ```
---
---@see |lua-loop-callbacks|
---@see |vim.schedule()|
---@see |vim.in_fast_event()|
----@param cb function
+---@param fn function
---@return function
-function vim.schedule_wrap(cb)
+function vim.schedule_wrap(fn)
return function(...)
local args = vim.F.pack_len(...)
vim.schedule(function()
- cb(vim.F.unpack_len(args))
+ fn(vim.F.unpack_len(args))
end)
end
end
@@ -876,7 +888,7 @@ end
--- Example:
---
--- ```lua
---- local hl_normal = vim.print(vim.api.nvim_get_hl_by_name('Normal', true))
+--- local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' }))
--- ```
---
--- @see |vim.inspect()|
diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua
index 5e4f390ca3..ddd0a0eb49 100644
--- a/runtime/lua/vim/_meta.lua
+++ b/runtime/lua/vim/_meta.lua
@@ -10,6 +10,7 @@ vim._watch = require('vim._watch')
vim.diagnostic = require('vim.diagnostic')
vim.filetype = require('vim.filetype')
vim.fs = require('vim.fs')
+vim.func = require('vim.func')
vim.health = require('vim.health')
vim.highlight = require('vim.highlight')
vim.iter = require('vim.iter')
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index 3822e5ff5b..68ef54eb2f 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -80,6 +80,9 @@ function vim.api.nvim__id_float(flt) end
function vim.api.nvim__inspect_cell(grid, row, col) end
--- @private
+function vim.api.nvim__invalidate_glyph_cache() end
+
+--- @private
--- @return any[]
function vim.api.nvim__runtime_inspect() end
@@ -422,6 +425,7 @@ function vim.api.nvim_buf_get_number(buffer) end
--- @return integer
function vim.api.nvim_buf_get_offset(buffer, index) end
+--- @deprecated
--- @param buffer integer
--- @param name string
--- @return any
@@ -629,6 +633,7 @@ function vim.api.nvim_buf_set_mark(buffer, name, line, col, opts) end
--- @param name string Buffer name
function vim.api.nvim_buf_set_name(buffer, name) end
+--- @deprecated
--- @param buffer integer
--- @param name string
--- @param value any
@@ -1280,10 +1285,12 @@ function vim.api.nvim_get_mode() end
--- @return table<string,any>
function vim.api.nvim_get_namespaces() end
+--- @deprecated
--- @param name string
--- @return any
function vim.api.nvim_get_option(name) end
+--- @deprecated
--- @param name string
--- @return table<string,any>
function vim.api.nvim_get_option_info(name) end
@@ -1608,6 +1615,8 @@ function vim.api.nvim_open_term(buffer, opts) end
--- • noautocmd: If true then no buffer-related autocommand
--- events such as `BufEnter`, `BufLeave` or `BufWinEnter` may
--- fire from calling this function.
+--- • fixed: If true when anchor is NW or SW, the float window
+--- would be kept fixed even if the window would be truncated.
--- @return integer
function vim.api.nvim_open_win(buffer, enter, config) end
@@ -1900,7 +1909,7 @@ function vim.api.nvim_set_hl_ns_fast(ns_id) end
--- @param rhs string Right-hand-side `{rhs}` of the mapping.
--- @param opts vim.api.keyset.keymap Optional parameters map: Accepts all `:map-arguments` as keys
--- except `<buffer>`, values are booleans (default false). Also:
---- • "noremap" non-recursive mapping `:noremap`
+--- • "noremap" disables `recursive_mapping`, like `:noremap`
--- • "desc" human-readable description.
--- • "callback" Lua function called in place of {rhs}.
--- • "replace_keycodes" (boolean) When "expr" is true, replace
@@ -1909,6 +1918,7 @@ function vim.api.nvim_set_hl_ns_fast(ns_id) end
--- "callback" is equivalent to returning an empty string.
function vim.api.nvim_set_keymap(mode, lhs, rhs, opts) end
+--- @deprecated
--- @param name string
--- @param value any
function vim.api.nvim_set_option(name, value) end
@@ -2112,6 +2122,7 @@ function vim.api.nvim_win_get_height(window) end
--- @return integer
function vim.api.nvim_win_get_number(window) end
+--- @deprecated
--- @param window integer
--- @param name string
--- @return any
@@ -2194,6 +2205,7 @@ function vim.api.nvim_win_set_height(window, height) end
--- @param ns_id integer the namespace to use
function vim.api.nvim_win_set_hl_ns(window, ns_id) end
+--- @deprecated
--- @param window integer
--- @param name string
--- @param value any
diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua
index 349c68f8f9..eaaa32d7b3 100644
--- a/runtime/lua/vim/_meta/api_keysets.lua
+++ b/runtime/lua/vim/_meta/api_keysets.lua
@@ -112,6 +112,7 @@ error('Cannot require a meta file')
--- @field footer_pos? string
--- @field style? string
--- @field noautocmd? boolean
+--- @field fixed? boolean
--- @class vim.api.keyset.get_autocmds
--- @field event? any
diff --git a/runtime/lua/vim/_meta/builtin.lua b/runtime/lua/vim/_meta/builtin.lua
index 0a6dd3e151..92c23f7764 100644
--- a/runtime/lua/vim/_meta/builtin.lua
+++ b/runtime/lua/vim/_meta/builtin.lua
@@ -194,10 +194,10 @@ function vim.str_utfindex(str, index) end
--- @return string|nil Converted string if conversion succeeds, `nil` otherwise.
function vim.iconv(str, from, to, opts) end
---- Schedules {callback} to be invoked soon by the main event-loop. Useful
+--- Schedules {fn} to be invoked soon by the main event-loop. Useful
--- to avoid |textlock| or other temporary restrictions.
---- @param callback fun()
-function vim.schedule(callback) end
+--- @param fn function
+function vim.schedule(fn) end
--- Wait for {time} in milliseconds until {callback} returns `true`.
---
diff --git a/runtime/lua/vim/_meta/json.lua b/runtime/lua/vim/_meta/json.lua
index edf905c7c6..e010086615 100644
--- a/runtime/lua/vim/_meta/json.lua
+++ b/runtime/lua/vim/_meta/json.lua
@@ -1,5 +1,8 @@
---@meta
+---@nodoc
+vim.json = {}
+
-- luacheck: no unused args
---@defgroup vim.json
diff --git a/runtime/lua/vim/_meta/lpeg.lua b/runtime/lua/vim/_meta/lpeg.lua
new file mode 100644
index 0000000000..42c9a6449e
--- /dev/null
+++ b/runtime/lua/vim/_meta/lpeg.lua
@@ -0,0 +1,323 @@
+--- @meta
+
+-- These types were taken from https://github.com/LuaCATS/lpeg, with types being renamed to include
+-- the vim namespace and with some descriptions made less verbose.
+
+--- *LPeg* is a new pattern-matching library for Lua, based on [Parsing Expression Grammars](https://bford.info/packrat/) (PEGs).
+vim.lpeg = {}
+
+--- @class vim.lpeg.Pattern
+--- @operator unm: vim.lpeg.Pattern
+--- @operator add(vim.lpeg.Pattern): vim.lpeg.Pattern
+--- @operator sub(vim.lpeg.Pattern): vim.lpeg.Pattern
+--- @operator mul(vim.lpeg.Pattern): vim.lpeg.Pattern
+--- @operator mul(vim.lpeg.Capture): vim.lpeg.Pattern
+--- @operator div(string): vim.lpeg.Capture
+--- @operator div(number): vim.lpeg.Capture
+--- @operator div(table): vim.lpeg.Capture
+--- @operator div(function): vim.lpeg.Capture
+--- @operator pow(number): vim.lpeg.Pattern
+--- @operator mod(function): nil
+local Pattern = {}
+
+--- @alias vim.lpeg.Capture vim.lpeg.Pattern
+
+--- Matches the given `pattern` against the `subject` string. If the match succeeds, returns the index in the
+--- subject of the first character after the match, or the captured values (if the pattern captured any value).
+--- An optional numeric argument `init` makes the match start at that position in the subject string. As usual
+--- in Lua libraries, a negative value counts from the end. Unlike typical pattern-matching functions, `match`
+--- works only in anchored mode; that is, it tries to match the pattern with a prefix of the given subject
+--- string (at position `init`), not with an arbitrary substring of the subject. So, if we want to find a
+--- pattern anywhere in a string, we must either write a loop in Lua or write a pattern that
+--- matches anywhere.
+---
+--- Example:
+--- ```lua
+--- local pattern = lpeg.R("az") ^ 1 * -1
+--- assert(pattern:match("hello") == 6)
+--- assert(lpeg.match(pattern, "hello") == 6)
+--- assert(pattern:match("1 hello") == nil)
+--- ```
+---
+--- @param pattern vim.lpeg.Pattern
+--- @param subject string
+--- @param init? integer
+--- @return integer|vim.lpeg.Capture|nil
+function vim.lpeg.match(pattern, subject, init) end
+
+--- Matches the given `pattern` against the `subject` string. If the match succeeds, returns the
+--- index in the subject of the first character after the match, or the captured values (if the
+--- pattern captured any value). An optional numeric argument `init` makes the match start at
+--- that position in the subject string. As usual in Lua libraries, a negative value counts from the end.
+--- Unlike typical pattern-matching functions, `match` works only in anchored mode; that is, it tries
+--- to match the pattern with a prefix of the given subject string (at position `init`), not with
+--- an arbitrary substring of the subject. So, if we want to find a pattern anywhere in a string,
+--- we must either write a loop in Lua or write a pattern that matches anywhere.
+---
+--- Example:
+--- ```lua
+--- local pattern = lpeg.R("az") ^ 1 * -1
+--- assert(pattern:match("hello") == 6)
+--- assert(lpeg.match(pattern, "hello") == 6)
+--- assert(pattern:match("1 hello") == nil)
+--- ```
+---
+--- @param subject string
+--- @param init? integer
+--- @return integer|vim.lpeg.Capture|nil
+function Pattern:match(subject, init) end
+
+--- Returns the string `"pattern"` if the given value is a pattern, otherwise `nil`.
+---
+--- @return 'pattern'|nil
+function vim.lpeg.type(value) end
+
+--- Returns a string with the running version of LPeg.
+--- @return string
+function vim.lpeg.version() end
+
+--- Sets a limit for the size of the backtrack stack used by LPeg to track calls and choices.
+--- The default limit is `400`. Most well-written patterns need little backtrack levels and
+--- therefore you seldom need to change this limit; before changing it you should try to rewrite
+--- your pattern to avoid the need for extra space. Nevertheless, a few useful patterns may overflow.
+--- Also, with recursive grammars, subjects with deep recursion may also need larger limits.
+---
+--- @param max integer
+function vim.lpeg.setmaxstack(max) end
+
+--- Converts the given value into a proper pattern. This following rules are applied:
+--- * If the argument is a pattern, it is returned unmodified.
+--- * If the argument is a string, it is translated to a pattern that matches the string literally.
+--- * If the argument is a non-negative number `n`, the result is a pattern that matches exactly `n` characters.
+--- * If the argument is a negative number `-n`, the result is a pattern that succeeds only if
+--- the input string has less than `n` characters left: `lpeg.P(-n)` is equivalent to `-lpeg.P(n)`
+--- (see the unary minus operation).
+--- * If the argument is a boolean, the result is a pattern that always succeeds or always fails
+--- (according to the boolean value), without consuming any input.
+--- * If the argument is a table, it is interpreted as a grammar (see Grammars).
+--- * If the argument is a function, returns a pattern equivalent to a match-time captureover the empty string.
+---
+--- @param value vim.lpeg.Pattern|string|integer|boolean|table|function
+--- @return vim.lpeg.Pattern
+function vim.lpeg.P(value) end
+
+--- Returns a pattern that matches only if the input string at the current position is preceded by `patt`.
+--- Pattern `patt` must match only strings with some fixed length, and it cannot contain captures.
+--- Like the and predicate, this pattern never consumes any input, independently of success or failure.
+---
+--- @param pattern vim.lpeg.Pattern
+--- @return vim.lpeg.Pattern
+function vim.lpeg.B(pattern) end
+
+--- Returns a pattern that matches any single character belonging to one of the given ranges.
+--- Each `range` is a string `xy` of length 2, representing all characters with code between the codes of
+--- `x` and `y` (both inclusive). As an example, the pattern `lpeg.R("09")` matches any digit, and
+--- `lpeg.R("az", "AZ")` matches any ASCII letter.
+---
+--- Example:
+--- ```lua
+--- local pattern = lpeg.R("az") ^ 1 * -1
+--- assert(pattern:match("hello") == 6)
+--- ```
+---
+--- @param ... string
+--- @return vim.lpeg.Pattern
+function vim.lpeg.R(...) end
+
+--- Returns a pattern that matches any single character that appears in the given string (the `S` stands for Set).
+--- As an example, the pattern `lpeg.S("+-*/")` matches any arithmetic operator. Note that, if `s` is a character
+--- (that is, a string of length 1), then `lpeg.P(s)` is equivalent to `lpeg.S(s)` which is equivalent to
+--- `lpeg.R(s..s)`. Note also that both `lpeg.S("")` and `lpeg.R()` are patterns that always fail.
+---
+--- @param string string
+--- @return vim.lpeg.Pattern
+function vim.lpeg.S(string) end
+
+--- Creates a non-terminal (a variable) for a grammar. This operation creates a non-terminal (a variable)
+--- for a grammar. The created non-terminal refers to the rule indexed by `v` in the enclosing grammar.
+---
+--- Example:
+--- ```lua
+--- local b = lpeg.P({"(" * ((1 - lpeg.S "()") + lpeg.V(1)) ^ 0 * ")"})
+--- assert(b:match('((string))') == 11)
+--- assert(b:match('(') == nil)
+--- ```
+---
+--- @param v string|integer
+--- @return vim.lpeg.Pattern
+function vim.lpeg.V(v) end
+
+--- @class vim.lpeg.Locale
+--- @field alnum userdata
+--- @field alpha userdata
+--- @field cntrl userdata
+--- @field digit userdata
+--- @field graph userdata
+--- @field lower userdata
+--- @field print userdata
+--- @field punct userdata
+--- @field space userdata
+--- @field upper userdata
+--- @field xdigit userdata
+
+--- Returns a table with patterns for matching some character classes according to the current locale.
+--- The table has fields named `alnum`, `alpha`, `cntrl`, `digit`, `graph`, `lower`, `print`, `punct`,
+--- `space`, `upper`, and `xdigit`, each one containing a correspondent pattern. Each pattern matches
+--- any single character that belongs to its class.
+--- If called with an argument `table`, then it creates those fields inside the given table and returns
+--- that table.
+---
+--- Example:
+--- ```lua
+--- lpeg.locale(lpeg)
+--- local space = lpeg.space^0
+--- local name = lpeg.C(lpeg.alpha^1) * space
+--- local sep = lpeg.S(",;") * space
+--- local pair = lpeg.Cg(name * "=" * space * name) * sep^-1
+--- local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset)
+--- local t = list:match("a=b, c = hi; next = pi")
+--- assert(t.a == 'b')
+--- assert(t.c == 'hi')
+--- assert(t.next == 'pi')
+--- local locale = lpeg.locale()
+--- assert(type(locale.digit) == 'userdata')
+--- ```
+---
+--- @param tab? table
+--- @return vim.lpeg.Locale
+function vim.lpeg.locale(tab) end
+
+--- Creates a simple capture, which captures the substring of the subject that matches `patt`.
+--- The captured value is a string. If `patt` has other captures, their values are returned after this one.
+---
+--- Example:
+--- ```lua
+--- local function split (s, sep)
+--- sep = lpeg.P(sep)
+--- local elem = lpeg.C((1 - sep)^0)
+--- local p = elem * (sep * elem)^0
+--- return lpeg.match(p, s)
+--- end
+--- local a, b, c = split('a,b,c', ',')
+--- assert(a == 'a')
+--- assert(b == 'b')
+--- assert(c == 'c')
+--- ```
+---
+--- @param patt vim.lpeg.Pattern
+--- @return vim.lpeg.Capture
+function vim.lpeg.C(patt) end
+
+--- Creates an argument capture. This pattern matches the empty string and produces the value given as the
+--- nth extra argument given in the call to `lpeg.match`.
+--- @param n integer
+--- @return vim.lpeg.Capture
+function vim.lpeg.Carg(n) end
+
+--- Creates a back capture. This pattern matches the empty string and produces the values produced by the most recent
+--- group capture named `name` (where `name` can be any Lua value). Most recent means the last complete outermost
+--- group capture with the given name. A Complete capture means that the entire pattern corresponding to the capture
+--- has matched. An Outermost capture means that the capture is not inside another complete capture.
+--- In the same way that LPeg does not specify when it evaluates captures, it does not specify whether it reuses
+--- values previously produced by the group or re-evaluates them.
+---
+--- @param name any
+--- @return vim.lpeg.Capture
+function vim.lpeg.Cb(name) end
+
+--- Creates a constant capture. This pattern matches the empty string and produces all given values as its captured values.
+---
+--- @param ... any
+--- @return vim.lpeg.Capture
+function vim.lpeg.Cc(...) end
+
+--- Creates a fold capture. If `patt` produces a list of captures C1 C2 ... Cn, this capture will produce the value
+--- `func(...func(func(C1, C2), C3)...,Cn)`, that is, it will fold (or accumulate, or reduce) the captures from
+--- `patt` using function `func`. This capture assumes that `patt` should produce at least one capture with at
+--- least one value (of any type), which becomes the initial value of an accumulator. (If you need a specific
+--- initial value, you may prefix a constant captureto `patt`.) For each subsequent capture, LPeg calls `func`
+--- with this accumulator as the first argument and all values produced by the capture as extra arguments;
+--- the first result from this call becomes the new value for the accumulator. The final value of the accumulator
+--- becomes the captured value.
+---
+--- Example:
+--- ```lua
+--- local number = lpeg.R("09") ^ 1 / tonumber
+--- local list = number * ("," * number) ^ 0
+--- local function add(acc, newvalue) return acc + newvalue end
+--- local sum = lpeg.Cf(list, add)
+--- assert(sum:match("10,30,43") == 83)
+--- ```
+---
+--- @param patt vim.lpeg.Pattern
+--- @param func fun(acc, newvalue)
+--- @return vim.lpeg.Capture
+function vim.lpeg.Cf(patt, func) end
+
+--- Creates a group capture. It groups all values returned by `patt` into a single capture.
+--- The group may be anonymous (if no name is given) or named with the given name (which
+--- can be any non-nil Lua value).
+---
+--- @param patt vim.lpeg.Pattern
+--- @param name? string
+--- @return vim.lpeg.Capture
+function vim.lpeg.Cg(patt, name) end
+
+--- Creates a position capture. It matches the empty string and captures the position in the
+--- subject where the match occurs. The captured value is a number.
+---
+--- Example:
+--- ```lua
+--- local I = lpeg.Cp()
+--- local function anywhere(p) return lpeg.P({I * p * I + 1 * lpeg.V(1)}) end
+--- local match_start, match_end = anywhere("world"):match("hello world!")
+--- assert(match_start == 7)
+--- assert(match_end == 12)
+--- ```
+---
+--- @return vim.lpeg.Capture
+function vim.lpeg.Cp() end
+
+--- Creates a substitution capture. This function creates a substitution capture, which
+--- captures the substring of the subject that matches `patt`, with substitutions.
+--- For any capture inside `patt` with a value, the substring that matched the capture
+--- is replaced by the capture value (which should be a string). The final captured
+--- value is the string resulting from all replacements.
+---
+--- Example:
+--- ```lua
+--- local function gsub (s, patt, repl)
+--- patt = lpeg.P(patt)
+--- patt = lpeg.Cs((patt / repl + 1)^0)
+--- return lpeg.match(patt, s)
+--- end
+--- assert(gsub('Hello, xxx!', 'xxx', 'World') == 'Hello, World!')
+--- ```
+---
+--- @param patt vim.lpeg.Pattern
+--- @return vim.lpeg.Capture
+function vim.lpeg.Cs(patt) end
+
+--- Creates a table capture. This capture returns a table with all values from all anonymous captures
+--- made by `patt` inside this table in successive integer keys, starting at 1.
+--- Moreover, for each named capture group created by `patt`, the first value of the group is put into
+--- the table with the group name as its key. The captured value is only the table.
+---
+--- @param patt vim.lpeg.Pattern|''
+--- @return vim.lpeg.Capture
+function vim.lpeg.Ct(patt) end
+
+--- Creates a match-time capture. Unlike all other captures, this one is evaluated immediately when a match occurs
+--- (even if it is part of a larger pattern that fails later). It forces the immediate evaluation of all its nested captures
+--- and then calls `function`. The given function gets as arguments the entire subject, the current position
+--- (after the match of `patt`), plus any capture values produced by `patt`. The first value returned by `function`
+--- defines how the match happens. If the call returns a number, the match succeeds and the returned number
+--- becomes the new current position. (Assuming a subject sand current position i, the returned number must be
+--- in the range [i, len(s) + 1].) If the call returns true, the match succeeds without consuming any input
+--- (so, to return true is equivalent to return i). If the call returns false, nil, or no value, the match fails.
+--- Any extra values returned by the function become the values produced by the capture.
+---
+--- @param patt vim.lpeg.Pattern
+--- @param fn function
+--- @return vim.lpeg.Capture
+function vim.lpeg.Cmt(patt, fn) end
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index af676fa961..6ef3cf57e1 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -2181,8 +2181,8 @@ vim.bo.ft = vim.bo.filetype
--- and the value of that item:
---
--- item default Used for ~
---- stl ' ' or '^' statusline of the current window
---- stlnc ' ' or '=' statusline of the non-current windows
+--- stl ' ' statusline of the current window
+--- stlnc ' ' statusline of the non-current windows
--- wbr ' ' window bar
--- horiz '─' or '-' horizontal separators `:split`
--- horizup '┴' or '-' upwards facing horizontal separator
@@ -2201,9 +2201,7 @@ vim.bo.ft = vim.bo.filetype
--- eob '~' empty lines at the end of a buffer
--- lastline '@' 'display' contains lastline/truncate
---
---- Any one that is omitted will fall back to the default. For "stl" and
---- "stlnc" the space will be used when there is highlighting, '^' or '='
---- otherwise.
+--- Any one that is omitted will fall back to the default.
---
--- Note that "horiz", "horizup", "horizdown", "vertleft", "vertright" and
--- "verthoriz" are only used when 'laststatus' is 3, since only vertical
@@ -3088,9 +3086,8 @@ vim.go.icon = vim.o.icon
vim.o.iconstring = ""
vim.go.iconstring = vim.o.iconstring
---- Ignore case in search patterns. Also used when searching in the tags
---- file.
---- Also see 'smartcase' and 'tagcase'.
+--- Ignore case in search patterns, completion, and when searching the tags file.
+--- See also 'smartcase' and 'tagcase'.
--- Can be overruled by using "\c" or "\C" in the pattern, see
--- `/ignorecase`.
---
@@ -3486,12 +3483,11 @@ vim.go.joinspaces = vim.o.joinspaces
vim.go.js = vim.go.joinspaces
--- List of words that change the behavior of the `jumplist`.
---- stack Make the jumplist behave like the tagstack or like a
---- web browser. Relative location of entries in the
---- jumplist is preserved at the cost of discarding
---- subsequent entries when navigating backwards in the
---- jumplist and then jumping to a location.
---- `jumplist-stack`
+--- stack Make the jumplist behave like the tagstack.
+--- Relative location of entries in the jumplist is
+--- preserved at the cost of discarding subsequent entries
+--- when navigating backwards in the jumplist and then
+--- jumping to a location. `jumplist-stack`
---
--- view When moving through the jumplist, `changelist|,
--- |alternate-file` or using `mark-motions` try to
@@ -5670,17 +5666,11 @@ vim.bo.sw = vim.bo.shiftwidth
--- messages, for example with CTRL-G, and to avoid some other messages.
--- It is a list of flags:
--- flag meaning when present ~
---- f use "(3 of 5)" instead of "(file 3 of 5)" *shm-f*
---- i use "[noeol]" instead of "[Incomplete last line]" *shm-i*
--- l use "999L, 888B" instead of "999 lines, 888 bytes" *shm-l*
--- m use "[+]" instead of "[Modified]" *shm-m*
---- n use "[New]" instead of "[New File]" *shm-n*
--- r use "[RO]" instead of "[readonly]" *shm-r*
--- w use "[w]" instead of "written" for file write message *shm-w*
--- and "[a]" instead of "appended" for ':w >> file' command
---- x use "[dos]" instead of "[dos format]", "[unix]" *shm-x*
---- instead of "[unix format]" and "[mac]" instead of "[mac
---- format]"
--- a all of the above abbreviations *shm-a*
---
--- o overwrite message for writing a file with subsequent *shm-o*
@@ -5724,7 +5714,7 @@ vim.bo.sw = vim.bo.shiftwidth
--- shm=at Abbreviation, and truncate message when necessary.
---
--- @type string
-vim.o.shortmess = "filnxtToOCF"
+vim.o.shortmess = "ltToOCF"
vim.o.shm = vim.o.shortmess
vim.go.shortmess = vim.o.shortmess
vim.go.shm = vim.go.shortmess
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 2062e96b21..6686661a27 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -4528,7 +4528,7 @@ function vim.fn.jobresize(job, width, height) end
--- @return any
function vim.fn.jobsend(...) end
---- Note: Prefer |vim.system()| in Lua.
+--- Note: Prefer |vim.system()| in Lua (unless using the `pty` option).
---
--- Spawns {cmd} as a job.
--- If {cmd} is a List it runs directly (no 'shell').
@@ -9192,6 +9192,7 @@ function vim.fn.strtrans(string) end
--- echo strutf16len('😊') " returns 2
--- echo strutf16len('ą́') " returns 1
--- echo strutf16len('ą́', v:true) " returns 3
+--- <
---
--- @param string string
--- @param countcc? 0|1
diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua
index 6a3413b597..b83a8dd4b1 100644
--- a/runtime/lua/vim/_options.lua
+++ b/runtime/lua/vim/_options.lua
@@ -127,7 +127,7 @@ end
--- @param name string
local function get_options_info(name)
- local info = api.nvim_get_option_info(name)
+ local info = api.nvim_get_option_info2(name, {})
info.metatype = get_option_metatype(name, info)
return info
end
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index d847c28f5c..5ae4e508ef 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -210,6 +210,7 @@ local extension = {
astro = 'astro',
atl = 'atlas',
as = 'atlas',
+ zed = 'authzed',
ahk = 'autohotkey',
au3 = 'autoit',
ave = 'ave',
@@ -592,6 +593,7 @@ local extension = {
ly = 'lilypond',
ily = 'lilypond',
liquid = 'liquid',
+ liq = 'liquidsoap',
cl = 'lisp',
L = 'lisp',
lisp = 'lisp',
diff --git a/runtime/lua/vim/func.lua b/runtime/lua/vim/func.lua
new file mode 100644
index 0000000000..206d1bae95
--- /dev/null
+++ b/runtime/lua/vim/func.lua
@@ -0,0 +1,41 @@
+local M = {}
+
+-- TODO(lewis6991): Private for now until:
+-- - There are other places in the codebase that could benefit from this
+-- (e.g. LSP), but might require other changes to accommodate.
+-- - Invalidation of the cache needs to be controllable. Using weak tables
+-- is an acceptable invalidation policy, but it shouldn't be the only
+-- one.
+-- - I don't think the story around `hash` is completely thought out. We
+-- may be able to have a good default hash by hashing each argument,
+-- so basically a better 'concat'.
+-- - Need to support multi level caches. Can be done by allow `hash` to
+-- return multiple values.
+--
+--- Memoizes a function {fn} using {hash} to hash the arguments.
+---
+--- Internally uses a |lua-weaktable| to cache the results of {fn} meaning the
+--- cache will be invalidated whenever Lua does garbage collection.
+---
+--- The memoized function returns shared references so be wary about
+--- mutating return values.
+---
+--- @generic F: function
+--- @param hash integer|string|function Hash function to create a hash to use as a key to
+--- store results. Possible values:
+--- - When integer, refers to the index of an argument of {fn} to hash.
+--- This argument can have any type.
+--- - When function, is evaluated using the same arguments passed to {fn}.
+--- - When `concat`, the hash is determined by string concatenating all the
+--- arguments passed to {fn}.
+--- - When `concat-n`, the hash is determined by string concatenating the
+--- first n arguments passed to {fn}.
+---
+--- @param fn F Function to memoize.
+--- @return F # Memoized version of {fn}
+--- @nodoc
+function M._memoize(hash, fn)
+ return require('vim.func._memoize')(hash, fn)
+end
+
+return M
diff --git a/runtime/lua/vim/func/_memoize.lua b/runtime/lua/vim/func/_memoize.lua
new file mode 100644
index 0000000000..835bf64c93
--- /dev/null
+++ b/runtime/lua/vim/func/_memoize.lua
@@ -0,0 +1,59 @@
+--- Module for private utility functions
+
+--- @param argc integer?
+--- @return fun(...): any
+local function concat_hash(argc)
+ return function(...)
+ return table.concat({ ... }, '%%', 1, argc)
+ end
+end
+
+--- @param idx integer
+--- @return fun(...): any
+local function idx_hash(idx)
+ return function(...)
+ return select(idx, ...)
+ end
+end
+
+--- @param hash integer|string|fun(...): any
+--- @return fun(...): any
+local function resolve_hash(hash)
+ if type(hash) == 'number' then
+ hash = idx_hash(hash)
+ elseif type(hash) == 'string' then
+ local c = hash == 'concat' or hash:match('^concat%-(%d+)')
+ if c then
+ hash = concat_hash(tonumber(c))
+ else
+ error('invalid value for hash: ' .. hash)
+ end
+ end
+ --- @cast hash -integer
+ return hash
+end
+
+--- @generic F: function
+--- @param hash integer|string|fun(...): any
+--- @param fn F
+--- @return F
+return function(hash, fn)
+ vim.validate({
+ hash = { hash, { 'number', 'string', 'function' } },
+ fn = { fn, 'function' },
+ })
+
+ ---@type table<any,table<any,any>>
+ local cache = setmetatable({}, { __mode = 'kv' })
+
+ hash = resolve_hash(hash)
+
+ return function(...)
+ local key = hash(...)
+ if cache[key] == nil then
+ cache[key] = vim.F.pack_len(fn(...))
+ end
+
+ return vim.F.unpack_len(cache[key])
+ end
+end
diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua
index df593be097..bdea95f9ab 100644
--- a/runtime/lua/vim/keymap.lua
+++ b/runtime/lua/vim/keymap.lua
@@ -28,7 +28,7 @@ local keymap = {}
--- - "replace_keycodes" defaults to `true` if "expr" is `true`.
--- - "noremap": inverse of "remap" (see below).
--- - Also accepts:
---- - "buffer": (number|boolean) Creates buffer-local mapping, `0` or `true`
+--- - "buffer": (integer|boolean) Creates buffer-local mapping, `0` or `true`
--- for current buffer.
--- - "remap": (boolean) Make the mapping recursive. Inverse of "noremap".
--- Defaults to `false`.
@@ -44,7 +44,9 @@ function keymap.set(mode, lhs, rhs, opts)
opts = { opts, 't', true },
})
- opts = vim.deepcopy(opts) or {}
+ opts = vim.deepcopy(opts or {})
+
+ ---@cast mode string[]
mode = type(mode) == 'string' and { mode } or mode
if opts.expr and opts.replace_keycodes ~= false then
@@ -57,7 +59,7 @@ function keymap.set(mode, lhs, rhs, opts)
else
-- remaps behavior is opposite of noremap option.
opts.noremap = not opts.remap
- opts.remap = nil
+ opts.remap = nil ---@type boolean?
end
if type(rhs) == 'function' then
@@ -66,8 +68,8 @@ function keymap.set(mode, lhs, rhs, opts)
end
if opts.buffer then
- local bufnr = opts.buffer == true and 0 or opts.buffer
- opts.buffer = nil
+ local bufnr = opts.buffer == true and 0 or opts.buffer --[[@as integer]]
+ opts.buffer = nil ---@type integer?
for _, m in ipairs(mode) do
vim.api.nvim_buf_set_keymap(bufnr, m, lhs, rhs, opts)
end
@@ -89,7 +91,7 @@ end
--- ```
---
---@param opts table|nil A table of optional arguments:
---- - "buffer": (number|boolean) Remove a mapping from the given buffer.
+--- - "buffer": (integer|boolean) Remove a mapping from the given buffer.
--- When `0` or `true`, use the current buffer.
---@see |vim.keymap.set()|
---
@@ -103,9 +105,9 @@ function keymap.del(modes, lhs, opts)
opts = opts or {}
modes = type(modes) == 'string' and { modes } or modes
- local buffer = false
+ local buffer = false ---@type false|integer
if opts.buffer ~= nil then
- buffer = opts.buffer == true and 0 or opts.buffer
+ buffer = opts.buffer == true and 0 or opts.buffer --[[@as integer]]
end
if buffer == false then
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index 384d09ee48..9cccaa1d66 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -8,6 +8,7 @@ local M = {}
--- to throttle refreshes to at most one at a time
local active_refreshes = {}
+---@type table<integer, table<integer, lsp.CodeLens[]>>
--- bufnr -> client_id -> lenses
local lens_cache_by_buf = setmetatable({}, {
__index = function(t, b)
@@ -16,6 +17,8 @@ local lens_cache_by_buf = setmetatable({}, {
end,
})
+---@type table<integer, integer>
+---client_id -> namespace
local namespaces = setmetatable({}, {
__index = function(t, key)
local value = api.nvim_create_namespace('vim_lsp_codelens:' .. key)
@@ -27,6 +30,18 @@ local namespaces = setmetatable({}, {
---@private
M.__namespaces = namespaces
+local augroup = api.nvim_create_augroup('vim_lsp_codelens', {})
+
+api.nvim_create_autocmd('LspDetach', {
+ group = augroup,
+ callback = function(ev)
+ M.clear(ev.data.client_id, ev.buf)
+ end,
+})
+
+---@param lens lsp.CodeLens
+---@param bufnr integer
+---@param client_id integer
local function execute_lens(lens, bufnr, client_id)
local line = lens.range.start.line
api.nvim_buf_clear_namespace(bufnr, namespaces[client_id], line, line + 1)
@@ -42,7 +57,7 @@ end
--- Return all lenses for the given buffer
---
---@param bufnr integer Buffer number. 0 can be used for the current buffer.
----@return table (`CodeLens[]`)
+---@return lsp.CodeLens[]
function M.get(bufnr)
local lenses_by_client = lens_cache_by_buf[bufnr or 0]
if not lenses_by_client then
@@ -98,12 +113,17 @@ end
---@param client_id integer|nil filter by client_id. All clients if nil
---@param bufnr integer|nil filter by buffer. All buffers if nil
function M.clear(client_id, bufnr)
- local buffers = bufnr and { resolve_bufnr(bufnr) } or vim.tbl_keys(lens_cache_by_buf)
+ bufnr = bufnr and resolve_bufnr(bufnr)
+ local buffers = bufnr and { bufnr }
+ or vim.tbl_filter(api.nvim_buf_is_loaded, api.nvim_list_bufs())
for _, iter_bufnr in pairs(buffers) do
local client_ids = client_id and { client_id } or vim.tbl_keys(namespaces)
for _, iter_client_id in pairs(client_ids) do
local ns = namespaces[iter_client_id]
- lens_cache_by_buf[iter_bufnr][iter_client_id] = {}
+ -- there can be display()ed lenses, which are not stored in cache
+ if lens_cache_by_buf[iter_bufnr] then
+ lens_cache_by_buf[iter_bufnr][iter_client_id] = {}
+ end
api.nvim_buf_clear_namespace(iter_bufnr, ns, 0, -1)
end
end
@@ -111,7 +131,7 @@ end
--- Display the lenses using virtual text
---
----@param lenses table of lenses to display (`CodeLens[] | null`)
+---@param lenses? lsp.CodeLens[] lenses to display
---@param bufnr integer
---@param client_id integer
function M.display(lenses, bufnr, client_id)
@@ -124,7 +144,8 @@ function M.display(lenses, bufnr, client_id)
api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
return
end
- local lenses_by_lnum = {}
+
+ local lenses_by_lnum = {} ---@type table<integer, lsp.CodeLens[]>
for _, lens in pairs(lenses) do
local line_lenses = lenses_by_lnum[lens.range.start.line]
if not line_lenses then
@@ -160,7 +181,7 @@ end
--- Store lenses for a specific buffer and client
---
----@param lenses table of lenses to store (`CodeLens[] | null`)
+---@param lenses? lsp.CodeLens[] lenses to store
---@param bufnr integer
---@param client_id integer
function M.save(lenses, bufnr, client_id)
@@ -174,7 +195,7 @@ function M.save(lenses, bufnr, client_id)
lens_cache_by_buf[bufnr] = lenses_by_client
local ns = namespaces[client_id]
api.nvim_buf_attach(bufnr, false, {
- on_detach = function(b)
+ on_detach = function(_, b)
lens_cache_by_buf[b] = nil
end,
on_lines = function(_, b, _, first_lnum, last_lnum)
@@ -185,6 +206,10 @@ function M.save(lenses, bufnr, client_id)
lenses_by_client[client_id] = lenses
end
+---@param lenses? lsp.CodeLens[]
+---@param bufnr integer
+---@param client_id integer
+---@param callback fun()
local function resolve_lenses(lenses, bufnr, client_id, callback)
lenses = lenses or {}
local num_lens = vim.tbl_count(lenses)
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 4ea3dde81c..d43d9a7cfa 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -371,15 +371,21 @@ function M.hover(_, result, ctx, config)
end
return
end
- local markdown_lines = util.convert_input_to_markdown_lines(result.contents)
- markdown_lines = util.trim_empty_lines(markdown_lines)
- if vim.tbl_isempty(markdown_lines) then
+ local format = 'markdown'
+ local contents ---@type string[]
+ if type(result.contents) == 'table' and result.contents.kind == 'plaintext' then
+ format = 'plaintext'
+ contents = vim.split(result.contents.value or '', '\n', { trimempty = true })
+ else
+ contents = util.convert_input_to_markdown_lines(result.contents)
+ end
+ if vim.tbl_isempty(contents) then
if config.silent ~= true then
vim.notify('No information available')
end
return
end
- return util.open_floating_preview(markdown_lines, 'markdown', config)
+ return util.open_floating_preview(contents, format, config)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
@@ -470,7 +476,6 @@ function M.signature_help(_, result, ctx, config)
vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters')
local ft = vim.bo[ctx.bufnr].filetype
local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers)
- lines = util.trim_empty_lines(lines)
if vim.tbl_isempty(lines) then
if config.silent ~= true then
print('No signature help available')
diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua
index 023b1c26be..fe06006108 100644
--- a/runtime/lua/vim/lsp/health.lua
+++ b/runtime/lua/vim/lsp/health.lua
@@ -32,8 +32,15 @@ function M.check()
vim.health.start('vim.lsp: Active Clients')
if next(clients) then
for _, client in pairs(clients) do
+ local attached_to = table.concat(vim.tbl_keys(client.attached_buffers or {}), ',')
report_info(
- string.format('%s (id=%s, root_dir=%s)', client.name, client.id, client.config.root_dir)
+ string.format(
+ '%s (id=%s, root_dir=%s, attached_to=[%s])',
+ client.name,
+ client.id,
+ vim.fn.fnamemodify(client.config.root_dir, ':~'),
+ attached_to
+ )
)
end
else
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 54721865b7..0d1e3cc0d1 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -102,7 +102,7 @@ end
local function split_lines(value)
value = string.gsub(value, '\r\n?', '\n')
- return split(value, '\n', { plain = true })
+ return split(value, '\n', { plain = true, trimempty = true })
end
local function create_window_without_focus()
@@ -877,9 +877,12 @@ end
--- window for `textDocument/hover`, for parsing the result of
--- `textDocument/signatureHelp`, and potentially others.
---
+--- Note that if the input is of type `MarkupContent` and its kind is `plaintext`,
+--- then the corresponding value is returned without further modifications.
+---
---@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`)
---@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}.
----@return table {contents} extended with lines of converted markdown.
+---@return string[] extended with lines of converted markdown.
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
function M.convert_input_to_markdown_lines(input, contents)
contents = contents or {}
@@ -887,27 +890,13 @@ function M.convert_input_to_markdown_lines(input, contents)
if type(input) == 'string' then
list_extend(contents, split_lines(input))
else
- assert(type(input) == 'table', 'Expected a table for Hover.contents')
+ assert(type(input) == 'table', 'Expected a table for LSP input')
-- MarkupContent
if input.kind then
- -- The kind can be either plaintext or markdown.
- -- If it's plaintext, then wrap it in a <text></text> block
-
- -- Some servers send input.value as empty, so let's ignore this :(
local value = input.value or ''
-
- if input.kind == 'plaintext' then
- -- wrap this in a <text></text> block so that stylize_markdown
- -- can properly process it as plaintext
- value = string.format('<text>\n%s\n</text>', value)
- end
-
- -- assert(type(value) == 'string')
list_extend(contents, split_lines(value))
-- MarkupString variation 2
elseif input.language then
- -- Some servers send input.value as empty, so let's ignore this :(
- -- assert(type(input.value) == 'string')
table.insert(contents, '```' .. input.language)
list_extend(contents, split_lines(input.value or ''))
table.insert(contents, '```')
@@ -925,7 +914,7 @@ function M.convert_input_to_markdown_lines(input, contents)
return contents
end
---- Converts `textDocument/SignatureHelp` response to markdown lines.
+--- Converts `textDocument/signatureHelp` response to markdown lines.
---
---@param signature_help table Response of `textDocument/SignatureHelp`
---@param ft string|nil filetype that will be use as the `lang` for the label markdown code block
@@ -955,10 +944,10 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers
end
local label = signature.label
if ft then
- -- wrap inside a code block so stylize_markdown can render it properly
+ -- wrap inside a code block for proper rendering
label = ('```%s\n%s\n```'):format(ft, label)
end
- list_extend(contents, split(label, '\n', { plain = true }))
+ list_extend(contents, split(label, '\n', { plain = true, trimempty = true }))
if signature.documentation then
-- if LSP returns plain string, we treat it as plaintext. This avoids
-- special characters like underscore or similar from being interpreted
@@ -1223,7 +1212,7 @@ function M.preview_location(location, opts)
local syntax = vim.bo[bufnr].syntax
if syntax == '' then
-- When no syntax is set, we use filetype as fallback. This might not result
- -- in a valid syntax definition. See also ft detection in stylize_markdown.
+ -- in a valid syntax definition.
-- An empty syntax is more common now with TreeSitter, since TS disables syntax.
syntax = vim.bo[bufnr].filetype
end
@@ -1240,36 +1229,65 @@ local function find_window_by_var(name, value)
end
end
---- Trims empty lines from input and pad top and bottom with empty lines
----
----@param contents table of lines to trim and pad
----@param opts table with optional fields
---- - pad_top number of lines to pad contents at top (default 0)
---- - pad_bottom number of lines to pad contents at bottom (default 0)
----@return table table of trimmed and padded lines
-function M._trim(contents, opts)
- validate({
- contents = { contents, 't' },
- opts = { opts, 't', true },
- })
- opts = opts or {}
- contents = M.trim_empty_lines(contents)
- if opts.pad_top then
- for _ = 1, opts.pad_top do
- table.insert(contents, 1, '')
+---Returns true if the line is empty or only contains whitespace.
+---@param line string
+---@return boolean
+local function is_blank_line(line)
+ return line and line:match('^%s*$')
+end
+
+---Returns true if the line corresponds to a Markdown thematic break.
+---@param line string
+---@return boolean
+local function is_separator_line(line)
+ return line and line:match('^ ? ? ?%-%-%-+%s*$')
+end
+
+---Replaces separator lines by the given divider and removing surrounding blank lines.
+---@param contents string[]
+---@param divider string
+---@return string[]
+local function replace_separators(contents, divider)
+ local trimmed = {}
+ local l = 1
+ while l <= #contents do
+ local line = contents[l]
+ if is_separator_line(line) then
+ if l > 1 and is_blank_line(contents[l - 1]) then
+ table.remove(trimmed)
+ end
+ table.insert(trimmed, divider)
+ if is_blank_line(contents[l + 1]) then
+ l = l + 1
+ end
+ else
+ table.insert(trimmed, line)
end
+ l = l + 1
end
- if opts.pad_bottom then
- for _ = 1, opts.pad_bottom do
- table.insert(contents, '')
+
+ return trimmed
+end
+
+---Collapses successive blank lines in the input table into a single one.
+---@param contents string[]
+---@return string[]
+local function collapse_blank_lines(contents)
+ local collapsed = {}
+ local l = 1
+ while l <= #contents do
+ local line = contents[l]
+ if is_blank_line(line) then
+ while is_blank_line(contents[l + 1]) do
+ l = l + 1
+ end
end
+ table.insert(collapsed, line)
+ l = l + 1
end
- return contents
+ return collapsed
end
---- Generates a table mapping markdown code block lang to vim syntax,
---- based on g:markdown_fenced_languages
----@return table table of lang -> syntax mappings
local function get_markdown_fences()
local fences = {}
for _, fence in pairs(vim.g.markdown_fenced_languages or {}) do
@@ -1297,8 +1315,6 @@ end
--- - wrap_at character to wrap at for computing height
--- - max_width maximal width of floating window
--- - max_height maximal height of floating window
---- - pad_top number of lines to pad contents at top
---- - pad_bottom number of lines to pad contents at bottom
--- - separator insert separator after code block
---@return table stripped content
function M.stylize_markdown(bufnr, contents, opts)
@@ -1335,7 +1351,7 @@ function M.stylize_markdown(bufnr, contents, opts)
end
-- Clean up
- contents = M._trim(contents, opts)
+ contents = vim.split(table.concat(contents, '\n'), '\n', { trimempty = true })
local stripped = {}
local highlights = {}
@@ -1484,6 +1500,45 @@ function M.stylize_markdown(bufnr, contents, opts)
return stripped
end
+--- @class lsp.util.NormalizeMarkdownOptions
+--- @field width integer Thematic breaks are expanded to this size. Defaults to 80.
+
+--- Normalizes Markdown input to a canonical form.
+---
+--- The returned Markdown adheres to the GitHub Flavored Markdown (GFM)
+--- specification.
+---
+--- The following transformations are made:
+---
+--- 1. Carriage returns ('\r') and empty lines at the beginning and end are removed
+--- 2. Successive empty lines are collapsed into a single empty line
+--- 3. Thematic breaks are expanded to the given width
+---
+---@private
+---@param contents string[]
+---@param opts? lsp.util.NormalizeMarkdownOptions
+---@return string[] table of lines containing normalized Markdown
+---@see https://github.github.com/gfm
+function M._normalize_markdown(contents, opts)
+ validate({
+ contents = { contents, 't' },
+ opts = { opts, 't', true },
+ })
+ opts = opts or {}
+
+ -- 1. Carriage returns are removed
+ contents = vim.split(table.concat(contents, '\n'):gsub('\r', ''), '\n', { trimempty = true })
+
+ -- 2. Successive empty lines are collapsed into a single empty line
+ contents = collapse_blank_lines(contents)
+
+ -- 3. Thematic breaks are expanded to the given width
+ local divider = string.rep('─', opts.width or 80)
+ contents = replace_separators(contents, divider)
+
+ return contents
+end
+
--- Closes the preview window
---
---@param winnr integer window id of preview window
@@ -1620,8 +1675,6 @@ end
--- - wrap_at: (integer) character to wrap at for computing height when wrap is enabled
--- - max_width: (integer) maximal width of floating window
--- - max_height: (integer) maximal height of floating window
---- - pad_top: (integer) number of lines to pad contents at top
---- - pad_bottom: (integer) number of lines to pad contents at bottom
--- - focus_id: (string) if a popup with this id is opened, then focus it
--- - close_events: (table) list of events that closes the floating window
--- - focusable: (boolean, default true) Make float focusable
@@ -1629,8 +1682,7 @@ end
--- is also `true`, focus an existing floating window with the same
--- {focus_id}
---@return integer bufnr of newly created float window
----@return integer winid of newly created float window
----preview window
+---@return integer winid of newly created float window preview window
function M.open_floating_preview(contents, syntax, opts)
validate({
contents = { contents, 't' },
@@ -1639,7 +1691,6 @@ function M.open_floating_preview(contents, syntax, opts)
})
opts = opts or {}
opts.wrap = opts.wrap ~= false -- wrapping by default
- opts.stylize_markdown = opts.stylize_markdown ~= false and vim.g.syntax_on ~= nil
opts.focus = opts.focus ~= false
opts.close_events = opts.close_events or { 'CursorMoved', 'CursorMovedI', 'InsertCharPre' }
@@ -1671,16 +1722,21 @@ function M.open_floating_preview(contents, syntax, opts)
api.nvim_win_close(existing_float, true)
end
+ -- Create the buffer
local floating_bufnr = api.nvim_create_buf(false, true)
- local do_stylize = syntax == 'markdown' and opts.stylize_markdown
-
- -- Clean up input: trim empty lines from the end, pad
- contents = M._trim(contents, opts)
+ -- Set up the contents, using treesitter for markdown
+ local do_stylize = syntax == 'markdown' and vim.g.syntax_on ~= nil
if do_stylize then
- -- applies the syntax and sets the lines to the buffer
- contents = M.stylize_markdown(floating_bufnr, contents, opts)
+ local width = M._make_floating_popup_size(contents, opts)
+ contents = M._normalize_markdown(contents, { width = width })
+ vim.bo[floating_bufnr].filetype = 'markdown'
+ vim.treesitter.start(floating_bufnr)
+ api.nvim_buf_set_lines(floating_bufnr, 0, -1, false, contents)
else
+ -- Clean up input: trim empty lines
+ contents = vim.split(table.concat(contents, '\n'), '\n', { trimempty = true })
+
if syntax then
vim.bo[floating_bufnr].syntax = syntax
end
@@ -1697,9 +1753,9 @@ function M.open_floating_preview(contents, syntax, opts)
local float_option = M.make_floating_popup_options(width, height, opts)
local floating_winnr = api.nvim_open_win(floating_bufnr, false, float_option)
+
if do_stylize then
vim.wo[floating_winnr].conceallevel = 2
- vim.wo[floating_winnr].concealcursor = 'n'
end
-- disable folding
vim.wo[floating_winnr].foldenable = false
@@ -1708,6 +1764,7 @@ function M.open_floating_preview(contents, syntax, opts)
vim.bo[floating_bufnr].modifiable = false
vim.bo[floating_bufnr].bufhidden = 'wipe'
+
api.nvim_buf_set_keymap(
floating_bufnr,
'n',
@@ -1908,6 +1965,7 @@ function M.symbols_to_items(symbols, bufnr)
end
--- Removes empty lines from the beginning and end.
+---@deprecated use `vim.split()` with `trimempty` instead
---@param lines table list of lines to trim
---@return table trimmed list of lines
function M.trim_empty_lines(lines)
@@ -2172,6 +2230,35 @@ function M.lookup_section(settings, section)
return settings
end
+--- Converts line range (0-based, end-inclusive) to lsp range,
+--- handles absence of a trailing newline
+---
+---@param bufnr integer
+---@param start_line integer
+---@param end_line integer
+---@param offset_encoding lsp.PositionEncodingKind
+---@return lsp.Range
+local function make_line_range_params(bufnr, start_line, end_line, offset_encoding)
+ local last_line = api.nvim_buf_line_count(bufnr) - 1
+
+ ---@type lsp.Position
+ local end_pos
+
+ if end_line == last_line and not vim.api.nvim_get_option_value('endofline', { buf = bufnr }) then
+ end_pos = {
+ line = end_line,
+ character = M.character_offset(bufnr, end_line, #get_line(bufnr, end_line), offset_encoding),
+ }
+ else
+ end_pos = { line = end_line + 1, character = 0 }
+ end
+
+ return {
+ start = { line = start_line, character = 0 },
+ ['end'] = end_pos,
+ }
+end
+
---@private
--- Request updated LSP information for a buffer.
---
@@ -2195,6 +2282,8 @@ function M._refresh(method, opts)
return
end
+ local textDocument = M.make_text_document_params(bufnr)
+
local only_visible = opts.only_visible or false
if only_visible then
@@ -2202,28 +2291,25 @@ function M._refresh(method, opts)
if api.nvim_win_get_buf(window) == bufnr then
local first = vim.fn.line('w0', window)
local last = vim.fn.line('w$', window)
- local params = {
- textDocument = M.make_text_document_params(bufnr),
- range = {
- start = { line = first - 1, character = 0 },
- ['end'] = { line = last, character = 0 },
- },
- }
for _, client in ipairs(clients) do
- client.request(method, params, nil, bufnr)
+ client.request(method, {
+ textDocument = textDocument,
+ range = make_line_range_params(bufnr, first - 1, last - 1, client.offset_encoding),
+ }, nil, bufnr)
end
end
end
else
- local params = {
- textDocument = M.make_text_document_params(bufnr),
- range = {
- start = { line = 0, character = 0 },
- ['end'] = { line = api.nvim_buf_line_count(bufnr), character = 0 },
- },
- }
for _, client in ipairs(clients) do
- client.request(method, params, nil, bufnr)
+ client.request(method, {
+ textDocument = textDocument,
+ range = make_line_range_params(
+ bufnr,
+ 0,
+ api.nvim_buf_line_count(bufnr) - 1,
+ client.offset_encoding
+ ),
+ }, nil, bufnr)
end
end
end
diff --git a/runtime/lua/vim/secure.lua b/runtime/lua/vim/secure.lua
index 893b3e1877..d29c356af3 100644
--- a/runtime/lua/vim/secure.lua
+++ b/runtime/lua/vim/secure.lua
@@ -2,9 +2,9 @@ local M = {}
--- Reads trust database from $XDG_STATE_HOME/nvim/trust.
---
----@return (table) Contents of trust database, if it exists. Empty table otherwise.
+---@return table<string, string> Contents of trust database, if it exists. Empty table otherwise.
local function read_trust()
- local trust = {}
+ local trust = {} ---@type table<string, string>
local f = io.open(vim.fn.stdpath('state') .. '/trust', 'r')
if f then
local contents = f:read('*a')
@@ -24,12 +24,12 @@ end
--- Writes provided {trust} table to trust database at
--- $XDG_STATE_HOME/nvim/trust.
---
----@param trust (table) Trust table to write
+---@param trust table<string, string> Trust table to write
local function write_trust(trust)
vim.validate({ trust = { trust, 't' } })
local f = assert(io.open(vim.fn.stdpath('state') .. '/trust', 'w'))
- local t = {}
+ local t = {} ---@type string[]
for p, h in pairs(trust) do
t[#t + 1] = string.format('%s %s\n', h, p)
end
@@ -61,7 +61,7 @@ function M.read(path)
return nil
end
- local contents
+ local contents ---@type string?
do
local f = io.open(fullpath, 'r')
if not f then
@@ -108,6 +108,11 @@ function M.read(path)
return contents
end
+---@class vim.trust.opts
+---@field action string
+---@field path? string
+---@field bufnr? integer
+
--- Manage the trust database.
---
--- The trust database is located at |$XDG_STATE_HOME|/nvim/trust.
@@ -134,6 +139,7 @@ function M.trust(opts)
},
})
+ ---@cast opts vim.trust.opts
local path = opts.path
local bufnr = opts.bufnr
local action = opts.action
@@ -144,7 +150,7 @@ function M.trust(opts)
assert(not path, '"path" is not valid when action is "allow"')
end
- local fullpath
+ local fullpath ---@type string?
if path then
fullpath = vim.uv.fs_realpath(vim.fs.normalize(path))
elseif bufnr then
@@ -165,7 +171,8 @@ function M.trust(opts)
if action == 'allow' then
local newline = vim.bo[bufnr].fileformat == 'unix' and '\n' or '\r\n'
- local contents = table.concat(vim.api.nvim_buf_get_lines(bufnr, 0, -1, false), newline)
+ local contents =
+ table.concat(vim.api.nvim_buf_get_lines(bufnr --[[@as integer]], 0, -1, false), newline)
if vim.bo[bufnr].endofline then
contents = contents .. newline
end
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 0c38fa955a..9542d93789 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -534,12 +534,12 @@ function vim.tbl_flatten(t)
return result
end
---- Enumerate a table sorted by its keys.
+--- Enumerates key-value pairs of a table, ordered by key.
---
---@see Based on https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
---@param t table Dict-like table
----@return function iterator over sorted keys and their values
+---@return function # |for-in| iterator over sorted keys and their values
function vim.spairs(t)
assert(type(t) == 'table', string.format('Expected table, got %s', type(t)))
@@ -551,7 +551,6 @@ function vim.spairs(t)
table.sort(keys)
-- Return the iterator function.
- -- TODO(justinmk): Return "iterator function, table {t}, and nil", like pairs()?
local i = 0
return function()
i = i + 1
@@ -561,11 +560,14 @@ function vim.spairs(t)
end
end
---- Tests if a Lua table can be treated as an array (a table indexed by integers).
+--- Tests if `t` is an "array": a table indexed _only_ by integers (potentially non-contiguous).
---
---- Empty table `{}` is assumed to be an array, unless it was created by
---- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result,
---- for example from |rpcrequest()| or |vim.fn|.
+--- If the indexes start from 1 and are contiguous then the array is also a list. |vim.tbl_islist()|
+---
+--- Empty table `{}` is an array, unless it was created by |vim.empty_dict()| or returned as
+--- a dict-like |API| or Vimscript result, for example from |rpcrequest()| or |vim.fn|.
+---
+---@see https://github.com/openresty/luajit2#tableisarray
---
---@param t table
---@return boolean `true` if array-like table, else `false`.
@@ -597,11 +599,13 @@ function vim.tbl_isarray(t)
end
end
---- Tests if a Lua table can be treated as a list (a table indexed by consecutive integers starting from 1).
+--- Tests if `t` is a "list": a table indexed _only_ by contiguous integers starting from 1 (what
+--- |lua-length| calls a "regular array").
+---
+--- Empty table `{}` is a list, unless it was created by |vim.empty_dict()| or returned as
+--- a dict-like |API| or Vimscript result, for example from |rpcrequest()| or |vim.fn|.
---
---- Empty table `{}` is assumed to be an list, unless it was created by
---- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result,
---- for example from |rpcrequest()| or |vim.fn|.
+---@see |vim.tbl_isarray()|
---
---@param t table
---@return boolean `true` if list-like table, else `false`.
@@ -705,61 +709,6 @@ function vim.endswith(s, suffix)
return #suffix == 0 or s:sub(-#suffix) == suffix
end
---- Validates a parameter specification (types and values).
----
---- Usage example:
----
---- ```lua
---- function user.new(name, age, hobbies)
---- vim.validate{
---- name={name, 'string'},
---- age={age, 'number'},
---- hobbies={hobbies, 'table'},
---- }
---- ...
---- end
---- ```
----
---- Examples with explicit argument values (can be run directly):
----
---- ```lua
---- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
---- --> NOP (success)
----
---- vim.validate{arg1={1, 'table'}}
---- --> error('arg1: expected table, got number')
----
---- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
---- --> error('arg1: expected even number, got 3')
---- ```
----
---- If multiple types are valid they can be given as a list.
----
---- ```lua
---- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}}
---- -- NOP (success)
----
---- vim.validate{arg1={1, {'string', 'table'}}}
---- -- error('arg1: expected string|table, got number')
----
---- ```
----
----@param opt table Names of parameters to validate. Each key is a parameter
---- name; each value is a tuple in one of these forms:
---- 1. (arg_value, type_name, optional)
---- - arg_value: argument value
---- - type_name: string|table type name, one of: ("table", "t", "string",
---- "s", "number", "n", "boolean", "b", "function", "f", "nil",
---- "thread", "userdata") or list of them.
---- - optional: (optional) boolean, if true, `nil` is valid
---- 2. (arg_value, fn, msg)
---- - arg_value: argument value
---- - fn: any function accepting one argument, returns true if and
---- only if the argument is valid. Can optionally return an additional
---- informative error message as the second returned value.
---- - msg: (optional) error string if validation fails
-function vim.validate(opt) end -- luacheck: no unused
-
do
local type_names = {
['table'] = 'table',
@@ -844,6 +793,59 @@ do
return true, nil
end
+ --- Validates a parameter specification (types and values).
+ ---
+ --- Usage example:
+ ---
+ --- ```lua
+ --- function user.new(name, age, hobbies)
+ --- vim.validate{
+ --- name={name, 'string'},
+ --- age={age, 'number'},
+ --- hobbies={hobbies, 'table'},
+ --- }
+ --- ...
+ --- end
+ --- ```
+ ---
+ --- Examples with explicit argument values (can be run directly):
+ ---
+ --- ```lua
+ --- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
+ --- --> NOP (success)
+ ---
+ --- vim.validate{arg1={1, 'table'}}
+ --- --> error('arg1: expected table, got number')
+ ---
+ --- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
+ --- --> error('arg1: expected even number, got 3')
+ --- ```
+ ---
+ --- If multiple types are valid they can be given as a list.
+ ---
+ --- ```lua
+ --- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}}
+ --- -- NOP (success)
+ ---
+ --- vim.validate{arg1={1, {'string', 'table'}}}
+ --- -- error('arg1: expected string|table, got number')
+ ---
+ --- ```
+ ---
+ ---@param opt table Names of parameters to validate. Each key is a parameter
+ --- name; each value is a tuple in one of these forms:
+ --- 1. (arg_value, type_name, optional)
+ --- - arg_value: argument value
+ --- - type_name: string|table type name, one of: ("table", "t", "string",
+ --- "s", "number", "n", "boolean", "b", "function", "f", "nil",
+ --- "thread", "userdata") or list of them.
+ --- - optional: (optional) boolean, if true, `nil` is valid
+ --- 2. (arg_value, fn, msg)
+ --- - arg_value: argument value
+ --- - fn: any function accepting one argument, returns true if and
+ --- only if the argument is valid. Can optionally return an additional
+ --- informative error message as the second returned value.
+ --- - msg: (optional) error string if validation fails
function vim.validate(opt)
local ok, err_msg = is_valid(opt)
if not ok then
@@ -866,28 +868,25 @@ function vim.is_callable(f)
return type(m.__call) == 'function'
end
---- Creates a table whose members are automatically created when accessed, if they don't already
---- exist.
----
---- They mimic defaultdict in python.
+--- Creates a table whose missing keys are provided by {createfn} (like Python's "defaultdict").
---
---- If {create} is `nil`, this will create a defaulttable whose constructor function is
---- this function, effectively allowing to create nested tables on the fly:
+--- If {createfn} is `nil` it defaults to defaulttable() itself, so accessing nested keys creates
+--- nested tables:
---
--- ```lua
--- local a = vim.defaulttable()
--- a.b.c = 1
--- ```
---
----@param create function?(key:any):any The function called to create a missing value.
----@return table Empty table with metamethod
-function vim.defaulttable(create)
- create = create or function(_)
+---@param createfn function?(key:any):any Provides the value for a missing `key`.
+---@return table # Empty table with `__index` metamethod.
+function vim.defaulttable(createfn)
+ createfn = createfn or function(_)
return vim.defaulttable()
end
return setmetatable({}, {
__index = function(tbl, key)
- rawset(tbl, key, create(key))
+ rawset(tbl, key, createfn(key))
return rawget(tbl, key)
end,
})
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index cc8be72670..0e34cbcbcc 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -127,6 +127,7 @@ function M.get_parser(bufnr, lang, opts)
)
end
elseif parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then
+ assert(lang, 'lang should be valid')
parsers[bufnr] = M._create_parser(bufnr, lang, opts)
end
@@ -162,7 +163,7 @@ function M.is_ancestor(dest, source)
return false
end
- local current = source
+ local current = source ---@type TSNode?
while current ~= nil do
if current == dest then
return true
@@ -491,7 +492,7 @@ end
--- function, it accepts the buffer number of the source buffer as its only
--- argument and should return a string.
function M.inspect_tree(opts)
- ---@cast opts InspectTreeOpts
+ ---@diagnostic disable-next-line: invisible
require('vim.treesitter.dev').inspect_tree(opts)
end
diff --git a/runtime/lua/vim/treesitter/_meta.lua b/runtime/lua/vim/treesitter/_meta.lua
index 9a94f12c16..d01b7be3b0 100644
--- a/runtime/lua/vim/treesitter/_meta.lua
+++ b/runtime/lua/vim/treesitter/_meta.lua
@@ -50,7 +50,8 @@ function TSNode:_rawquery(query, captures, start, end_, opts) end
---@alias TSLoggerCallback fun(logtype: 'parse'|'lex', msg: string)
---@class TSParser
----@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: boolean?): TSTree, integer[]
+---@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: true): TSTree, Range6[]
+---@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: false|nil): TSTree, Range4[]
---@field reset fun(self: TSParser)
---@field included_ranges fun(self: TSParser, include_bytes: boolean?): integer[]
---@field set_included_ranges fun(self: TSParser, ranges: (Range6|TSNode)[])
diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua
index abf0bf345d..87d74789a3 100644
--- a/runtime/lua/vim/treesitter/_query_linter.lua
+++ b/runtime/lua/vim/treesitter/_query_linter.lua
@@ -10,20 +10,12 @@ local M = {}
--- @alias vim.treesitter.ParseError {msg: string, range: Range4}
---- @private
---- Caches parse results for queries for each language.
---- Entries of parse_cache[lang][query_text] will either be true for successful parse or contain the
---- message and range of the parse error.
---- @type table<string,table<string,vim.treesitter.ParseError|true>>
-local parse_cache = {}
-
--- Contains language dependent context for the query linter
--- @class QueryLinterLanguageContext
--- @field lang string? Current `lang` of the targeted parser
--- @field parser_info table? Parser info returned by vim.treesitter.language.inspect
--- @field is_first_lang boolean Whether this is the first language of a linter run checking queries for multiple `langs`
---- @private
--- Adds a diagnostic for node in the query buffer
--- @param diagnostics Diagnostic[]
--- @param range Range4
@@ -42,7 +34,6 @@ local function add_lint_for_node(diagnostics, range, lint, lang)
}
end
---- @private
--- Determines the target language of a query file by its path: <lang>/<query_type>.scm
--- @param buf integer
--- @return string?
@@ -53,7 +44,6 @@ local function guess_query_lang(buf)
end
end
---- @private
--- @param buf integer
--- @param opts QueryLinterOpts|QueryLinterNormalizedOpts|nil
--- @return QueryLinterNormalizedOpts
@@ -87,7 +77,6 @@ local lint_query = [[;; query
(ERROR) @error
]]
---- @private
--- @param err string
--- @param node TSNode
--- @return vim.treesitter.ParseError
@@ -112,38 +101,26 @@ local function get_error_entry(err, node)
}
end
---- @private
--- @param node TSNode
--- @param buf integer
--- @param lang string
---- @param diagnostics Diagnostic[]
-local function check_toplevel(node, buf, lang, diagnostics)
- local query_text = vim.treesitter.get_node_text(node, buf)
-
- if not parse_cache[lang] then
- parse_cache[lang] = {}
- end
-
- local lang_cache = parse_cache[lang]
-
- if lang_cache[query_text] == nil then
- local cache_val, err = pcall(vim.treesitter.query.parse, lang, query_text) ---@type boolean|vim.treesitter.ParseError, string|Query
-
- if not cache_val and type(err) == 'string' then
- cache_val = get_error_entry(err, node)
- end
-
- lang_cache[query_text] = cache_val
- end
+local function hash_parse(node, buf, lang)
+ return tostring(node:id()) .. tostring(buf) .. tostring(vim.b[buf].changedtick) .. lang
+end
- local cache_entry = lang_cache[query_text]
+--- @param node TSNode
+--- @param buf integer
+--- @param lang string
+--- @return vim.treesitter.ParseError?
+local parse = vim.func._memoize(hash_parse, function(node, buf, lang)
+ local query_text = vim.treesitter.get_node_text(node, buf)
+ local ok, err = pcall(vim.treesitter.query.parse, lang, query_text) ---@type boolean|vim.treesitter.ParseError, string|Query
- if type(cache_entry) ~= 'boolean' then
- add_lint_for_node(diagnostics, cache_entry.range, cache_entry.msg, lang)
+ if not ok and type(err) == 'string' then
+ return get_error_entry(err, node)
end
-end
+end)
---- @private
--- @param buf integer
--- @param match table<integer,TSNode>
--- @param query Query
@@ -164,7 +141,10 @@ local function lint_match(buf, match, query, lang_context, diagnostics)
-- other checks rely on Neovim parser introspection
if lang and parser_info and cap_id == 'toplevel' then
- check_toplevel(node, buf, lang, diagnostics)
+ local err = parse(node, buf, lang)
+ if err then
+ add_lint_for_node(diagnostics, err.range, err.msg, lang)
+ end
end
end
end
diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua
index 7f24ba8590..db30d638af 100644
--- a/runtime/lua/vim/treesitter/dev.lua
+++ b/runtime/lua/vim/treesitter/dev.lua
@@ -258,7 +258,7 @@ end
--- @private
---
---- @param opts InspectTreeOpts
+--- @param opts InspectTreeOpts?
function M.inspect_tree(opts)
vim.validate({
opts = { opts, 't', true },
@@ -597,8 +597,9 @@ function M.edit_query(lang)
})
api.nvim_buf_set_lines(query_buf, 0, -1, false, {
- ';; Write your query here. Use @captures to highlight matches in the source buffer.',
- ';; Completion for grammar nodes is available (see :h compl-omni)',
+ ';; Write queries here (see $VIMRUNTIME/queries/ for examples).',
+ ';; Move cursor to a capture ("@foo") to highlight matches in the source buffer.',
+ ';; Completion for grammar nodes is available (:help compl-omni)',
'',
'',
})
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index b555ee231b..670f2797b7 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -78,13 +78,14 @@ local TSCallbackNames = {
---@field private _opts table Options
---@field private _parser TSParser Parser for language
---@field private _has_regions boolean
----@field private _regions Range6[][]?
+---@field private _regions table<integer, Range6[]>?
---List of regions this tree should manage and parse. If nil then regions are
---taken from _trees. This is mostly a short-lived cache for included_regions()
---@field private _lang string Language name
---@field private _parent_lang? string Parent language name
---@field private _source (integer|string) Buffer or string to parse
----@field private _trees TSTree[] Reference to parsed tree (one for each language)
+---@field private _trees table<integer, TSTree> Reference to parsed tree (one for each language).
+---Each key is the index of region, which is synced with _regions and _valid.
---@field private _valid boolean|table<integer,boolean> If the parsed tree is valid
---@field private _logger? fun(logtype: string, msg: string)
---@field private _logfile? file*
@@ -211,7 +212,7 @@ function LanguageTree:_log(...)
end
local info = debug.getinfo(2, 'nl')
- local nregions = #self:included_regions()
+ local nregions = vim.tbl_count(self:included_regions())
local prefix =
string.format('%s:%d: (#regions=%d) ', info.name or '???', info.currentline or 0, nregions)
@@ -244,8 +245,13 @@ function LanguageTree:invalidate(reload)
end
end
---- Returns all trees this language tree contains.
+--- Returns all trees of the regions parsed by this parser.
--- Does not include child languages.
+--- The result is list-like if
+--- * this LanguageTree is the root, in which case the result is empty or a singleton list; or
+--- * the root LanguageTree is fully parsed.
+---
+---@return table<integer, TSTree>
function LanguageTree:trees()
return self._trees
end
@@ -255,16 +261,15 @@ function LanguageTree:lang()
return self._lang
end
---- Determines whether this tree is valid.
---- If the tree is invalid, call `parse()`.
---- This will return the updated tree.
----@param exclude_children boolean|nil
+--- Returns whether this LanguageTree is valid, i.e., |LanguageTree:trees()| reflects the latest
+--- state of the source. If invalid, user should call |LanguageTree:parse()|.
+---@param exclude_children boolean|nil whether to ignore the validity of children (default `false`)
---@return boolean
function LanguageTree:is_valid(exclude_children)
local valid = self._valid
if type(valid) == 'table' then
- for i = 1, #self:included_regions() do
+ for i, _ in pairs(self:included_regions()) do
if not valid[i] then
return false
end
@@ -328,7 +333,7 @@ end
--- @private
--- @param range boolean|Range?
---- @return integer[] changes
+--- @return Range6[] changes
--- @return integer no_regions_parsed
--- @return number total_parse_time
function LanguageTree:_parse_regions(range)
@@ -370,7 +375,7 @@ function LanguageTree:_add_injections()
local seen_langs = {} ---@type table<string,boolean>
local query_time, injections_by_lang = tcall(self._get_injections, self)
- for lang, injection_ranges in pairs(injections_by_lang) do
+ for lang, injection_regions in pairs(injections_by_lang) do
local has_lang = pcall(language.add, lang)
-- Child language trees should just be ignored if not found, since
@@ -383,7 +388,7 @@ function LanguageTree:_add_injections()
child = self:add_child(lang)
end
- child:set_included_regions(injection_ranges)
+ child:set_included_regions(injection_regions)
seen_langs[lang] = true
end
end
@@ -408,14 +413,14 @@ end
--- Set to `true` to run a complete parse of the source (Note: Can be slow!)
--- Set to `false|nil` to only parse regions with empty ranges (typically
--- only the root tree without injections).
---- @return TSTree[]
+--- @return table<integer, TSTree>
function LanguageTree:parse(range)
if self:is_valid() then
self:_log('valid')
return self._trees
end
- local changes --- @type Range6?
+ local changes --- @type Range6[]?
-- Collect some stats
local no_regions_parsed = 0
@@ -565,7 +570,7 @@ function LanguageTree:_iter_regions(fn)
local all_valid = true
- for i, region in ipairs(self:included_regions()) do
+ for i, region in pairs(self:included_regions()) do
if was_valid or self._valid[i] then
self._valid[i] = fn(i, region)
if not self._valid[i] then
@@ -601,7 +606,7 @@ end
--- nodes, which is useful for templating languages like ERB and EJS.
---
---@private
----@param new_regions Range6[][] List of regions this tree should manage and parse.
+---@param new_regions (Range4|Range6|TSNode)[][] List of regions this tree should manage and parse.
function LanguageTree:set_included_regions(new_regions)
self._has_regions = true
@@ -609,16 +614,20 @@ function LanguageTree:set_included_regions(new_regions)
for _, region in ipairs(new_regions) do
for i, range in ipairs(region) do
if type(range) == 'table' and #range == 4 then
- region[i] = Range.add_bytes(self._source, range)
+ region[i] = Range.add_bytes(self._source, range --[[@as Range4]])
elseif type(range) == 'userdata' then
region[i] = { range:range(true) }
end
end
end
+ -- included_regions is not guaranteed to be list-like, but this is still sound, i.e. if
+ -- new_regions is different from included_regions, then outdated regions in included_regions are
+ -- invalidated. For example, if included_regions = new_regions ++ hole ++ outdated_regions, then
+ -- outdated_regions is invalidated by _iter_regions in else branch.
if #self:included_regions() ~= #new_regions then
-- TODO(lewis6991): inefficient; invalidate trees incrementally
- for _, t in ipairs(self._trees) do
+ for _, t in pairs(self._trees) do
self:_do_callback('changedtree', t:included_ranges(true), t)
end
self._trees = {}
@@ -632,20 +641,22 @@ function LanguageTree:set_included_regions(new_regions)
self._regions = new_regions
end
----Gets the set of included regions
----@return Range6[][]
+---Gets the set of included regions managed by this LanguageTree. This can be different from the
+---regions set by injection query, because a partial |LanguageTree:parse()| drops the regions
+---outside the requested range.
+---@return table<integer, Range6[]>
function LanguageTree:included_regions()
if self._regions then
return self._regions
end
- if not self._has_regions or #self._trees == 0 then
- -- treesitter.c will default empty ranges to { -1, -1, -1, -1, -1, -1}
+ if not self._has_regions then
+ -- treesitter.c will default empty ranges to { -1, -1, -1, -1, -1, -1} (the full range)
return { {} }
end
local regions = {} ---@type Range6[][]
- for i, _ in ipairs(self._trees) do
+ for i, _ in pairs(self._trees) do
regions[i] = self._trees[i]:included_ranges(true)
end
@@ -727,12 +738,14 @@ local function add_injection(t, tree_index, pattern, lang, combined, ranges)
end
-- TODO(clason): replace by refactored `ts.has_parser` API (without registering)
----@param lang string parser name
----@return boolean # true if parser for {lang} exists on rtp
-local has_parser = function(lang)
+--- The result of this function is cached to prevent nvim_get_runtime_file from being
+--- called too often
+--- @param lang string parser name
+--- @return boolean # true if parser for {lang} exists on rtp
+local has_parser = vim.func._memoize(1, function(lang)
return vim._ts_has_language(lang)
or #vim.api.nvim_get_runtime_file('parser/' .. lang .. '.*', false) > 0
-end
+end)
--- Return parser name for language (if exists) or filetype (if registered and exists).
--- Also attempts with the input lower-cased.
@@ -801,7 +814,7 @@ local function combine_regions(regions)
return result
end
---- Gets language injection points by language.
+--- Gets language injection regions by language.
---
--- This is where most of the injection processing occurs.
---
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 44ed37d64e..8cbbffcd60 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -191,12 +191,6 @@ function M.set(lang, query_name, text)
explicit_queries[lang][query_name] = M.parse(lang, text)
end
---- `false` if query files didn't exist or were empty
----@type table<string, table<string, Query|false>>
-local query_get_cache = vim.defaulttable(function()
- return setmetatable({}, { __mode = 'v' })
-end)
-
---@deprecated
function M.get_query(...)
vim.deprecate('vim.treesitter.query.get_query()', 'vim.treesitter.query.get()', '0.10')
@@ -209,34 +203,19 @@ end
---@param query_name string Name of the query (e.g. "highlights")
---
---@return Query|nil Parsed query
-function M.get(lang, query_name)
+M.get = vim.func._memoize('concat-2', function(lang, query_name)
if explicit_queries[lang][query_name] then
return explicit_queries[lang][query_name]
end
- local cached = query_get_cache[lang][query_name]
- if cached then
- return cached
- elseif cached == false then
- return nil
- end
-
local query_files = M.get_files(lang, query_name)
local query_string = read_query_files(query_files)
if #query_string == 0 then
- query_get_cache[lang][query_name] = false
return nil
end
- local query = M.parse(lang, query_string)
- query_get_cache[lang][query_name] = query
- return query
-end
-
----@type table<string, table<string, Query>>
-local query_parse_cache = vim.defaulttable(function()
- return setmetatable({}, { __mode = 'v' })
+ return M.parse(lang, query_string)
end)
---@deprecated
@@ -262,20 +241,15 @@ end
---@param query string Query in s-expr syntax
---
---@return Query Parsed query
-function M.parse(lang, query)
+M.parse = vim.func._memoize('concat-2', function(lang, query)
language.add(lang)
- local cached = query_parse_cache[lang][query]
- if cached then
- return cached
- end
local self = setmetatable({}, Query)
self.query = vim._ts_parse_query(lang, query)
self.info = self.query:inspect()
self.captures = self.info.captures
- query_parse_cache[lang][query] = self
return self
-end
+end)
---@deprecated
function M.get_range(...)
@@ -843,11 +817,13 @@ function M.omnifunc(findstart, base)
return require('vim.treesitter._query_linter').omnifunc(findstart, base)
end
---- Open a window for live editing of a treesitter query.
+--- Opens a live editor to query the buffer you started from.
---
---- Can also be shown with `:EditQuery`. *:EditQuery*
+--- Can also be shown with *:EditQuery*.
---
---- Note that the editor opens a scratch buffer, and so queries aren't persisted on disk.
+--- If you move the cursor to a capture name ("@foo"), text matching the capture is highlighted in
+--- the source buffer. The query editor is a scratch buffer, use `:write` to save it. You can find
+--- example queries at `$VIMRUNTIME/queries/`.
---
--- @param lang? string language to open the query editor for. If omitted, inferred from the current buffer's filetype.
function M.edit(lang)
diff --git a/runtime/lua/vim/uri.lua b/runtime/lua/vim/uri.lua
index 9dce80b77e..2dc817c5c1 100644
--- a/runtime/lua/vim/uri.lua
+++ b/runtime/lua/vim/uri.lua
@@ -60,7 +60,7 @@ end
---@param path string Path to file
---@return string URI
function M.uri_from_fname(path)
- local volume_path, fname = path:match('^([a-zA-Z]:)(.*)')
+ local volume_path, fname = path:match('^([a-zA-Z]:)(.*)') ---@type string?
local is_windows = volume_path ~= nil
if is_windows then
path = volume_path .. M.uri_encode(fname:gsub('\\', '/'))
@@ -82,7 +82,7 @@ function M.uri_from_bufnr(bufnr)
local fname = vim.api.nvim_buf_get_name(bufnr)
local volume_path = fname:match('^([a-zA-Z]:).*')
local is_windows = volume_path ~= nil
- local scheme
+ local scheme ---@type string?
if is_windows then
fname = fname:gsub('\\', '/')
scheme = fname:match(WINDOWS_URI_SCHEME_PATTERN)
@@ -107,10 +107,9 @@ function M.uri_to_fname(uri)
uri = M.uri_decode(uri)
--TODO improve this.
if is_windows_file_uri(uri) then
- uri = uri:gsub('^file:/+', '')
- uri = uri:gsub('/', '\\')
+ uri = uri:gsub('^file:/+', ''):gsub('/', '\\')
else
- uri = uri:gsub('^file:/+', '/')
+ uri = uri:gsub('^file:/+', '/') ---@type string
end
return uri
end
diff --git a/runtime/queries/markdown/highlights.scm b/runtime/queries/markdown/highlights.scm
index e78d233cc6..2cc5546bac 100644
--- a/runtime/queries/markdown/highlights.scm
+++ b/runtime/queries/markdown/highlights.scm
@@ -61,3 +61,11 @@
] @string.escape
(inline) @spell
+
+;; Conceal backticks
+(fenced_code_block
+ (fenced_code_block_delimiter) @conceal
+ (#set! conceal ""))
+(fenced_code_block
+ (info_string (language) @conceal
+ (#set! conceal "")))
diff --git a/runtime/queries/markdown_inline/highlights.scm b/runtime/queries/markdown_inline/highlights.scm
index cd5da530d7..c75da478af 100644
--- a/runtime/queries/markdown_inline/highlights.scm
+++ b/runtime/queries/markdown_inline/highlights.scm
@@ -92,3 +92,11 @@
"]"
] @conceal
(#set! conceal ""))
+
+;; Replace common HTML entities.
+((entity_reference) @conceal (#eq? @conceal "&nbsp;") (#set! conceal ""))
+((entity_reference) @conceal (#eq? @conceal "&lt;") (#set! conceal "<"))
+((entity_reference) @conceal (#eq? @conceal "&gt;") (#set! conceal ">"))
+((entity_reference) @conceal (#eq? @conceal "&amp;") (#set! conceal "&"))
+((entity_reference) @conceal (#eq? @conceal "&quot;") (#set! conceal "\""))
+((entity_reference) @conceal (#any-of? @conceal "&ensp;" "&emsp;") (#set! conceal " "))
diff --git a/runtime/syntax/kotlin.vim b/runtime/syntax/kotlin.vim
new file mode 100644
index 0000000000..9b85b8ef5c
--- /dev/null
+++ b/runtime/syntax/kotlin.vim
@@ -0,0 +1,157 @@
+" Vim syntax file
+" Language: Kotlin
+" Maintainer: Alexander Udalov
+" URL: https://github.com/udalov/kotlin-vim
+" Last Change: 30 December 2022
+
+if exists('b:current_syntax')
+ finish
+endif
+
+syn keyword ktStatement break continue return
+syn keyword ktConditional if else when
+syn keyword ktRepeat do for while
+syn keyword ktOperator in is by
+syn keyword ktKeyword get set out super this where
+syn keyword ktException try catch finally throw
+
+syn keyword ktInclude import package
+
+" Generated stdlib class names {{{
+" The following is generated by https://github.com/udalov/kotlin-vim/blob/master/extra/generate-stdlib-class-names.main.kts
+syn keyword ktType AbstractCollection AbstractCoroutineContextElement AbstractCoroutineContextKey AbstractDoubleTimeSource AbstractIterator AbstractList AbstractLongTimeSource
+syn keyword ktType AbstractMap AbstractMutableCollection AbstractMutableList AbstractMutableMap AbstractMutableSet AbstractSet AccessDeniedException Accessor Annotation
+syn keyword ktType AnnotationRetention AnnotationTarget Any Appendable ArithmeticException Array ArrayDeque ArrayList AssertionError Boolean BooleanArray BooleanIterator
+syn keyword ktType BuilderInference Byte ByteArray ByteIterator CName CallsInPlace CancellationException Char CharArray CharCategory CharDirectionality CharIterator CharProgression
+syn keyword ktType CharRange CharSequence CharacterCodingException Charsets ClassCastException Cloneable ClosedFloatingPointRange ClosedRange Collection Comparable
+syn keyword ktType ComparableTimeMark Comparator ConcurrentModificationException ConditionalEffect ContextFunctionTypeParams Continuation ContinuationInterceptor ContractBuilder
+syn keyword ktType CopyActionContext CopyActionResult CoroutineContext DeepRecursiveFunction DeepRecursiveScope Delegates Deprecated DeprecatedSinceKotlin DeprecationLevel
+syn keyword ktType Destructured Double DoubleArray DoubleIterator DslMarker Duration DurationUnit Effect Element EmptyCoroutineContext Entry Enum EnumEntries Error Exception
+syn keyword ktType ExperimentalContracts ExperimentalJsExport ExperimentalMultiplatform ExperimentalObjCName ExperimentalObjCRefinement ExperimentalPathApi ExperimentalStdlibApi
+syn keyword ktType ExperimentalSubclassOptIn ExperimentalTime ExperimentalTypeInference ExperimentalUnsignedTypes ExtensionFunctionType FileAlreadyExistsException
+syn keyword ktType FileSystemException FileTreeWalk FileVisitorBuilder FileWalkDirection Float FloatArray FloatIterator FreezingIsDeprecated Function Function0 Function1 Function10
+syn keyword ktType Function11 Function12 Function13 Function14 Function15 Function16 Function17 Function18 Function19 Function2 Function20 Function21 Function22 Function3 Function4
+syn keyword ktType Function5 Function6 Function7 Function8 Function9 FunctionN Getter Grouping HashMap HashSet HiddenFromObjC HidesFromObjC Ignore IllegalArgumentException
+syn keyword ktType IllegalStateException IndexOutOfBoundsException IndexedValue Int IntArray IntIterator IntProgression IntRange InvocationKind Iterable Iterator JsExport JsName
+syn keyword ktType JvmDefault JvmDefaultWithCompatibility JvmDefaultWithoutCompatibility JvmField JvmInline JvmMultifileClass JvmName JvmOverloads JvmRecord JvmSerializableLambda
+syn keyword ktType JvmStatic JvmSuppressWildcards JvmSynthetic JvmWildcard KAnnotatedElement KCallable KClass KClassifier KDeclarationContainer KFunction KMutableProperty
+syn keyword ktType KMutableProperty0 KMutableProperty1 KMutableProperty2 KParameter KProperty KProperty0 KProperty1 KProperty2 KType KTypeParameter KTypeProjection KVariance
+syn keyword ktType KVisibility Key Kind KotlinNullPointerException KotlinReflectionNotSupportedError KotlinVersion Lazy LazyThreadSafetyMode Level LinkedHashMap LinkedHashSet List
+syn keyword ktType ListIterator Long LongArray LongIterator LongProgression LongRange Map MatchGroup MatchGroupCollection MatchNamedGroupCollection MatchResult Metadata Monotonic
+syn keyword ktType MustBeDocumented MutableCollection MutableEntry MutableIterable MutableIterator MutableList MutableListIterator MutableMap MutableSet NoSuchElementException
+syn keyword ktType NoSuchFileException NoWhenBranchMatchedException NotImplementedError Nothing NullPointerException Number NumberFormatException ObjCName ObservableProperty
+syn keyword ktType OnErrorAction OnErrorResult OpenEndRange OptIn OptionalExpectation OverloadResolutionByLambdaReturnType Pair ParameterName PathWalkOption
+syn keyword ktType PropertyDelegateProvider PublishedApi PurelyImplements Random RandomAccess ReadOnlyProperty ReadWriteProperty RefinesInSwift Regex RegexOption Repeatable
+syn keyword ktType ReplaceWith RequiresOptIn RestrictsSuspension Result Retention Returns ReturnsNotNull RuntimeException Sequence SequenceScope Set Setter SharedImmutable Short
+syn keyword ktType ShortArray ShortIterator ShouldRefineInSwift SimpleEffect SinceKotlin Strictfp String StringBuilder SubclassOptInRequired Suppress Synchronized Target
+syn keyword ktType TestTimeSource ThreadLocal Throwable Throws TimeMark TimeSource TimedValue Transient Triple TypeCastException Typography UByte UByteArray UInt UIntArray
+syn keyword ktType UIntProgression UIntRange ULong ULongArray ULongProgression ULongRange UShort UShortArray UninitializedPropertyAccessException Unit UnsafeVariance
+syn keyword ktType UnsupportedOperationException ValueTimeMark Volatile WithComparableMarks
+" }}}
+
+syn keyword ktModifier annotation companion enum inner abstract final open override sealed vararg dynamic expect actual suspend
+syn keyword ktStructure class object interface typealias fun val var constructor init
+
+syn keyword ktReservedKeyword typeof
+
+syn keyword ktBoolean true false
+syn keyword ktConstant null
+
+syn keyword ktModifier reified external inline noinline crossinline
+
+syn match ktModifier "\v<data>\ze\@=.*<(class|object)>"
+syn match ktModifier "\v<value>\ze\@=.*<class>"
+syn match ktModifier "\v<(tailrec|operator|infix)>\ze\@=.*<fun>"
+syn match ktModifier "\v<const>\ze\@=.*<val>"
+syn match ktModifier "\v<lateinit>\ze\@=.*<var>"
+syn match ktModifier "\v<(internal|private|protected|public)>\ze\@=.*<(class|object|interface|typealias|fun|val|var|constructor|get|set)>"
+
+syn match ktOperator "\v\?:|::|\<\=? | \>\=?|[!=]\=\=?|<as>\??|[-*+/%]\=?|[!&|]"
+
+syn keyword ktTodo TODO FIXME XXX contained
+syn match ktShebang "\v^#!.*$"
+syn match ktLineComment "\v//.*$" contains=ktTodo,@Spell
+syn region ktComment matchgroup=ktCommentMatchGroup start="/\*" end="\*/" contains=ktComment,ktTodo,@Spell
+
+syn region ktDocComment start="/\*\*" end="\*/" contains=ktDocTag,ktTodo,@Spell
+syn match ktDocTag "\v\@(author|constructor|receiver|return|since|suppress)>" contained
+syn match ktDocTag "\v\@(exception|param|property|throws|see|sample)>\s*\S+" contains=ktDocTagParam contained
+syn match ktDocTagParam "\v(\s|\[)\S+" contained
+syn match ktComment "/\*\*/"
+
+syn match ktSpecialCharError "\v\\." contained
+syn match ktSpecialChar "\v\\([tbnr'"$\\]|u\x{4})" contained
+syn region ktString start='"' skip='\\"' end='"' contains=ktSimpleInterpolation,ktComplexInterpolation,ktSpecialChar,ktSpecialCharError,@Spell
+syn region ktString start='"""' end='""""*' contains=ktSimpleInterpolation,ktComplexInterpolation,@Spell
+syn match ktCharacter "\v'[^']*'" contains=ktSpecialChar,ktSpecialCharError
+syn match ktCharacter "\v'\\''" contains=ktSpecialChar
+syn match ktCharacter "\v'[^\\]'"
+
+syn match ktAnnotation "\v(\w)@<!\@[[:alnum:]_.]*(:[[:alnum:]_.]*)?"
+syn match ktLabel "\v\w+\@"
+syn match ktLabel "\v(\w)@<=\@\w+"
+
+syn match ktSimpleInterpolation "\v\$\h\w*" contained
+syn region ktComplexInterpolation matchgroup=ktComplexInterpolationBrace start="\v\$\{" end="\v\}" contains=ALLBUT,ktSimpleInterpolation,ktTodo,ktSpecialCharError,ktSpecialChar,ktDocTag,ktDocTagParam
+
+syn match ktNumber "\v<\d+[_[:digit:]]*(uL?|UL?|[LFf])?"
+syn match ktNumber "\v<0[Xx]\x+[_[:xdigit:]]*(uL?|UL?|L)?"
+syn match ktNumber "\v<0[Bb][01]+[_01]*(uL?|UL?|L)?"
+syn match ktFloat "\v<\d*(\d[eE][-+]?\d+|\.\d+([eE][-+]?\d+)?)[Ff]?"
+
+syn match ktEscapedName "\v`.*`"
+
+syn match ktExclExcl "!!"
+syn match ktArrow "->"
+
+syn region ktFold start="{" end="}" transparent fold
+
+exec "syntax sync ccomment ktComment minlines=10"
+
+hi def link ktStatement Statement
+hi def link ktConditional Conditional
+hi def link ktRepeat Repeat
+hi def link ktOperator Operator
+hi def link ktKeyword Keyword
+hi def link ktException Exception
+hi def link ktReservedKeyword Error
+
+hi def link ktInclude Include
+
+hi def link ktType Type
+hi def link ktModifier StorageClass
+hi def link ktStructure Structure
+hi def link ktTypedef Typedef
+
+hi def link ktBoolean Boolean
+hi def link ktConstant Constant
+
+hi def link ktTodo Todo
+hi def link ktShebang Comment
+hi def link ktLineComment Comment
+hi def link ktComment Comment
+hi def link ktCommentMatchGroup Comment
+hi def link ktDocComment Comment
+hi def link ktDocTag Special
+hi def link ktDocTagParam Identifier
+
+hi def link ktSpecialChar SpecialChar
+hi def link ktSpecialCharError Error
+hi def link ktString String
+hi def link ktCharacter Character
+
+hi def link ktAnnotation Identifier
+hi def link ktLabel Identifier
+
+hi def link ktSimpleInterpolation Identifier
+hi def link ktComplexInterpolationBrace Identifier
+
+hi def link ktNumber Number
+hi def link ktFloat Float
+
+hi def link ktExclExcl Special
+hi def link ktArrow Structure
+
+let b:current_syntax = 'kotlin'
+
+" vim:foldmethod=marker