aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/doc/api.txt91
-rw-r--r--runtime/doc/builtin.txt2
-rw-r--r--runtime/doc/deprecated.txt4
-rw-r--r--runtime/doc/diagnostic.txt7
-rw-r--r--runtime/doc/health.txt30
-rw-r--r--runtime/doc/helphelp.txt1
-rw-r--r--runtime/doc/lsp.txt6
-rw-r--r--runtime/doc/lua-guide.txt2
-rw-r--r--runtime/doc/lua.txt35
-rw-r--r--runtime/doc/news.txt26
-rw-r--r--runtime/doc/options.txt8
-rw-r--r--runtime/doc/quickfix.txt4
-rw-r--r--runtime/doc/starting.txt33
-rw-r--r--runtime/doc/terminal.txt6
-rw-r--r--runtime/doc/treesitter.txt44
-rw-r--r--runtime/doc/ui.txt1
-rw-r--r--runtime/doc/usr_02.txt7
-rw-r--r--runtime/doc/usr_05.txt2
-rw-r--r--runtime/doc/usr_25.txt6
-rw-r--r--runtime/doc/various.txt5
-rw-r--r--runtime/doc/vim_diff.txt14
-rw-r--r--runtime/ftplugin/editorconfig.vim6
-rw-r--r--runtime/ftplugin/help.lua53
-rw-r--r--runtime/lua/vim/_defaults.lua2
-rw-r--r--runtime/lua/vim/_editor.lua16
-rw-r--r--runtime/lua/vim/_meta/api.lua76
-rw-r--r--runtime/lua/vim/_meta/api_keysets.lua1
-rw-r--r--runtime/lua/vim/_meta/options.lua44
-rw-r--r--runtime/lua/vim/_meta/vimfn.lua2
-rw-r--r--runtime/lua/vim/_options.lua2
-rw-r--r--runtime/lua/vim/diagnostic.lua18
-rw-r--r--runtime/lua/vim/filetype.lua7
-rw-r--r--runtime/lua/vim/filetype/detect.lua2
-rw-r--r--runtime/lua/vim/fs.lua33
-rw-r--r--runtime/lua/vim/health.lua30
-rw-r--r--runtime/lua/vim/lsp.lua2
-rw-r--r--runtime/lua/vim/lsp/client.lua6
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua2
-rw-r--r--runtime/lua/vim/lsp/handlers.lua5
-rw-r--r--runtime/lua/vim/lsp/util.lua5
-rw-r--r--runtime/lua/vim/shared.lua4
-rw-r--r--runtime/lua/vim/treesitter.lua8
-rw-r--r--runtime/lua/vim/treesitter/_fold.lua204
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua19
-rw-r--r--runtime/lua/vim/treesitter/language.lua5
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua143
-rw-r--r--runtime/lua/vim/treesitter/query.lua31
-rw-r--r--runtime/syntax/lyrics.vim4
-rw-r--r--runtime/syntax/tiasm.vim2
-rw-r--r--runtime/syntax/vim.vim11
50 files changed, 696 insertions, 381 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index c8e0dcd0c5..5a6361d45f 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -654,35 +654,22 @@ nvim_del_var({name}) *nvim_del_var()*
• {name} Variable name
nvim_echo({chunks}, {history}, {opts}) *nvim_echo()*
- Echo a message.
+ Prints a message given by a list of `[text, hl_group]` "chunks".
+
+ Example: >lua
+ vim.api.nvim_echo({ { 'chunk1-line1\nchunk1-line2\n' }, { 'chunk2-line1' } }, true, {})
+<
Parameters: ~
- • {chunks} A list of `[text, hl_group]` arrays, each representing a
- text chunk with specified highlight group name or ID.
- `hl_group` element can be omitted for no highlight.
+ • {chunks} List of `[text, hl_group]` pairs, where each is a `text`
+ string highlighted by the (optional) name or ID `hl_group`.
• {history} if true, add to |message-history|.
• {opts} Optional parameters.
- • verbose: Message is printed as a result of 'verbose'
- option. If Nvim was invoked with -V3log_file, the message
- will be redirected to the log_file and suppressed from
- direct output.
-
-nvim_err_write({str}) *nvim_err_write()*
- Writes a message to the Vim error buffer. Does not append "\n", the
- message is buffered (won't display) until a linefeed is written.
-
- Parameters: ~
- • {str} Message
-
-nvim_err_writeln({str}) *nvim_err_writeln()*
- Writes a message to the Vim error buffer. Appends "\n", so the buffer is
- flushed (and displayed).
-
- Parameters: ~
- • {str} Message
-
- See also: ~
- • nvim_err_write()
+ • err: Treat the message like `:echoerr`. Sets `hl_group`
+ to |hl-ErrorMsg| by default.
+ • verbose: Message is controlled by the 'verbose' option.
+ Nvim invoked with `-V3log` will write the message to the
+ "log" file instead of standard output.
nvim_eval_statusline({str}, {opts}) *nvim_eval_statusline()*
Evaluates statusline string.
@@ -775,6 +762,8 @@ nvim_get_api_info() *nvim_get_api_info()*
nvim_get_chan_info({chan}) *nvim_get_chan_info()*
Gets information about a channel.
+ See |nvim_list_uis()| for an example of how to get channel info.
+
Parameters: ~
• {chan} channel_id, or 0 for current channel
@@ -796,7 +785,7 @@ nvim_get_chan_info({chan}) *nvim_get_chan_info()*
present if a pty is used (e.g. for conpty on Windows).
• "buffer" (optional) Buffer connected to |terminal| instance.
• "client" (optional) Info about the peer (client on the other end of
- the RPC channel), which it provided via |nvim_set_client_info()|.
+ the channel), as set by |nvim_set_client_info()|.
nvim_get_color_by_name({name}) *nvim_get_color_by_name()*
Returns the 24-bit RGB value of a |nvim_get_color_map()| color name or
@@ -1079,6 +1068,12 @@ nvim_list_tabpages() *nvim_list_tabpages()*
nvim_list_uis() *nvim_list_uis()*
Gets a list of dictionaries representing attached UIs.
+ Example: The Nvim builtin |TUI| sets its channel info as described in
+ |startup-tui|. In particular, it sets `client.name` to "nvim-tui". So you
+ can check if the TUI is running by inspecting the client name of each UI: >lua
+ vim.print(vim.api.nvim_get_chan_info(vim.api.nvim_list_uis()[1].chan).client.name)
+<
+
Return: ~
Array of UI dictionaries, each with these keys:
• "height" Requested height of the UI
@@ -1099,17 +1094,6 @@ nvim_load_context({dict}) *nvim_load_context()*
Parameters: ~
• {dict} |Context| map.
-nvim_notify({msg}, {log_level}, {opts}) *nvim_notify()*
- Notify the user with a message
-
- Relays the call to vim.notify . By default forwards your message in the
- echo area but can be overridden to trigger desktop notifications.
-
- Parameters: ~
- • {msg} Message to display to the user
- • {log_level} The log level
- • {opts} Reserved for future use.
-
nvim_open_term({buffer}, {opts}) *nvim_open_term()*
Open a terminal instance in a buffer
@@ -1127,7 +1111,7 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
Example: this `TermHl` command can be used to display and highlight raw
ANSI termcodes, so you can use Nvim as a "scrollback pager" (for terminals
- like kitty): *terminal-scrollback-pager* >lua
+ like kitty): *ansi-colorize* *terminal-scrollback-pager* >lua
vim.api.nvim_create_user_command('TermHl', function()
local b = vim.api.nvim_create_buf(false, true)
local chan = vim.api.nvim_open_term(b, {})
@@ -1154,13 +1138,6 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
Return: ~
Channel id, or 0 on error
-nvim_out_write({str}) *nvim_out_write()*
- Writes a message to the Vim output buffer. Does not append "\n", the
- message is buffered (won't display) until a linefeed is written.
-
- Parameters: ~
- • {str} Message
-
nvim_paste({data}, {crlf}, {phase}) *nvim_paste()*
Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat
the input. UIs call this to implement "paste", but it's also intended for
@@ -1259,25 +1236,23 @@ nvim_select_popupmenu_item({item}, {insert}, {finish}, {opts})
*nvim_set_client_info()*
nvim_set_client_info({name}, {version}, {type}, {methods}, {attributes})
- Self-identifies the client.
+ Self-identifies the client. Sets the `client` object returned by
+ |nvim_get_chan_info()|.
- The client/plugin/application should call this after connecting, to
- provide hints about its identity and purpose, for debugging and
- orchestration.
+ Clients should call this just after connecting, to provide hints for
+ debugging and orchestration. (Note: Something is better than nothing!
+ Fields are optional, but at least set `name`.)
Can be called more than once; the caller should merge old info if
appropriate. Example: library first identifies the channel, then a plugin
using that library later identifies itself.
- Note: ~
- • "Something is better than nothing". You don't need to include all the
- fields.
-
Attributes: ~
|RPC| only
Parameters: ~
- • {name} Short name for the connected client
+ • {name} Client short-name. Sets the `client.name` field of
+ |nvim_get_chan_info()|.
• {version} Dict describing the version, with these (optional) keys:
• "major" major version (defaults to 0 if not set, for
no release yet)
@@ -3175,11 +3150,13 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
• {config} Map defining the window configuration. Keys:
• relative: Sets the window layout to "floating", placed at
(row,col) coordinates relative to:
- • "editor" The global editor grid
+ • "cursor" Cursor position in current window.
+ • "editor" The global editor grid.
+ • "laststatus" 'laststatus' if present, or last row.
+ • "mouse" Mouse position.
+ • "tabline" Tabline if present, or first row.
• "win" Window given by the `win` field, or current
window.
- • "cursor" Cursor position in current window.
- • "mouse" Mouse position
• win: |window-ID| window to split, or relative window when
creating a float (relative="win").
• anchor: Decides which corner of the float to place at
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index f466dde861..6e05dd24d2 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -8282,7 +8282,7 @@ search({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]]) *search()*
• {skip} (`string|function?`)
Return: ~
- (`any`)
+ (`integer`)
searchcount([{options}]) *searchcount()*
Get or update the last search count, like what is displayed
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index ec98cc844f..4f320aeab3 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -16,8 +16,12 @@ Deprecated features
DEPRECATED IN 0.11 *deprecated-0.11*
API
+• nvim_notify() Use |nvim_echo()| or `nvim_exec_lua("vim.notify(...)", ...)` instead.
• nvim_subscribe() Plugins must maintain their own "multicast" channels list.
• nvim_unsubscribe() Plugins must maintain their own "multicast" channels list.
+• nvim_out_write() Use |nvim_echo()|.
+• nvim_err_write() Use |nvim_echo()| with `{err=true}`.
+• nvim_err_writeln() Use |nvim_echo()| with `{err=true}`.
DIAGNOSTICS
• *vim.diagnostic.goto_next()* Use |vim.diagnostic.jump()| with `{count=1, float=true}` instead.
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index 3437717467..7d97a18437 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -93,6 +93,10 @@ The {opts} table passed to a handler is the full set of configuration options
values in the table are already resolved (i.e. if a user specifies a
function for a config option, the function has already been evaluated).
+If a diagnostic handler is configured with a "severity" key then the list of
+diagnostics passed to that handler will be filtered using the value of that
+key (see example below).
+
Nvim provides these handlers by default: "virtual_text", "signs", and
"underline".
@@ -119,6 +123,9 @@ with |vim.notify()|: >lua
vim.diagnostic.config({
["my/notify"] = {
log_level = vim.log.levels.INFO
+
+ -- This handler will only receive "error" diagnostics.
+ severity = vim.diagnostic.severity.ERROR,
}
})
<
diff --git a/runtime/doc/health.txt b/runtime/doc/health.txt
index bca145bd8e..3d37b88321 100644
--- a/runtime/doc/health.txt
+++ b/runtime/doc/health.txt
@@ -21,18 +21,7 @@ To run all healthchecks, use: >vim
<
Plugin authors are encouraged to write new healthchecks. |health-dev|
- *g:health*
-g:health This global variable controls the behavior and appearance of the
- `health` floating window. It should be a dictionary containing the
- following optional keys:
- - `style`: string? Determines the display style of the `health` window.
- Set to `'float'` to enable a floating window. Other
- styles are not currently supported.
-
- Example: >lua
- vim.g.health = { style = 'float' }
-
-Commands *health-commands*
+COMMANDS *health-commands*
*:che* *:checkhealth*
:che[ckhealth] Run all healthchecks.
@@ -60,6 +49,23 @@ Commands *health-commands*
:checkhealth vim*
<
+USAGE *health-usage*
+
+Local mappings in the healthcheck buffer:
+
+q Closes the window.
+
+Global configuration:
+
+ *g:health*
+g:health Dictionary with the following optional keys:
+ - `style` (`'float'|nil`) Set to "float" to display :checkhealth in
+ a floating window instead of the default behavior.
+
+ Example: >lua
+ vim.g.health = { style = 'float' }
+
+--------------------------------------------------------------------------------
Create a healthcheck *health-dev*
Healthchecks are functions that check the user environment, configuration, or
diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt
index 46b3ab507d..f7009aebfe 100644
--- a/runtime/doc/helphelp.txt
+++ b/runtime/doc/helphelp.txt
@@ -193,6 +193,7 @@ Jump to specific subjects by using tags. This can be done in two ways:
Use CTRL-T or CTRL-O to jump back.
Use ":q" to close the help window.
+Use `yxx` to execute the current Lua/Vimscript code block.
If there are several matches for an item you are looking for, this is how you
can jump to each one of them:
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 16e6abe294..e8270123d7 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -32,7 +32,7 @@ Follow these steps to get LSP features:
Example: >lua
vim.lsp.config['luals'] = {
-- Command and arguments to start the server.
- cmd = { 'lua-language-server' }
+ cmd = { 'lua-language-server' },
-- Filetypes to automatically attach to.
filetypes = { 'lua' },
@@ -93,7 +93,7 @@ Given: >lua
multilineTokenSupport = true,
}
}
- }
+ },
root_markers = { '.git' },
})
@@ -878,7 +878,7 @@ foldexpr({lnum}) *vim.lsp.foldexpr()*
To use, check for the "textDocument/foldingRange" capability in an
|LspAttach| autocommand. Example: >lua
- vim.api.nvim_create_autocommand('LspAttach', {
+ vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if client:supports_method('textDocument/foldingRange') then
diff --git a/runtime/doc/lua-guide.txt b/runtime/doc/lua-guide.txt
index b40d5a0791..d0d148f689 100644
--- a/runtime/doc/lua-guide.txt
+++ b/runtime/doc/lua-guide.txt
@@ -153,7 +153,7 @@ its functions if this succeeds and prints an error message otherwise:
if not ok then
print("Module had an error")
else
- mymod.function()
+ mymod.func()
end
<
In contrast to |:source|, |require()| not only searches through all `lua/` directories
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 6547a76f56..44cbf238cf 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -161,7 +161,7 @@ languages like Python and C#. Example: >lua
local func_with_opts = function(opts)
local will_do_foo = opts.foo
local filename = opts.filename
- ...
+ -- ...
end
func_with_opts { foo = true, filename = "hello.world" }
@@ -1299,7 +1299,7 @@ global value of a |global-local| option, see |:setglobal|.
A special interface |vim.opt| exists for conveniently interacting with list-
-and map-style option from Lua: It allows accessing them as Lua tables and
+and map-style options from Lua: It allows accessing them as Lua tables and
offers object-oriented method for adding and removing entries.
Examples: ~
@@ -1505,7 +1505,7 @@ vim.wo[{winid}][{bufnr}] *vim.wo*
Lua module: vim *lua-vim*
vim.cmd({command}) *vim.cmd()*
- Executes Vim script commands.
+ Executes Vimscript (|Ex-commands|).
Note that `vim.cmd` can be indexed with a command name to return a
callable function to the command.
@@ -1539,9 +1539,9 @@ vim.cmd({command}) *vim.cmd()*
Parameters: ~
• {command} (`string|table`) Command(s) to execute. If a string,
- executes multiple lines of Vim script at once. In this
- case, it is an alias to |nvim_exec2()|, where `opts.output`
- is set to false. Thus it works identical to |:source|. If a
+ executes multiple lines of Vimscript at once. In this case,
+ it is an alias to |nvim_exec2()|, where `opts.output` is
+ set to false. Thus it works identical to |:source|. If a
table, executes a single command. In this case, it is an
alias to |nvim_cmd()| where `opts` is empty.
@@ -1805,7 +1805,7 @@ vim.system({cmd}, {opts}, {on_exit}) *vim.system()*
-- Runs synchronously:
local obj = vim.system({'echo', 'hello'}, { text = true }):wait()
- -- { code = 0, signal = 0, stdout = 'hello', stderr = '' }
+ -- { code = 0, signal = 0, stdout = 'hello\n', stderr = '' }
<
See |uv.spawn()| for more details. Note: unlike |uv.spawn()|, vim.system
@@ -2428,7 +2428,7 @@ vim.validate({name}, {value}, {validator}, {optional}, {message})
function vim.startswith(s, prefix)
vim.validate('s', s, 'string')
vim.validate('prefix', prefix, 'string')
- ...
+ -- ...
end
<
2. `vim.validate(spec)` (deprecated) where `spec` is of type
@@ -2442,7 +2442,7 @@ vim.validate({name}, {value}, {validator}, {optional}, {message})
age={age, 'number'},
hobbies={hobbies, 'table'},
}
- ...
+ -- ...
end
<
@@ -3148,6 +3148,23 @@ vim.fs.parents({start}) *vim.fs.parents()*
(`nil`)
(`string?`)
+vim.fs.relpath({base}, {target}, {opts}) *vim.fs.relpath()*
+ Gets `target` path relative to `base`, or `nil` if `base` is not an
+ ancestor.
+
+ Example: >lua
+ vim.fs.relpath('/var', '/var/lib') -- 'lib'
+ vim.fs.relpath('/var', '/usr/bin') -- nil
+<
+
+ Parameters: ~
+ • {base} (`string`)
+ • {target} (`string`)
+ • {opts} (`table?`) Reserved for future use
+
+ Return: ~
+ (`string?`)
+
vim.fs.rm({path}, {opts}) *vim.fs.rm()*
WARNING: This feature is experimental/unstable.
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 931f5e117c..e6a1adf15b 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -68,6 +68,8 @@ DIAGNOSTICS
• The "underline" diagnostics handler sorts diagnostics by severity when using
the "severity_sort" option.
+• Diagnostics are filtered by severity before being passed to a diagnostic
+ handler |diagnostic-handlers|.
EDITOR
@@ -94,7 +96,7 @@ EVENTS
• `msg_show`:
• `history` argument indicating if the message was added to the history.
• new message kinds: "bufwrite", "completion", "list_cmd", "lua_print",
- "search_cmd", "undo", "wildlist".
+ "search_cmd", "undo", "verbose", wildlist".
HIGHLIGHTS
@@ -156,6 +158,11 @@ TREESITTER
if no languages are explicitly registered.
• |vim.treesitter.language.add()| returns `true` if a parser was loaded
successfully and `nil,errmsg` otherwise instead of throwing an error.
+• |vim.treesitter.get_parser()| and |vim.treesitter.start()| no longer parse
+ the tree before returning. Scripts must call |LanguageTree:parse()| explicitly. >lua
+ local p = vim.treesitter.get_parser(0, 'c')
+ p:parse()
+<
TUI
@@ -178,6 +185,9 @@ API
• Improved API "meta" docstrings and :help documentation.
• |nvim__ns_set()| can set properties for a namespace
+• |nvim_echo()| `err` field to print error messages and `chunks` accepts
+ highlight group IDs.
+• |nvim_open_win()| `relative` field can be set to "laststatus" and "tabline".
DEFAULTS
@@ -219,6 +229,7 @@ DIAGNOSTICS
EDITOR
+• Use |yxx| in :help docs to execute Lua and Vimscript code examples.
• Improved |paste| handling for redo (dot-repeat) and macros (|recording|):
• Redoing a large paste is significantly faster and ignores 'autoindent'.
• Replaying a macro with |@| also replays pasted text.
@@ -274,6 +285,7 @@ LUA
supporting two new parameters, `encoding` and `strict_indexing`.
• |vim.json.encode()| has an option to enable forward slash escaping
• |vim.fs.abspath()| converts paths to absolute paths.
+• |vim.fs.relpath()| gets relative path compared to base path.
OPTIONS
@@ -289,6 +301,12 @@ PERFORMANCE
inflight requests). This greatly improves performance with slow LSP servers.
• 10x speedup for |vim.treesitter.foldexpr()| (when no parser exists for the
buffer).
+• Strong |treesitter-query| caching makes repeat |vim.treesitter.query.get()|
+ and |vim.treesitter.query.parse()| calls significantly faster for large
+ queries.
+• Treesitter highlighting is now asynchronous. To force synchronous parsing,
+ use `vim.g._ts_force_sync_parsing = true`.
+• Treesitter folding is now calculated asynchronously.
PLUGINS
@@ -331,6 +349,8 @@ TREESITTER
• New |TSNode:child_with_descendant()|, which is nearly identical to
|TSNode:child_containing_descendant()| except that it can return the
descendant itself.
+• |LanguageTree:parse()| optionally supports asynchronous invocation, which is
+ activated by passing the `on_parse` callback parameter.
TUI
@@ -359,8 +379,8 @@ UI
• |vim.diagnostic.setqflist()| updates an existing quickfix list with the
given title if found
• |ui-messages| content chunks now also contain the highlight group ID.
-• |:checkhealth| can be display in a floating window and controlled by
- the |g:health| variable.
+• |:checkhealth| can display in a floating window, controlled by the
+ |g:health| variable.
==============================================================================
CHANGED FEATURES *news-changed*
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index c2ed19f34f..8d171183d6 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1560,8 +1560,8 @@ A jump table for the options with a short description can be found at |Q_op|.
"menu" or "menuone". No effect if "longest" is present.
noselect Same as "noinsert", except that no menu item is
- pre-selected. If both "noinsert" and "noselect" are present,
- "noselect" has precedence.
+ pre-selected. If both "noinsert" and "noselect" are
+ present, "noselect" has precedence.
fuzzy Enable |fuzzy-matching| for completion candidates. This
allows for more flexible and intuitive matching, where
@@ -4657,8 +4657,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'redrawtime' 'rdt' number (default 2000)
global
Time in milliseconds for redrawing the display. Applies to
- 'hlsearch', 'inccommand', |:match| highlighting and syntax
- highlighting.
+ 'hlsearch', 'inccommand', |:match| highlighting, syntax highlighting,
+ and async |LanguageTree:parse()|.
When redrawing takes more than this many milliseconds no further
matches will be highlighted.
For syntax highlighting the time applies per window. When over the
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index a291c0277d..70082c7835 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -538,9 +538,9 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
< Otherwise it works the same as `:ldo`.
FILTERING A QUICKFIX OR LOCATION LIST:
- *cfilter-plugin* *:Cfilter* *:Lfilter*
+ *cfilter-plugin* *:Cfilter* *:Lfilter* *package-cfilter*
If you have too many entries in a quickfix list, you can use the cfilter
-plugin to reduce the number of entries. Load the plugin with: >
+plugin to reduce the number of entries. Load the plugin with: >vim
packadd cfilter
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 0bfbea75fb..c0254c3fa1 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -164,8 +164,7 @@ argument.
you can overwrite a file by adding an exclamation mark to
the Ex command, as in ":w!". The 'readonly' option can be
reset with ":set noro" (see the options chapter, |options|).
- Subsequent edits will not be done in readonly mode. Calling
- the executable "view" has the same effect as the -R argument.
+ Subsequent edits will not be done in readonly mode.
The 'updatecount' option will be set to 10000, meaning that
the swap file will not be updated automatically very often.
See |-M| for disallowing modifications.
@@ -226,7 +225,8 @@ argument.
arguments. The {script} name is stored at `_G.arg[0]`.
Sets 'verbose' to 1 (like "-V1"), so Lua `print()` writes to
- output.
+ output, as well as other message-emitting functions like
+ |:echo|.
If {script} prints messages and doesn't cause Nvim to exit,
Nvim ensures output ends with a newline.
@@ -288,21 +288,18 @@ argument.
command from a script. |debug-mode|
*-n*
--n No |swap-file| will be used. Recovery after a crash will be
- impossible. Handy if you want to view or edit a file on a
- very slow medium (e.g., a floppy).
- Can also be done with ":set updatecount=0". You can switch it
- on again by setting the 'updatecount' option to some value,
- e.g., ":set uc=100".
- 'updatecount' is set to 0 AFTER executing commands from a
- vimrc file, but before the GUI initializations. Thus it
- overrides a setting for 'updatecount' in a vimrc file, but not
- in a gvimrc file. See |startup|.
- When you want to reduce accesses to the disk (e.g., for a
- laptop), don't use "-n", but set 'updatetime' and
- 'updatecount' to very big numbers, and type ":preserve" when
- you want to save your work. This way you keep the possibility
- for crash recovery.
+-n Disables |swap-file| by setting 'updatecount' to 0 (after
+ executing any |vimrc|). Recovery after a crash will be
+ impossible. Improves peformance when working with a file on
+ a very slow medium (usb drive, network share).
+
+ Enable it again by setting 'updatecount' to some value, e.g.
+ ":set updatecount=100".
+
+ To reduce accesses to the disk, don't use "-n", but set
+ 'updatetime' and 'updatecount' to very big numbers, and type
+ ":preserve" when you want to save your work. This way you
+ keep the possibility for crash recovery.
*-o*
-o[N] Open N windows, split horizontally. If [N] is not given,
diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt
index ff8e3a976f..a7f278990c 100644
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -165,8 +165,8 @@ directory indicated in the request. >lua
end
})
-To try it out, select the above code and source it with `:'<,'>lua`, then run
-this command in a :terminal buffer: >
+To try it out, select the above code and source it with `:'<,'>lua` (or
+`yxx`), then run this command in a :terminal buffer: >
printf "\033]7;file://./foo/bar\033\\"
@@ -207,7 +207,7 @@ Use |jobwait()| to check if the terminal job has finished: >vim
let running = jobwait([&channel], 0)[0] == -1
<
==============================================================================
-:Termdebug plugin *terminal-debug*
+:Termdebug plugin *terminal-debug* *terminal-debugger* *package-termdebug*
The Terminal debugging plugin can be used to debug a program with gdb and view
the source code in a Vim window. Since this is completely contained inside
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 28fe943359..41679f80ca 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -70,7 +70,7 @@ adds arbitrary metadata and conditional data to a match.
Queries are written in a lisp-like language documented in
https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax
-Note: The predicates listed there page differ from those Nvim supports. See
+Note: The predicates listed there differ from those Nvim supports. See
|treesitter-predicates| for a complete list of predicates supported by Nvim.
Nvim looks for queries as `*.scm` files in a `queries` directory under
@@ -1090,6 +1090,9 @@ start({bufnr}, {lang}) *vim.treesitter.start()*
required for some plugins. In this case, add `vim.bo.syntax = 'on'` after
the call to `start`.
+ Note: By default, the highlighter parses code asynchronously, using a
+ segment time of 3ms.
+
Example: >lua
vim.api.nvim_create_autocmd( 'FileType', { pattern = 'tex',
callback = function(args)
@@ -1336,7 +1339,7 @@ parse({lang}, {query}) *vim.treesitter.query.parse()*
`info.captures`).
• `info.patterns`: information about predicates.
- Example (select the code then run `:'<,'>lua` to try it): >lua
+ Example (to try it, use `yxx` or select the code then run `:'<,'>lua`): >lua
local query = vim.treesitter.query.parse('vimdoc', [[
; query
((h1) @str
@@ -1401,8 +1404,8 @@ Query:iter_captures({node}, {source}, {start}, {stop})
Defaults to `node:end_()`.
Return: ~
- (`fun(end_line: integer?): integer, TSNode, vim.treesitter.query.TSMetadata, TSQueryMatch`)
- capture id, capture node, metadata, match
+ (`fun(end_line: integer?): integer, TSNode, vim.treesitter.query.TSMetadata, TSQueryMatch, TSTree`)
+ capture id, capture node, metadata, match, tree
*Query:iter_matches()*
Query:iter_matches({node}, {source}, {start}, {stop}, {opts})
@@ -1422,7 +1425,7 @@ Query:iter_matches({node}, {source}, {start}, {stop}, {opts})
-- `node` was captured by the `name` capture in the match
local node_data = metadata[id] -- Node level metadata
- ... use the info here ...
+ -- ... use the info here ...
end
end
end
@@ -1447,8 +1450,8 @@ Query:iter_matches({node}, {source}, {start}, {stop}, {opts})
compatibility and will be removed in a future release.
Return: ~
- (`fun(): integer, table<integer, TSNode[]>, vim.treesitter.query.TSMetadata`)
- pattern id, match, metadata
+ (`fun(): integer, table<integer, TSNode[]>, vim.treesitter.query.TSMetadata, TSTree`)
+ pattern id, match, metadata, tree
set({lang}, {query_name}, {text}) *vim.treesitter.query.set()*
Sets the runtime query named {query_name} for {lang}
@@ -1611,7 +1614,7 @@ LanguageTree:node_for_range({range}, {opts})
Return: ~
(`TSNode?`)
-LanguageTree:parse({range}) *LanguageTree:parse()*
+LanguageTree:parse({range}, {on_parse}) *LanguageTree:parse()*
Recursively parse all regions in the language tree using
|treesitter-parsers| for the corresponding languages and run injection
queries on the parsed trees to determine whether child trees should be
@@ -1622,14 +1625,27 @@ LanguageTree:parse({range}) *LanguageTree:parse()*
if {range} is `true`).
Parameters: ~
- • {range} (`boolean|Range?`) Parse this range in the parser's source.
- 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).
+ • {range} (`boolean|Range?`) Parse this range in the parser's
+ source. 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).
+ • {on_parse} (`fun(err?: string, trees?: table<integer, TSTree>)?`)
+ Function invoked when parsing completes. When provided and
+ `vim.g._ts_force_sync_parsing` is not set, parsing will
+ run asynchronously. The first argument to the function is
+ a string respresenting the error type, in case of a
+ failure (currently only possible for timeouts). The second
+ argument is the list of trees returned by the parse (upon
+ success), or `nil` if the parse timed out (determined by
+ 'redrawtime').
+
+ If parsing was still able to finish synchronously (within
+ 3ms), `parse()` returns the list of trees. Otherwise, it
+ returns `nil`.
Return: ~
- (`table<integer, TSTree>`)
+ (`table<integer, TSTree>?`)
*LanguageTree:register_cbs()*
LanguageTree:register_cbs({cbs}, {recursive})
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index 8f25133e7a..26ea03d2be 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -806,6 +806,7 @@ must handle.
"search_cmd" Entered search command
"search_count" Search count message ("S" flag of 'shortmess')
"undo" |:undo| and |:redo| message
+ "verbose" 'verbose' message
"wildlist" 'wildmode' "list" message
"wmsg" Warning ("search hit BOTTOM", |W10|, …)
New kinds may be added in the future; clients should treat unknown
diff --git a/runtime/doc/usr_02.txt b/runtime/doc/usr_02.txt
index 1fc612de26..f8cfcbe547 100644
--- a/runtime/doc/usr_02.txt
+++ b/runtime/doc/usr_02.txt
@@ -684,6 +684,13 @@ Summary: *help-summary* >
:help E128
< takes you to the |:function| command
+27) Documenction for packages distributed with Vim have the form package-<name>.
+ So >
+ :help package-termdebug
+<
+ will bring you to the help section for the included termdebug plugin and
+ how to enable it.
+
==============================================================================
diff --git a/runtime/doc/usr_05.txt b/runtime/doc/usr_05.txt
index 698d1207d3..d75438cd22 100644
--- a/runtime/doc/usr_05.txt
+++ b/runtime/doc/usr_05.txt
@@ -235,7 +235,7 @@ an archive or as a repository. For an archive you can follow these steps:
else.
-Adding nohlsearch package *nohlsearch-install*
+Adding nohlsearch package *nohlsearch-install* *package-nohlsearch*
Load the plugin with this command: >
packadd nohlsearch
diff --git a/runtime/doc/usr_25.txt b/runtime/doc/usr_25.txt
index 955d2ae5f0..8dbe1332b5 100644
--- a/runtime/doc/usr_25.txt
+++ b/runtime/doc/usr_25.txt
@@ -190,15 +190,15 @@ This results in the following:
story. ~
-JUSTIFYING TEXT
+JUSTIFYING TEXT *justify* *:Justify* *Justify()* *package-justify*
Vim has no built-in way of justifying text. However, there is a neat macro
package that does the job. To use this package, execute the following
-command: >
+command: >vim
:packadd justify
-Or put this line in your |vimrc|: >
+Or put this line in your |vimrc|: >vim
packadd! justify
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index 6074931565..611e820cab 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -554,6 +554,11 @@ gO Show a filetype-specific, navigable "outline" of the
*:sl!* *:sleep!*
:[N]sl[eep]! [N][m] Same as above, but hide the cursor.
+ *yxx*
+yxx Executes the current code block.
+
+ Works in |help| buffers.
+
==============================================================================
2. Using Vim like less or more *less*
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index a92ddf33e6..a59312208a 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -347,11 +347,15 @@ Options:
- `:set {option}<` removes local value for all |global-local| options.
- `:setlocal {option}<` copies global value to local value for all options.
+- 'ambiwidth' cannot be set to empty.
- 'autoread' works in the terminal (if it supports "focus" events)
+- 'background' cannot be set to empty.
- 'cpoptions' flags: |cpo-_|
- 'diffopt' "linematch" feature
+- 'eadirection' cannot be set to empty.
- 'exrc' searches for ".nvim.lua", ".nvimrc", or ".exrc" files. The
user is prompted whether to trust the file.
+- 'fileformat' cannot be set to empty.
- 'fillchars' flags: "msgsep", "horiz", "horizup", "horizdown",
"vertleft", "vertright", "verthoriz"
- 'foldcolumn' supports up to 9 dynamic/fixed columns
@@ -363,14 +367,17 @@ Options:
- "clean" removes unloaded buffers from the jumplist.
- the |jumplist|, |changelist|, |alternate-file| or using |mark-motions|.
- 'laststatus' global statusline support
+- 'mousemodel' cannot be set to empty.
- 'mousescroll' amount to scroll by when scrolling with a mouse
- 'pumblend' pseudo-transparent popupmenu
- 'scrollback'
- 'shortmess'
- "F" flag does not affect output from autocommands.
- "q" flag fully hides macro recording message.
+- 'showcmdloc' cannot be set to empty.
- 'signcolumn' can show multiple signs (dynamic or fixed columns)
- 'statuscolumn' full control of columns using 'statusline' format
+- 'splitkeep' cannot be set to empty.
- 'tabline' middle-click on tabpage label closes tabpage,
and %@Func@foo%X can call any function on mouse-click
- 'termpastefilter'
@@ -423,8 +430,11 @@ TUI:
<
*'term'* *E529* *E530* *E531*
- 'term' reflects the terminal type derived from |$TERM| and other environment
- checks. For debugging only; not reliable during startup. >vim
- :echo &term
+ checks. Use `:echo &term` to get its value. For debugging only; not
+ reliable during startup.
+ - Note: If you want to detect when Nvim is running in a terminal, use
+ `has('gui_running')` |has()| or see |nvim_list_uis()| for an example of
+ how to inspect the UI channel.
- "builtin_x" means one of the |builtin-terms| was chosen, because the expected
terminfo file was not found on the system.
- Nvim will use 256-colour capability on Linux virtual terminals. Vim uses
diff --git a/runtime/ftplugin/editorconfig.vim b/runtime/ftplugin/editorconfig.vim
index 6d437351eb..1693a95c0b 100644
--- a/runtime/ftplugin/editorconfig.vim
+++ b/runtime/ftplugin/editorconfig.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin
" Language: EditorConfig
" Maintainer: Riley Bruins <ribru17@gmail.com>
-" Last Change: 2024 Jul 06
+" Last Change: 2025 Jan 10
if exists('b:did_ftplugin')
finish
@@ -10,4 +10,6 @@ let b:did_ftplugin = 1
setl comments=:#,:; commentstring=#\ %s
-let b:undo_ftplugin = 'setl com< cms<'
+setl omnifunc=syntaxcomplete#Complete
+
+let b:undo_ftplugin = 'setl com< cms< ofu<'
diff --git a/runtime/ftplugin/help.lua b/runtime/ftplugin/help.lua
index 8d991be0e4..689a4db408 100644
--- a/runtime/ftplugin/help.lua
+++ b/runtime/ftplugin/help.lua
@@ -31,5 +31,56 @@ vim.keymap.set('n', 'gO', function()
require('vim.vimhelp').show_toc()
end, { buffer = 0, silent = true })
-vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n exe "nunmap <buffer> gO"'
+-- Add "runnables" for Lua/Vimscript code examples.
+---@type table<integer, { lang: string, code: string }>
+local code_blocks = {}
+local tree = vim.treesitter.get_parser():parse()[1]
+local query = vim.treesitter.query.parse(
+ 'vimdoc',
+ [[
+ (codeblock
+ (language) @_lang
+ .
+ (code) @code
+ (#any-of? @_lang "lua" "vim")
+ (#set! @code lang @_lang))
+]]
+)
+local run_message_ns = vim.api.nvim_create_namespace('vimdoc/run_message')
+
+vim.api.nvim_buf_clear_namespace(0, run_message_ns, 0, -1)
+for _, match, metadata in query:iter_matches(tree:root(), 0, 0, -1) do
+ for id, nodes in pairs(match) do
+ local name = query.captures[id]
+ local node = nodes[1]
+ local start, _, end_ = node:parent():range() --[[@as integer]]
+
+ if name == 'code' then
+ vim.api.nvim_buf_set_extmark(0, run_message_ns, start, 0, {
+ virt_text = { { 'Run with `yxx`', 'LspCodeLens' } },
+ })
+ local code = vim.treesitter.get_node_text(node, 0)
+ local lang_node = match[metadata[id].lang][1] --[[@as TSNode]]
+ local lang = vim.treesitter.get_node_text(lang_node, 0)
+ for i = start + 1, end_ do
+ code_blocks[i] = { lang = lang, code = code }
+ end
+ end
+ end
+end
+
+vim.keymap.set('n', 'yxx', function()
+ local pos = vim.api.nvim_win_get_cursor(0)[1]
+ local code_block = code_blocks[pos]
+ if not code_block then
+ vim.print('No code block found')
+ elseif code_block.lang == 'lua' then
+ vim.cmd.lua(code_block.code)
+ elseif code_block.lang == 'vim' then
+ vim.cmd(code_block.code)
+ end
+end, { buffer = true })
+
+vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '')
+ .. '\n exe "nunmap <buffer> gO" | exe "nunmap <buffer> yxx"'
vim.b.undo_ftplugin = vim.b.undo_ftplugin .. ' | call v:lua.vim.treesitter.stop()'
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index 4216a2acb7..d71116117e 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -224,7 +224,7 @@ do
local function cmd(opts)
local ok, err = pcall(vim.api.nvim_cmd, opts, {})
if not ok then
- vim.api.nvim_err_writeln(err:sub(#'Vim:' + 1))
+ vim.api.nvim_echo({ { err:sub(#'Vim:' + 1) } }, true, { err = true })
end
end
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 44f17b3f85..4b28b63746 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -58,6 +58,7 @@ vim._extra = {
--- @private
vim.log = {
+ --- @enum vim.log.levels
levels = {
TRACE = 0,
DEBUG = 1,
@@ -92,7 +93,7 @@ local utfs = {
---
--- -- Runs synchronously:
--- local obj = vim.system({'echo', 'hello'}, { text = true }):wait()
---- -- { code = 0, signal = 0, stdout = 'hello', stderr = '' }
+--- -- { code = 0, signal = 0, stdout = 'hello\n', stderr = '' }
---
--- ```
---
@@ -390,7 +391,7 @@ end
local VIM_CMD_ARG_MAX = 20
---- Executes Vim script commands.
+--- Executes Vimscript (|Ex-commands|).
---
--- Note that `vim.cmd` can be indexed with a command name to return a callable function to the
--- command.
@@ -425,7 +426,7 @@ local VIM_CMD_ARG_MAX = 20
--- ```
---
---@param command string|table Command(s) to execute.
---- If a string, executes multiple lines of Vim script at once. In this
+--- If a string, executes multiple lines of Vimscript at once. In this
--- case, it is an alias to |nvim_exec2()|, where `opts.output` is set
--- to false. Thus it works identical to |:source|.
--- If a table, executes a single command. In this case, it is an alias
@@ -620,13 +621,8 @@ end
---@param opts table|nil Optional parameters. Unused by default.
---@diagnostic disable-next-line: unused-local
function vim.notify(msg, level, opts) -- luacheck: no unused args
- if level == vim.log.levels.ERROR then
- vim.api.nvim_err_writeln(msg)
- elseif level == vim.log.levels.WARN then
- vim.api.nvim_echo({ { msg, 'WarningMsg' } }, true, {})
- else
- vim.api.nvim_echo({ { msg } }, true, {})
- end
+ local chunks = { { msg, level == vim.log.levels.WARN and 'WarningMsg' or nil } }
+ vim.api.nvim_echo(chunks, true, { err = level == vim.log.levels.ERROR })
end
do
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index 7297c8ad38..670e867c1e 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -1097,29 +1097,28 @@ function vim.api.nvim_del_user_command(name) end
--- @param name string Variable name
function vim.api.nvim_del_var(name) end
---- Echo a message.
+--- Prints a message given by a list of `[text, hl_group]` "chunks".
---
---- @param chunks any[] A list of `[text, hl_group]` arrays, each representing a
---- text chunk with specified highlight group name or ID.
---- `hl_group` element can be omitted for no highlight.
+--- Example:
+--- ```lua
+--- vim.api.nvim_echo({ { 'chunk1-line1\nchunk1-line2\n' }, { 'chunk2-line1' } }, true, {})
+--- ```
+---
+--- @param chunks any[] List of `[text, hl_group]` pairs, where each is a `text` string highlighted by
+--- the (optional) name or ID `hl_group`.
--- @param history boolean if true, add to `message-history`.
--- @param opts vim.api.keyset.echo_opts Optional parameters.
---- - verbose: Message is printed as a result of 'verbose' option.
---- If Nvim was invoked with -V3log_file, the message will be
---- redirected to the log_file and suppressed from direct output.
+--- - err: Treat the message like `:echoerr`. Sets `hl_group` to `hl-ErrorMsg` by default.
+--- - verbose: Message is controlled by the 'verbose' option. Nvim invoked with `-V3log`
+--- will write the message to the "log" file instead of standard output.
function vim.api.nvim_echo(chunks, history, opts) end
---- Writes a message to the Vim error buffer. Does not append "\n", the
---- message is buffered (won't display) until a linefeed is written.
----
---- @param str string Message
+--- @deprecated
+--- @param str string
function vim.api.nvim_err_write(str) end
---- Writes a message to the Vim error buffer. Appends "\n", so the buffer is
---- flushed (and displayed).
----
---- @see vim.api.nvim_err_write
---- @param str string Message
+--- @deprecated
+--- @param str string
function vim.api.nvim_err_writeln(str) end
--- Evaluates a Vimscript `expression`. Dicts and Lists are recursively expanded.
@@ -1279,6 +1278,8 @@ function vim.api.nvim_get_autocmds(opts) end
--- Gets information about a channel.
---
+--- See `nvim_list_uis()` for an example of how to get channel info.
+---
--- @param chan integer channel_id, or 0 for current channel
--- @return table<string,any> # Channel info dict with these keys:
--- - "id" Channel id.
@@ -1296,8 +1297,8 @@ function vim.api.nvim_get_autocmds(opts) end
--- "/dev/pts/1". If unknown, the key will still be present if a pty is used (e.g.
--- for conpty on Windows).
--- - "buffer" (optional) Buffer connected to |terminal| instance.
---- - "client" (optional) Info about the peer (client on the other end of the RPC channel),
---- which it provided via |nvim_set_client_info()|.
+--- - "client" (optional) Info about the peer (client on the other end of the channel), as set
+--- by |nvim_set_client_info()|.
---
function vim.api.nvim_get_chan_info(chan) end
@@ -1619,6 +1620,14 @@ function vim.api.nvim_list_tabpages() end
--- Gets a list of dictionaries representing attached UIs.
---
+--- Example: The Nvim builtin `TUI` sets its channel info as described in `startup-tui`. In
+--- particular, it sets `client.name` to "nvim-tui". So you can check if the TUI is running by
+--- inspecting the client name of each UI:
+---
+--- ```lua
+--- vim.print(vim.api.nvim_get_chan_info(vim.api.nvim_list_uis()[1].chan).client.name)
+--- ```
+---
--- @return any[] # Array of UI dictionaries, each with these keys:
--- - "height" Requested height of the UI
--- - "width" Requested width of the UI
@@ -1638,14 +1647,10 @@ function vim.api.nvim_list_wins() end
--- @return any
function vim.api.nvim_load_context(dict) end
---- Notify the user with a message
----
---- Relays the call to vim.notify . By default forwards your message in the
---- echo area but can be overridden to trigger desktop notifications.
----
---- @param msg string Message to display to the user
---- @param log_level integer The log level
---- @param opts table<string,any> Reserved for future use.
+--- @deprecated
+--- @param msg string
+--- @param log_level integer
+--- @param opts table<string,any>
--- @return any
function vim.api.nvim_notify(msg, log_level, opts) end
@@ -1664,7 +1669,8 @@ function vim.api.nvim_notify(msg, log_level, opts) end
--- in a virtual terminal having the intended size.
---
--- Example: this `TermHl` command can be used to display and highlight raw ANSI termcodes, so you
---- can use Nvim as a "scrollback pager" (for terminals like kitty): [terminal-scrollback-pager]()
+--- can use Nvim as a "scrollback pager" (for terminals like kitty): [ansi-colorize]()
+--- [terminal-scrollback-pager]()
---
--- ```lua
--- vim.api.nvim_create_user_command('TermHl', function()
@@ -1748,10 +1754,12 @@ function vim.api.nvim_open_term(buffer, opts) end
--- @param config vim.api.keyset.win_config Map defining the window configuration. Keys:
--- - relative: Sets the window layout to "floating", placed at (row,col)
--- coordinates relative to:
---- - "editor" The global editor grid
---- - "win" Window given by the `win` field, or current window.
---- - "cursor" Cursor position in current window.
---- - "mouse" Mouse position
+--- - "cursor" Cursor position in current window.
+--- - "editor" The global editor grid.
+--- - "laststatus" 'laststatus' if present, or last row.
+--- - "mouse" Mouse position.
+--- - "tabline" Tabline if present, or first row.
+--- - "win" Window given by the `win` field, or current window.
--- - win: `window-ID` window to split, or relative window when creating a
--- float (relative="win").
--- - anchor: Decides which corner of the float to place at (row,col):
@@ -1859,10 +1867,8 @@ function vim.api.nvim_open_term(buffer, opts) end
--- @return integer # Window handle, or 0 on error
function vim.api.nvim_open_win(buffer, enter, config) end
---- Writes a message to the Vim output buffer. Does not append "\n", the
---- message is buffered (won't display) until a linefeed is written.
----
---- @param str string Message
+--- @deprecated
+--- @param str string
function vim.api.nvim_out_write(str) end
--- Parse command line.
diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua
index c08ab0663b..98e916115e 100644
--- a/runtime/lua/vim/_meta/api_keysets.lua
+++ b/runtime/lua/vim/_meta/api_keysets.lua
@@ -88,6 +88,7 @@ error('Cannot require a meta file')
--- @field pattern? string|string[]
--- @class vim.api.keyset.echo_opts
+--- @field err? boolean
--- @field verbose? boolean
--- @class vim.api.keyset.empty
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index e5cea884c5..14f252516a 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -52,7 +52,7 @@ vim.go.ari = vim.go.allowrevins
--- set to one of CJK locales. See Unicode Standard Annex #11
--- (https://www.unicode.org/reports/tr11).
---
---- @type string
+--- @type 'single'|'double'
vim.o.ambiwidth = "single"
vim.o.ambw = vim.o.ambiwidth
vim.go.ambiwidth = vim.o.ambiwidth
@@ -208,7 +208,7 @@ vim.go.awa = vim.go.autowriteall
--- will change. To use other settings, place ":highlight" commands AFTER
--- the setting of the 'background' option.
---
---- @type string
+--- @type 'light'|'dark'
vim.o.background = "dark"
vim.o.bg = vim.o.background
vim.go.background = vim.o.background
@@ -595,7 +595,7 @@ vim.wo.briopt = vim.wo.breakindentopt
--- This option is used together with 'buftype' and 'swapfile' to specify
--- special kinds of buffers. See `special-buffers`.
---
---- @type string
+--- @type ''|'hide'|'unload'|'delete'|'wipe'
vim.o.bufhidden = ""
vim.o.bh = vim.o.bufhidden
vim.bo.bufhidden = vim.o.bufhidden
@@ -658,7 +658,7 @@ vim.bo.bl = vim.bo.buflisted
--- without saving. For writing there must be matching `BufWriteCmd|,
--- |FileWriteCmd` or `FileAppendCmd` autocommands.
---
---- @type string
+--- @type ''|'acwrite'|'help'|'nofile'|'nowrite'|'quickfix'|'terminal'|'prompt'
vim.o.buftype = ""
vim.o.bt = vim.o.buftype
vim.bo.buftype = vim.o.buftype
@@ -1087,8 +1087,8 @@ vim.go.cia = vim.go.completeitemalign
--- "menu" or "menuone". No effect if "longest" is present.
---
--- noselect Same as "noinsert", except that no menu item is
---- pre-selected. If both "noinsert" and "noselect" are present,
---- "noselect" has precedence.
+--- pre-selected. If both "noinsert" and "noselect" are
+--- present, "noselect" has precedence.
---
--- fuzzy Enable `fuzzy-matching` for completion candidates. This
--- allows for more flexible and intuitive matching, where
@@ -1118,7 +1118,7 @@ vim.go.cot = vim.go.completeopt
--- For Insert mode completion the buffer-local value is used. For
--- command line completion the global value is used.
---
---- @type string
+--- @type ''|'slash'|'backslash'
vim.o.completeslash = ""
vim.o.csl = vim.o.completeslash
vim.bo.completeslash = vim.o.completeslash
@@ -1824,7 +1824,7 @@ vim.go.dy = vim.go.display
--- hor horizontally, height of windows is not affected
--- both width and height of windows is affected
---
---- @type string
+--- @type 'both'|'ver'|'hor'
vim.o.eadirection = "both"
vim.o.ead = vim.o.eadirection
vim.go.eadirection = vim.o.eadirection
@@ -2126,7 +2126,7 @@ vim.go.fencs = vim.go.fileencodings
--- option is set, because the file would be different when written.
--- This option cannot be changed when 'modifiable' is off.
---
---- @type string
+--- @type 'unix'|'dos'|'mac'
vim.o.fileformat = "unix"
vim.o.ff = vim.o.fileformat
vim.bo.fileformat = vim.o.fileformat
@@ -2382,7 +2382,7 @@ vim.go.fcl = vim.go.foldclose
--- "[1-9]": to display a fixed number of columns
--- See `folding`.
---
---- @type string
+--- @type 'auto'|'auto:1'|'auto:2'|'auto:3'|'auto:4'|'auto:5'|'auto:6'|'auto:7'|'auto:8'|'auto:9'|'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
vim.o.foldcolumn = "0"
vim.o.fdc = vim.o.foldcolumn
vim.wo.foldcolumn = vim.o.foldcolumn
@@ -2479,7 +2479,7 @@ vim.wo.fmr = vim.wo.foldmarker
--- `fold-syntax` syntax Syntax highlighting items specify folds.
--- `fold-diff` diff Fold text that is not changed.
---
---- @type string
+--- @type 'manual'|'expr'|'marker'|'indent'|'syntax'|'diff'
vim.o.foldmethod = "manual"
vim.o.fdm = vim.o.foldmethod
vim.wo.foldmethod = vim.o.foldmethod
@@ -3144,7 +3144,7 @@ vim.bo.ims = vim.bo.imsearch
--- 'redrawtime') then 'inccommand' is automatically disabled until
--- `Command-line-mode` is done.
---
---- @type string
+--- @type 'nosplit'|'split'|''
vim.o.inccommand = "nosplit"
vim.o.icm = vim.o.inccommand
vim.go.inccommand = vim.o.inccommand
@@ -4354,7 +4354,7 @@ vim.go.mh = vim.go.mousehide
--- "g<LeftMouse>" is "<C-LeftMouse> (jump to tag under mouse click)
--- "g<RightMouse>" is "<C-RightMouse> ("CTRL-T")
---
---- @type string
+--- @type 'extend'|'popup'|'popup_setpos'
vim.o.mousemodel = "popup_setpos"
vim.o.mousem = vim.o.mousemodel
vim.go.mousemodel = vim.o.mousemodel
@@ -4845,8 +4845,8 @@ vim.go.redrawdebug = vim.o.redrawdebug
vim.go.rdb = vim.go.redrawdebug
--- Time in milliseconds for redrawing the display. Applies to
---- 'hlsearch', 'inccommand', `:match` highlighting and syntax
---- highlighting.
+--- 'hlsearch', 'inccommand', `:match` highlighting, syntax highlighting,
+--- and async `LanguageTree:parse()`.
--- When redrawing takes more than this many milliseconds no further
--- matches will be highlighted.
--- For syntax highlighting the time applies per window. When over the
@@ -4947,7 +4947,7 @@ vim.wo.rl = vim.wo.rightleft
--- This is useful for languages such as Hebrew, Arabic and Farsi.
--- The 'rightleft' option must be set for 'rightleftcmd' to take effect.
---
---- @type string
+--- @type 'search'
vim.o.rightleftcmd = "search"
vim.o.rlc = vim.o.rightleftcmd
vim.wo.rightleftcmd = vim.o.rightleftcmd
@@ -5222,7 +5222,7 @@ vim.go.sect = vim.go.sections
--- backwards, you cannot include the last character of a line, when
--- starting in Normal mode and 'virtualedit' empty.
---
---- @type string
+--- @type 'inclusive'|'exclusive'|'old'
vim.o.selection = "inclusive"
vim.o.sel = vim.o.selection
vim.go.selection = vim.o.selection
@@ -5788,7 +5788,7 @@ vim.go.sc = vim.go.showcmd
--- place the text. Without a custom 'statusline' or 'tabline' it will be
--- displayed in a convenient location.
---
---- @type string
+--- @type 'last'|'statusline'|'tabline'
vim.o.showcmdloc = "last"
vim.o.sloc = vim.o.showcmdloc
vim.go.showcmdloc = vim.o.showcmdloc
@@ -5920,7 +5920,7 @@ vim.go.siso = vim.go.sidescrolloff
--- "number" display signs in the 'number' column. If the number
--- column is not present, then behaves like "auto".
---
---- @type string
+--- @type 'yes'|'no'|'auto'|'auto:1'|'auto:2'|'auto:3'|'auto:4'|'auto:5'|'auto:6'|'auto:7'|'auto:8'|'auto:9'|'yes:1'|'yes:2'|'yes:3'|'yes:4'|'yes:5'|'yes:6'|'yes:7'|'yes:8'|'yes:9'|'number'
vim.o.signcolumn = "auto"
vim.o.scl = vim.o.signcolumn
vim.wo.signcolumn = vim.o.signcolumn
@@ -6228,7 +6228,7 @@ vim.go.sb = vim.go.splitbelow
--- with the previous cursor position. For "screen", the text cannot always
--- be kept on the same screen line when 'wrap' is enabled.
---
---- @type string
+--- @type 'cursor'|'screen'|'topline'
vim.o.splitkeep = "cursor"
vim.o.spk = vim.o.splitkeep
vim.go.splitkeep = vim.o.splitkeep
@@ -6876,7 +6876,7 @@ vim.go.tbs = vim.go.tagbsearch
--- match Match case
--- smart Ignore case unless an upper case letter is used
---
---- @type string
+--- @type 'followic'|'ignore'|'match'|'followscs'|'smart'
vim.o.tagcase = "followic"
vim.o.tc = vim.o.tagcase
vim.bo.tagcase = vim.o.tagcase
@@ -7758,7 +7758,7 @@ vim.go.wop = vim.go.wildoptions
--- key is never used for the menu.
--- This option is not used for <F10>; on Win32.
---
---- @type string
+--- @type 'yes'|'menu'|'no'
vim.o.winaltkeys = "menu"
vim.o.wak = vim.o.winaltkeys
vim.go.winaltkeys = vim.o.winaltkeys
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 031b109b38..6316ab2bfc 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -7537,7 +7537,7 @@ function vim.fn.screenstring(row, col) end
--- @param stopline? integer
--- @param timeout? integer
--- @param skip? string|function
---- @return any
+--- @return integer
function vim.fn.search(pattern, flags, stopline, timeout, skip) end
--- Get or update the last search count, like what is displayed
diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua
index dc37595578..8338c5ead7 100644
--- a/runtime/lua/vim/_options.lua
+++ b/runtime/lua/vim/_options.lua
@@ -768,7 +768,7 @@ end
---
---
--- A special interface |vim.opt| exists for conveniently interacting with list-
---- and map-style option from Lua: It allows accessing them as Lua tables and
+--- and map-style options from Lua: It allows accessing them as Lua tables and
--- offers object-oriented method for adding and removing entries.
---
--- Examples: ~
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 90f967fe79..6466c7d6e8 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -1395,10 +1395,6 @@ M.handlers.signs = {
return
end
- if opts.signs and opts.signs.severity then
- diagnostics = filter_by_severity(opts.signs.severity, diagnostics)
- end
-
-- 10 is the default sign priority when none is explicitly specified
local priority = opts.signs and opts.signs.priority or 10
local get_priority = severity_to_extmark_priority(priority, opts)
@@ -1501,10 +1497,6 @@ M.handlers.underline = {
return
end
- if opts.underline and opts.underline.severity then
- diagnostics = filter_by_severity(opts.underline.severity, diagnostics)
- end
-
local ns = M.get_namespace(namespace)
if not ns.user_data.underline_ns then
ns.user_data.underline_ns =
@@ -1565,7 +1557,6 @@ M.handlers.virtual_text = {
return
end
- local severity --- @type vim.diagnostic.SeverityFilter?
if opts.virtual_text then
if opts.virtual_text.format then
diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics)
@@ -1576,9 +1567,6 @@ M.handlers.virtual_text = {
then
diagnostics = prefix_source(diagnostics)
end
- if opts.virtual_text.severity then
- severity = opts.virtual_text.severity
- end
end
local ns = M.get_namespace(namespace)
@@ -1590,9 +1578,6 @@ M.handlers.virtual_text = {
local virt_text_ns = ns.user_data.virt_text_ns
local buffer_line_diagnostics = diagnostic_lines(diagnostics)
for line, line_diagnostics in pairs(buffer_line_diagnostics) do
- if severity then
- line_diagnostics = filter_by_severity(severity, line_diagnostics)
- end
local virt_texts = M._get_virt_text_chunks(line_diagnostics, opts.virtual_text)
if virt_texts then
@@ -1797,7 +1782,8 @@ function M.show(namespace, bufnr, diagnostics, opts)
for handler_name, handler in pairs(M.handlers) do
if handler.show and opts_res[handler_name] then
- handler.show(namespace, bufnr, diagnostics, opts_res)
+ local filtered = filter_by_severity(opts_res[handler_name].severity, diagnostics)
+ handler.show(namespace, bufnr, filtered, opts_res)
end
end
end
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index dee1bd88ca..1960bca52b 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -1574,6 +1574,11 @@ local filename = {
['.gitmodules'] = 'gitconfig',
['.gitattributes'] = 'gitattributes',
['.gitignore'] = 'gitignore',
+ ['.ignore'] = 'gitignore',
+ ['.dockerignore'] = 'gitignore',
+ ['.npmignore'] = 'gitignore',
+ ['.rgignore'] = 'gitignore',
+ ['.vscodeignore'] = 'gitignore',
['gitolite.conf'] = 'gitolite',
['git-rebase-todo'] = 'gitrebase',
gkrellmrc = 'gkrellmrc',
@@ -2369,6 +2374,8 @@ local pattern = {
['%.html%.m4$'] = 'htmlm4',
['^JAM.*%.'] = starsetf('jam'),
['^Prl.*%.'] = starsetf('jam'),
+ ['^${HOME}/.*/Code/User/.*%.json$'] = 'jsonc',
+ ['^${HOME}/.*/VSCodium/User/.*%.json$'] = 'jsonc',
['%.properties_..$'] = 'jproperties',
['%.properties_.._..$'] = 'jproperties',
['%.properties_.._.._'] = starsetf('jproperties'),
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 2d989fdbac..30a9951f6a 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -757,7 +757,7 @@ function M.html(_, bufnr)
if
matchregex(
line,
- [[@\(if\|for\|defer\|switch\)\|\*\(ngIf\|ngFor\|ngSwitch\|ngTemplateOutlet\)\|ng-template\|ng-content\|{{.*}}]]
+ [[@\(if\|for\|defer\|switch\)\|\*\(ngIf\|ngFor\|ngSwitch\|ngTemplateOutlet\)\|ng-template\|ng-content]]
)
then
return 'htmlangular'
diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua
index 04a6e43db1..91e06688b3 100644
--- a/runtime/lua/vim/fs.lua
+++ b/runtime/lua/vim/fs.lua
@@ -741,4 +741,37 @@ function M.abspath(path)
return M.joinpath(cwd, path)
end
+--- Gets `target` path relative to `base`, or `nil` if `base` is not an ancestor.
+---
+--- Example:
+---
+--- ```lua
+--- vim.fs.relpath('/var', '/var/lib') -- 'lib'
+--- vim.fs.relpath('/var', '/usr/bin') -- nil
+--- ```
+---
+--- @param base string
+--- @param target string
+--- @param opts table? Reserved for future use
+--- @return string|nil
+function M.relpath(base, target, opts)
+ vim.validate('base', base, 'string')
+ vim.validate('target', target, 'string')
+ vim.validate('opts', opts, 'table', true)
+
+ base = vim.fs.normalize(vim.fs.abspath(base))
+ target = vim.fs.normalize(vim.fs.abspath(target))
+ if base == target then
+ return '.'
+ end
+
+ local prefix = ''
+ if iswin then
+ prefix, base = split_windows_path(base)
+ end
+ base = prefix .. base .. (base ~= '/' and '/' or '')
+
+ return vim.startswith(target, base) and target:sub(#base + 1) or nil
+end
+
return M
diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua
index 6dc902489f..ee376f3a11 100644
--- a/runtime/lua/vim/health.lua
+++ b/runtime/lua/vim/health.lua
@@ -11,18 +11,7 @@
--- <
--- Plugin authors are encouraged to write new healthchecks. |health-dev|
---
---- *g:health*
---- g:health This global variable controls the behavior and appearance of the
---- `health` floating window. It should be a dictionary containing the
---- following optional keys:
---- - `style`: string? Determines the display style of the `health` window.
---- Set to `'float'` to enable a floating window. Other
---- styles are not currently supported.
----
---- Example: >lua
---- vim.g.health = { style = 'float' }
----
---- Commands *health-commands*
+--- COMMANDS *health-commands*
---
--- *:che* *:checkhealth*
--- :che[ckhealth] Run all healthchecks.
@@ -50,6 +39,23 @@
--- :checkhealth vim*
--- <
---
+--- USAGE *health-usage*
+---
+--- Local mappings in the healthcheck buffer:
+---
+--- q Closes the window.
+---
+--- Global configuration:
+---
+--- *g:health*
+--- g:health Dictionary with the following optional keys:
+--- - `style` (`'float'|nil`) Set to "float" to display :checkhealth in
+--- a floating window instead of the default behavior.
+---
+--- Example: >lua
+--- vim.g.health = { style = 'float' }
+---
+--- --------------------------------------------------------------------------------
--- Create a healthcheck *health-dev*
---
--- Healthchecks are functions that check the user environment, configuration, or
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 5b92926a21..23f4e104d0 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -1389,7 +1389,7 @@ end
--- |LspAttach| autocommand. Example:
---
--- ```lua
---- vim.api.nvim_create_autocommand('LspAttach', {
+--- vim.api.nvim_create_autocmd('LspAttach', {
--- callback = function(args)
--- local client = vim.lsp.get_client_by_id(args.data.client_id)
--- if client:supports_method('textDocument/foldingRange') then
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index 5d11312c77..a99363d3d6 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -702,14 +702,14 @@ local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'err
---
--- @param ... string List to write to the buffer
local function err_message(...)
- local message = table.concat(vim.iter({ ... }):flatten():totable())
+ local chunks = { { table.concat({ ... }) } }
if vim.in_fast_event() then
vim.schedule(function()
- api.nvim_err_writeln(message)
+ vim.api.nvim_echo(chunks, true, { err = true })
api.nvim_command('redraw')
end)
else
- api.nvim_err_writeln(message)
+ vim.api.nvim_echo(chunks, true, { err = true })
api.nvim_command('redraw')
end
end
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 9a879d9f38..8c1f3f10d4 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -208,7 +208,7 @@ end
--- @param uri string
--- @param client_id? integer
---- @param diagnostics vim.Diagnostic[]
+--- @param diagnostics lsp.Diagnostic[]
--- @param is_pull boolean
local function handle_diagnostics(uri, client_id, diagnostics, is_pull)
local fname = vim.uri_to_fname(uri)
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 1945040bda..3779c342e8 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -582,9 +582,8 @@ NSC['window/showMessage'] = function(_, params, ctx)
if message_type == protocol.MessageType.Error then
err_message('LSP[', client_name, '] ', message)
else
- --- @type string
- local message_type_name = protocol.MessageType[message_type]
- api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message))
+ message = ('LSP[%s][%s] %s\n'):format(client_name, protocol.MessageType[message_type], message)
+ api.nvim_echo({ { message } }, true, { err = true })
end
return params
end
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 5cccb3321f..14633adf0c 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -879,8 +879,7 @@ function M.make_floating_popup_options(width, height, opts)
col = col + (opts.offset_x or 0),
height = height,
focusable = opts.focusable,
- relative = opts.relative == 'mouse' and 'mouse'
- or opts.relative == 'editor' and 'editor'
+ relative = (opts.relative == 'mouse' or opts.relative == 'editor') and opts.relative
or 'cursor',
style = 'minimal',
width = width,
@@ -1433,7 +1432,7 @@ function M._make_floating_popup_size(contents, opts)
if vim.tbl_isempty(line_widths) then
for _, line in ipairs(contents) do
local line_width = vim.fn.strdisplaywidth(line:gsub('%z', '\n'))
- height = height + math.ceil(line_width / wrap_at)
+ height = height + math.max(1, math.ceil(line_width / wrap_at))
end
else
for i = 1, #contents do
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 24c3f243e5..02b12490af 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -959,7 +959,7 @@ do
--- function vim.startswith(s, prefix)
--- vim.validate('s', s, 'string')
--- vim.validate('prefix', prefix, 'string')
- --- ...
+ --- -- ...
--- end
--- ```
---
@@ -979,7 +979,7 @@ do
--- age={age, 'number'},
--- hobbies={hobbies, 'table'},
--- }
- --- ...
+ --- -- ...
--- end
--- ```
---
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index 89dc4e289a..0269699dfd 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -61,8 +61,6 @@ function M._create_parser(bufnr, lang, opts)
{ on_bytes = bytes_cb, on_detach = detach_cb, on_reload = reload_cb, preview = true }
)
- self:parse()
-
return self
end
@@ -397,6 +395,8 @@ end
--- Note: By default, disables regex syntax highlighting, which may be required for some plugins.
--- In this case, add `vim.bo.syntax = 'on'` after the call to `start`.
---
+--- Note: By default, the highlighter parses code asynchronously, using a segment time of 3ms.
+---
--- Example:
---
--- ```lua
@@ -408,8 +408,8 @@ end
--- })
--- ```
---
----@param bufnr (integer|nil) Buffer to be highlighted (default: current buffer)
----@param lang (string|nil) Language of the parser (default: from buffer filetype)
+---@param bufnr integer? Buffer to be highlighted (default: current buffer)
+---@param lang string? Language of the parser (default: from buffer filetype)
function M.start(bufnr, lang)
bufnr = vim._resolve_bufnr(bufnr)
local parser = assert(M.get_parser(bufnr, lang, { error = false }))
diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua
index d16013eca2..2777241e9f 100644
--- a/runtime/lua/vim/treesitter/_fold.lua
+++ b/runtime/lua/vim/treesitter/_fold.lua
@@ -69,8 +69,8 @@ end
---@param info TS.FoldInfo
---@param srow integer?
---@param erow integer? 0-indexed, exclusive
----@param parse_injections? boolean
-local function compute_folds_levels(bufnr, info, srow, erow, parse_injections)
+---@param callback function?
+local function compute_folds_levels(bufnr, info, srow, erow, callback)
srow = srow or 0
erow = erow or api.nvim_buf_line_count(bufnr)
@@ -79,104 +79,112 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections)
return
end
- parser:parse(parse_injections and { srow, erow } or nil)
-
- local enter_counts = {} ---@type table<integer, integer>
- local leave_counts = {} ---@type table<integer, integer>
- local prev_start = -1
- local prev_stop = -1
-
- parser:for_each_tree(function(tree, ltree)
- local query = ts.query.get(ltree:lang(), 'folds')
- if not query then
+ parser:parse(nil, function(_, trees)
+ if not trees then
return
end
- -- Collect folds starting from srow - 1, because we should first subtract the folds that end at
- -- srow - 1 from the level of srow - 1 to get accurate level of srow.
- for _, match, metadata in query:iter_matches(tree:root(), bufnr, math.max(srow - 1, 0), erow) do
- for id, nodes in pairs(match) do
- if query.captures[id] == 'fold' then
- local range = ts.get_range(nodes[1], bufnr, metadata[id])
- local start, _, stop, stop_col = Range.unpack4(range)
-
- if #nodes > 1 then
- -- assumes nodes are ordered by range
- local end_range = ts.get_range(nodes[#nodes], bufnr, metadata[id])
- local _, _, end_stop, end_stop_col = Range.unpack4(end_range)
- stop = end_stop
- stop_col = end_stop_col
- end
+ local enter_counts = {} ---@type table<integer, integer>
+ local leave_counts = {} ---@type table<integer, integer>
+ local prev_start = -1
+ local prev_stop = -1
- if stop_col == 0 then
- stop = stop - 1
- end
+ parser:for_each_tree(function(tree, ltree)
+ local query = ts.query.get(ltree:lang(), 'folds')
+ if not query then
+ return
+ end
- local fold_length = stop - start + 1
-
- -- Fold only multiline nodes that are not exactly the same as previously met folds
- -- Checking against just the previously found fold is sufficient if nodes
- -- are returned in preorder or postorder when traversing tree
- if
- fold_length > vim.wo.foldminlines and not (start == prev_start and stop == prev_stop)
- then
- enter_counts[start + 1] = (enter_counts[start + 1] or 0) + 1
- leave_counts[stop + 1] = (leave_counts[stop + 1] or 0) + 1
- prev_start = start
- prev_stop = stop
+ -- Collect folds starting from srow - 1, because we should first subtract the folds that end at
+ -- srow - 1 from the level of srow - 1 to get accurate level of srow.
+ for _, match, metadata in query:iter_matches(tree:root(), bufnr, math.max(srow - 1, 0), erow) do
+ for id, nodes in pairs(match) do
+ if query.captures[id] == 'fold' then
+ local range = ts.get_range(nodes[1], bufnr, metadata[id])
+ local start, _, stop, stop_col = Range.unpack4(range)
+
+ if #nodes > 1 then
+ -- assumes nodes are ordered by range
+ local end_range = ts.get_range(nodes[#nodes], bufnr, metadata[id])
+ local _, _, end_stop, end_stop_col = Range.unpack4(end_range)
+ stop = end_stop
+ stop_col = end_stop_col
+ end
+
+ if stop_col == 0 then
+ stop = stop - 1
+ end
+
+ local fold_length = stop - start + 1
+
+ -- Fold only multiline nodes that are not exactly the same as previously met folds
+ -- Checking against just the previously found fold is sufficient if nodes
+ -- are returned in preorder or postorder when traversing tree
+ if
+ fold_length > vim.wo.foldminlines and not (start == prev_start and stop == prev_stop)
+ then
+ enter_counts[start + 1] = (enter_counts[start + 1] or 0) + 1
+ leave_counts[stop + 1] = (leave_counts[stop + 1] or 0) + 1
+ prev_start = start
+ prev_stop = stop
+ end
end
end
end
- end
- end)
+ end)
- local nestmax = vim.wo.foldnestmax
- local level0_prev = info.levels0[srow] or 0
- local leave_prev = leave_counts[srow] or 0
-
- -- We now have the list of fold opening and closing, fill the gaps and mark where fold start
- for lnum = srow + 1, erow do
- local enter_line = enter_counts[lnum] or 0
- local leave_line = leave_counts[lnum] or 0
- local level0 = level0_prev - leave_prev + enter_line
-
- -- Determine if it's the start/end of a fold
- -- NB: vim's fold-expr interface does not have a mechanism to indicate that
- -- two (or more) folds start at this line, so it cannot distinguish between
- -- ( \n ( \n )) \n (( \n ) \n )
- -- versus
- -- ( \n ( \n ) \n ( \n ) \n )
- -- Both are represented by ['>1', '>2', '2', '>2', '2', '1'], and
- -- vim interprets as the second case.
- -- If it did have such a mechanism, (clamped - clamped_prev)
- -- would be the correct number of starts to pass on.
- local adjusted = level0 ---@type integer
- local prefix = ''
- if enter_line > 0 then
- prefix = '>'
- if leave_line > 0 then
- -- If this line ends a fold f1 and starts a fold f2, then move f1's end to the previous line
- -- so that f2 gets the correct level on this line. This may reduce the size of f1 below
- -- foldminlines, but we don't handle it for simplicity.
- adjusted = level0 - leave_line
- leave_line = 0
+ local nestmax = vim.wo.foldnestmax
+ local level0_prev = info.levels0[srow] or 0
+ local leave_prev = leave_counts[srow] or 0
+
+ -- We now have the list of fold opening and closing, fill the gaps and mark where fold start
+ for lnum = srow + 1, erow do
+ local enter_line = enter_counts[lnum] or 0
+ local leave_line = leave_counts[lnum] or 0
+ local level0 = level0_prev - leave_prev + enter_line
+
+ -- Determine if it's the start/end of a fold
+ -- NB: vim's fold-expr interface does not have a mechanism to indicate that
+ -- two (or more) folds start at this line, so it cannot distinguish between
+ -- ( \n ( \n )) \n (( \n ) \n )
+ -- versus
+ -- ( \n ( \n ) \n ( \n ) \n )
+ -- Both are represented by ['>1', '>2', '2', '>2', '2', '1'], and
+ -- vim interprets as the second case.
+ -- If it did have such a mechanism, (clamped - clamped_prev)
+ -- would be the correct number of starts to pass on.
+ local adjusted = level0 ---@type integer
+ local prefix = ''
+ if enter_line > 0 then
+ prefix = '>'
+ if leave_line > 0 then
+ -- If this line ends a fold f1 and starts a fold f2, then move f1's end to the previous line
+ -- so that f2 gets the correct level on this line. This may reduce the size of f1 below
+ -- foldminlines, but we don't handle it for simplicity.
+ adjusted = level0 - leave_line
+ leave_line = 0
+ end
end
- end
- -- Clamp at foldnestmax.
- local clamped = adjusted
- if adjusted > nestmax then
- prefix = ''
- clamped = nestmax
- end
+ -- Clamp at foldnestmax.
+ local clamped = adjusted
+ if adjusted > nestmax then
+ prefix = ''
+ clamped = nestmax
+ end
- -- Record the "real" level, so that it can be used as "base" of later compute_folds_levels().
- info.levels0[lnum] = adjusted
- info.levels[lnum] = prefix .. tostring(clamped)
+ -- Record the "real" level, so that it can be used as "base" of later compute_folds_levels().
+ info.levels0[lnum] = adjusted
+ info.levels[lnum] = prefix .. tostring(clamped)
- leave_prev = leave_line
- level0_prev = adjusted
- end
+ leave_prev = leave_line
+ level0_prev = adjusted
+ end
+
+ if callback then
+ callback()
+ end
+ end)
end
local M = {}
@@ -267,6 +275,8 @@ local function on_changedtree(bufnr, foldinfo, tree_changes)
schedule_if_loaded(bufnr, function()
local srow_upd, erow_upd ---@type integer?, integer?
local max_erow = api.nvim_buf_line_count(bufnr)
+ -- TODO(ribru17): Replace this with a proper .all() awaiter once #19624 is resolved
+ local iterations = 0
for _, change in ipairs(tree_changes) do
local srow, _, erow, ecol = Range.unpack4(change)
-- If a parser doesn't have any ranges explicitly set, treesitter will
@@ -280,12 +290,14 @@ local function on_changedtree(bufnr, foldinfo, tree_changes)
end
-- Start from `srow - foldminlines`, because this edit may have shrunken the fold below limit.
srow = math.max(srow - vim.wo.foldminlines, 0)
- compute_folds_levels(bufnr, foldinfo, srow, erow)
srow_upd = srow_upd and math.min(srow_upd, srow) or srow
erow_upd = erow_upd and math.max(erow_upd, erow) or erow
- end
- if #tree_changes > 0 then
- foldinfo:foldupdate(bufnr, srow_upd, erow_upd)
+ compute_folds_levels(bufnr, foldinfo, srow, erow, function()
+ iterations = iterations + 1
+ if iterations == #tree_changes then
+ foldinfo:foldupdate(bufnr, srow_upd, erow_upd)
+ end
+ end)
end
end)
end
@@ -343,8 +355,9 @@ local function on_bytes(bufnr, foldinfo, start_row, start_col, old_row, old_col,
foldinfo.on_bytes_range = nil
-- Start from `srow - foldminlines`, because this edit may have shrunken the fold below limit.
srow = math.max(srow - vim.wo.foldminlines, 0)
- compute_folds_levels(bufnr, foldinfo, srow, erow)
- foldinfo:foldupdate(bufnr, srow, erow)
+ compute_folds_levels(bufnr, foldinfo, srow, erow, function()
+ foldinfo:foldupdate(bufnr, srow, erow)
+ end)
end)
end
end
@@ -401,9 +414,10 @@ api.nvim_create_autocmd('OptionSet', {
for _, bufnr in ipairs(bufs) do
foldinfos[bufnr] = FoldInfo.new(bufnr)
api.nvim_buf_call(bufnr, function()
- compute_folds_levels(bufnr, foldinfos[bufnr])
+ compute_folds_levels(bufnr, foldinfos[bufnr], nil, nil, function()
+ foldinfos[bufnr]:foldupdate(bufnr, 0, api.nvim_buf_line_count(bufnr))
+ end)
end)
- foldinfos[bufnr]:foldupdate(bufnr, 0, api.nvim_buf_line_count(bufnr))
end
end,
})
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 96503c38ea..be138885d5 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -69,6 +69,7 @@ end
---@field private _queries table<string,vim.treesitter.highlighter.Query>
---@field tree vim.treesitter.LanguageTree
---@field private redraw_count integer
+---@field parsing boolean true if we are parsing asynchronously
local TSHighlighter = {
active = {},
}
@@ -147,8 +148,6 @@ function TSHighlighter.new(tree, opts)
vim.opt_local.spelloptions:append('noplainbuffer')
end)
- self.tree:parse()
-
return self
end
@@ -384,19 +383,23 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
end
---@private
----@param _win integer
---@param buf integer
---@param topline integer
---@param botline integer
-function TSHighlighter._on_win(_, _win, buf, topline, botline)
+function TSHighlighter._on_win(_, _, buf, topline, botline)
local self = TSHighlighter.active[buf]
- if not self then
+ if not self or self.parsing then
return false
end
- self.tree:parse({ topline, botline + 1 })
- self:prepare_highlight_states(topline, botline + 1)
+ self.parsing = self.tree:parse({ topline, botline + 1 }, function(_, trees)
+ if trees and self.parsing then
+ self.parsing = false
+ api.nvim__redraw({ buf = buf, valid = false, flush = false })
+ end
+ end) == nil
self.redraw_count = self.redraw_count + 1
- return true
+ self:prepare_highlight_states(topline, botline)
+ return #self._highlight_states > 0
end
api.nvim_set_decoration_provider(ns, {
diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua
index 446051dfd7..238a078703 100644
--- a/runtime/lua/vim/treesitter/language.lua
+++ b/runtime/lua/vim/treesitter/language.lua
@@ -133,8 +133,9 @@ function M.add(lang, opts)
path = paths[1]
end
- return loadparser(path, lang, symbol_name) or nil,
- string.format('Cannot load parser %s for language "%s"', path, lang)
+ local res = loadparser(path, lang, symbol_name)
+ return res,
+ res == nil and string.format('Cannot load parser %s for language "%s"', path, lang) or nil
end
--- @param x string|string[]
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 330eb45749..945a2301a9 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -44,6 +44,8 @@ local query = require('vim.treesitter.query')
local language = require('vim.treesitter.language')
local Range = require('vim.treesitter._range')
+local default_parse_timeout_ms = 3
+
---@alias TSCallbackName
---| 'changedtree'
---| 'bytes'
@@ -76,6 +78,10 @@ local TSCallbackNames = {
---@field private _injections_processed boolean
---@field private _opts table Options
---@field private _parser TSParser Parser for language
+---Table of regions for which the tree is currently running an async parse
+---@field private _ranges_being_parsed table<string, boolean>
+---Table of callback queues, keyed by each region for which the callbacks should be run
+---@field private _cb_queues table<string, fun(err?: string, trees?: table<integer, TSTree>)[]>
---@field private _has_regions boolean
---@field private _regions table<integer, Range6[]>?
---List of regions this tree should manage and parse. If nil then regions are
@@ -130,6 +136,8 @@ function LanguageTree.new(source, lang, opts)
_injections_processed = false,
_valid = false,
_parser = vim._create_ts_parser(lang),
+ _ranges_being_parsed = {},
+ _cb_queues = {},
_callbacks = {},
_callbacks_rec = {},
}
@@ -232,6 +240,7 @@ end
---@param reload boolean|nil
function LanguageTree:invalidate(reload)
self._valid = false
+ self._parser:reset()
-- buffer was reloaded, reparse all trees
if reload then
@@ -334,10 +343,12 @@ end
--- @private
--- @param range boolean|Range?
+--- @param timeout integer?
--- @return Range6[] changes
--- @return integer no_regions_parsed
--- @return number total_parse_time
-function LanguageTree:_parse_regions(range)
+--- @return boolean finished whether async parsing still needs time
+function LanguageTree:_parse_regions(range, timeout)
local changes = {}
local no_regions_parsed = 0
local total_parse_time = 0
@@ -357,9 +368,14 @@ function LanguageTree:_parse_regions(range)
)
then
self._parser:set_included_ranges(ranges)
+ self._parser:set_timeout(timeout and timeout * 1000 or 0) -- ms -> micros
local parse_time, tree, tree_changes =
tcall(self._parser.parse, self._parser, self._trees[i], self._source, true)
+ if not tree then
+ return changes, no_regions_parsed, total_parse_time, false
+ end
+
-- Pass ranges if this is an initial parse
local cb_changes = self._trees[i] and tree_changes or tree:included_ranges(true)
@@ -373,7 +389,7 @@ function LanguageTree:_parse_regions(range)
end
end
- return changes, no_regions_parsed, total_parse_time
+ return changes, no_regions_parsed, total_parse_time, true
end
--- @private
@@ -409,6 +425,82 @@ function LanguageTree:_add_injections()
return query_time
end
+--- @param range boolean|Range?
+--- @return string
+local function range_to_string(range)
+ return type(range) == 'table' and table.concat(range, ',') or tostring(range)
+end
+
+--- @private
+--- @param range boolean|Range?
+--- @param callback fun(err?: string, trees?: table<integer, TSTree>)
+function LanguageTree:_push_async_callback(range, callback)
+ local key = range_to_string(range)
+ self._cb_queues[key] = self._cb_queues[key] or {}
+ local queue = self._cb_queues[key]
+ queue[#queue + 1] = callback
+end
+
+--- @private
+--- @param range boolean|Range?
+--- @param err? string
+--- @param trees? table<integer, TSTree>
+function LanguageTree:_run_async_callbacks(range, err, trees)
+ local key = range_to_string(range)
+ for _, cb in ipairs(self._cb_queues[key]) do
+ cb(err, trees)
+ end
+ self._ranges_being_parsed[key] = false
+ self._cb_queues[key] = {}
+end
+
+--- Run an asynchronous parse, calling {on_parse} when complete.
+---
+--- @private
+--- @param range boolean|Range?
+--- @param on_parse fun(err?: string, trees?: table<integer, TSTree>)
+--- @return table<integer, TSTree>? trees the list of parsed trees, if parsing completed synchronously
+function LanguageTree:_async_parse(range, on_parse)
+ self:_push_async_callback(range, on_parse)
+
+ -- If we are already running an async parse, just queue the callback.
+ local range_string = range_to_string(range)
+ if not self._ranges_being_parsed[range_string] then
+ self._ranges_being_parsed[range_string] = true
+ else
+ return
+ end
+
+ local buf = vim.b[self._source]
+ local ct = buf.changedtick
+ local total_parse_time = 0
+ local redrawtime = vim.o.redrawtime
+ local timeout = not vim.g._ts_force_sync_parsing and default_parse_timeout_ms or nil
+
+ local function step()
+ -- If buffer was changed in the middle of parsing, reset parse state
+ if buf.changedtick ~= ct then
+ ct = buf.changedtick
+ total_parse_time = 0
+ end
+
+ local parse_time, trees, finished = tcall(self._parse, self, range, timeout)
+ total_parse_time = total_parse_time + parse_time
+
+ if finished then
+ self:_run_async_callbacks(range, nil, trees)
+ return trees
+ elseif total_parse_time > redrawtime then
+ self:_run_async_callbacks(range, 'TIMEOUT', nil)
+ return nil
+ else
+ vim.schedule(step)
+ end
+ end
+
+ return step()
+end
+
--- Recursively parse all regions in the language tree using |treesitter-parsers|
--- for the corresponding languages and run injection queries on the parsed trees
--- to determine whether child trees should be created and parsed.
@@ -420,11 +512,33 @@ 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 table<integer, TSTree>
-function LanguageTree:parse(range)
+--- @param on_parse fun(err?: string, trees?: table<integer, TSTree>)? Function invoked when parsing completes.
+--- When provided and `vim.g._ts_force_sync_parsing` is not set, parsing will run
+--- asynchronously. The first argument to the function is a string respresenting the error type,
+--- in case of a failure (currently only possible for timeouts). The second argument is the list
+--- of trees returned by the parse (upon success), or `nil` if the parse timed out (determined
+--- by 'redrawtime').
+---
+--- If parsing was still able to finish synchronously (within 3ms), `parse()` returns the list
+--- of trees. Otherwise, it returns `nil`.
+--- @return table<integer, TSTree>?
+function LanguageTree:parse(range, on_parse)
+ if on_parse then
+ return self:_async_parse(range, on_parse)
+ end
+ local trees, _ = self:_parse(range)
+ return trees
+end
+
+--- @private
+--- @param range boolean|Range|nil
+--- @param timeout integer?
+--- @return table<integer, TSTree> trees
+--- @return boolean finished
+function LanguageTree:_parse(range, timeout)
if self:is_valid() then
self:_log('valid')
- return self._trees
+ return self._trees, true
end
local changes --- @type Range6[]?
@@ -433,10 +547,15 @@ function LanguageTree:parse(range)
local no_regions_parsed = 0
local query_time = 0
local total_parse_time = 0
+ local is_finished --- @type boolean
-- At least 1 region is invalid
if not self:is_valid(true) then
- changes, no_regions_parsed, total_parse_time = self:_parse_regions(range)
+ changes, no_regions_parsed, total_parse_time, is_finished = self:_parse_regions(range, timeout)
+ timeout = timeout and math.max(timeout - total_parse_time, 0)
+ if not is_finished then
+ return self._trees, is_finished
+ end
-- Need to run injections when we parsed something
if no_regions_parsed > 0 then
self._injections_processed = false
@@ -457,10 +576,17 @@ function LanguageTree:parse(range)
})
for _, child in pairs(self._children) do
- child:parse(range)
+ if timeout == 0 then
+ return self._trees, false
+ end
+ local ctime, _, child_finished = tcall(child._parse, child, range, timeout)
+ timeout = timeout and math.max(timeout - ctime, 0)
+ if not child_finished then
+ return self._trees, child_finished
+ end
end
- return self._trees
+ return self._trees, true
end
--- Invokes the callback for each |LanguageTree| recursively.
@@ -907,6 +1033,7 @@ function LanguageTree:_edit(
)
end
+ self._parser:reset()
self._regions = nil
local changed_range = {
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 1fc001b39f..66ab0d52f0 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -262,6 +262,7 @@ local explicit_queries = setmetatable({}, {
---@param query_name string Name of the query (e.g., "highlights")
---@param text string Query text (unparsed).
function M.set(lang, query_name, text)
+ M.get:clear(lang, query_name)
explicit_queries[lang][query_name] = M.parse(lang, text)
end
@@ -284,7 +285,15 @@ M.get = memoize('concat-2', function(lang, query_name)
end
return M.parse(lang, query_string)
-end)
+end, false)
+
+api.nvim_create_autocmd('OptionSet', {
+ pattern = { 'runtimepath' },
+ group = api.nvim_create_augroup('ts_query_cache_reset', { clear = true }),
+ callback = function()
+ M.get:clear()
+ end,
+})
--- Parses a {query} string and returns a `Query` object (|lua-treesitter-query|), which can be used
--- to search the tree for the query patterns (via |Query:iter_captures()|, |Query:iter_matches()|),
@@ -292,7 +301,7 @@ end)
--- - `captures`: a list of unique capture names defined in the query (alias: `info.captures`).
--- - `info.patterns`: information about predicates.
---
---- Example (select the code then run `:'<,'>lua` to try it):
+--- Example (to try it, use `yxx` or select the code then run `:'<,'>lua`):
--- ```lua
--- local query = vim.treesitter.query.parse('vimdoc', [[
--- ; query
@@ -316,7 +325,7 @@ M.parse = memoize('concat-2', function(lang, query)
assert(language.add(lang))
local ts_query = vim._ts_parse_query(lang, query)
return Query.new(lang, ts_query)
-end)
+end, false)
--- Implementations of predicates that can optionally be prefixed with "any-".
---
@@ -904,8 +913,8 @@ end
---@param start? integer Starting line for the search. Defaults to `node:start()`.
---@param stop? integer Stopping line for the search (end-exclusive). Defaults to `node:end_()`.
---
----@return (fun(end_line: integer|nil): integer, TSNode, vim.treesitter.query.TSMetadata, TSQueryMatch):
---- capture id, capture node, metadata, match
+---@return (fun(end_line: integer|nil): integer, TSNode, vim.treesitter.query.TSMetadata, TSQueryMatch, TSTree):
+--- capture id, capture node, metadata, match, tree
---
---@note Captures are only returned if the query pattern of a specific capture contained predicates.
function Query:iter_captures(node, source, start, stop)
@@ -915,6 +924,8 @@ function Query:iter_captures(node, source, start, stop)
start, stop = value_or_node_range(start, stop, node)
+ -- Copy the tree to ensure it is valid during the entire lifetime of the iterator
+ local tree = node:tree():copy()
local cursor = vim._create_ts_querycursor(node, self.query, start, stop, { match_limit = 256 })
-- For faster checks that a match is not in the cache.
@@ -961,7 +972,7 @@ function Query:iter_captures(node, source, start, stop)
match_cache[match_id] = metadata
end
- return capture, captured_node, metadata, match
+ return capture, captured_node, metadata, match, tree
end
return iter
end
@@ -983,7 +994,7 @@ end
--- -- `node` was captured by the `name` capture in the match
---
--- local node_data = metadata[id] -- Node level metadata
---- ... use the info here ...
+--- -- ... use the info here ...
--- end
--- end
--- end
@@ -1002,7 +1013,7 @@ end
--- (last) node instead of the full list of matching nodes. This option is only for backward
--- compatibility and will be removed in a future release.
---
----@return (fun(): integer, table<integer, TSNode[]>, vim.treesitter.query.TSMetadata): pattern id, match, metadata
+---@return (fun(): integer, table<integer, TSNode[]>, vim.treesitter.query.TSMetadata, TSTree): pattern id, match, metadata, tree
function Query:iter_matches(node, source, start, stop, opts)
opts = opts or {}
opts.match_limit = opts.match_limit or 256
@@ -1013,6 +1024,8 @@ function Query:iter_matches(node, source, start, stop, opts)
start, stop = value_or_node_range(start, stop, node)
+ -- Copy the tree to ensure it is valid during the entire lifetime of the iterator
+ local tree = node:tree():copy()
local cursor = vim._create_ts_querycursor(node, self.query, start, stop, opts)
local function iter()
@@ -1050,7 +1063,7 @@ function Query:iter_matches(node, source, start, stop, opts)
end
-- TODO(lewis6991): create a new function that returns {match, metadata}
- return pattern_i, captures, metadata
+ return pattern_i, captures, metadata, tree
end
return iter
end
diff --git a/runtime/syntax/lyrics.vim b/runtime/syntax/lyrics.vim
index fd127988f2..48a5b1171c 100644
--- a/runtime/syntax/lyrics.vim
+++ b/runtime/syntax/lyrics.vim
@@ -2,7 +2,7 @@
" Language: LyRiCs
" Maintainer: ObserverOfTime <chronobserver@disroot.org>
" Filenames: *.lrc
-" Last Change: 2024 Sep 20
+" Last Change: 2025 Jan 13
if exists('b:current_syntax')
finish
@@ -23,7 +23,7 @@ syn match lrcTagName contained nextgroup=lrcTagValue
syn match lrcTagValue /:\zs.\+\ze\]/ contained
" Lyrics
-syn match lrcLyricTime /^\s*\(\[\d\d:\d\d\.\d\d\]\)\+/
+syn match lrcLyricTime /^\s*\(\[\d\d:\d\d\.\d\d\d\?\]\)\+/
\ contains=lrcNumber nextgroup=lrcLyricLine
syn match lrcLyricLine /.*$/ contained contains=lrcWordTime,@Spell
syn match lrcWordTime /<\d\d:\d\d\.\d\d>/ contained contains=lrcNumber,@NoSpell
diff --git a/runtime/syntax/tiasm.vim b/runtime/syntax/tiasm.vim
index bdadc4a0a7..c79596bdfe 100644
--- a/runtime/syntax/tiasm.vim
+++ b/runtime/syntax/tiasm.vim
@@ -99,4 +99,4 @@ hi def link tiasmIdentifier Identifier
hi def link tiasmType Type
hi def link tiasmFunction Function
-let b:current_syntax = "lineartiasm"
+let b:current_syntax = "tiasm"
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 12798201e2..edc69b907c 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -553,19 +553,21 @@ syn region vimPatSepZone oneline contained matchgroup=vimPatSepZ start="\\%\
syn region vimPatRegion contained transparent matchgroup=vimPatSepR start="\\[z%]\=(" end="\\)" contains=@vimSubstList oneline
syn match vimNotPatSep contained "\\\\"
syn cluster vimStringGroup contains=vimEscape,vimEscapeBrace,vimPatSep,vimNotPatSep,vimPatSepErr,vimPatSepZone,@Spell
-syn region vimString oneline keepend start=+[^a-zA-Z>\\@]"+lc=1 skip=+\\\\\|\\"+ matchgroup=vimStringEnd end=+"+ contains=@vimStringGroup extend
-syn region vimString oneline keepend start=+[^a-zA-Z>\\@]'+lc=1 end=+'+ extend
+syn region vimString oneline keepend matchgroup=vimString start=+[^a-zA-Z>\\@]"+lc=1 skip=+\\\\\|\\"+ matchgroup=vimStringEnd end=+"+ contains=@vimStringGroup extend
+syn region vimString oneline matchgroup=vimString start=+[^a-zA-Z>\\@]'+lc=1 end=+'+ contains=vimQuoteEscape extend
"syn region vimString oneline start="\s/\s*\A"lc=1 skip="\\\\\|\\+" end="/" contains=@vimStringGroup " see tst45.vim
syn match vimString contained +"[^"]*\\$+ skipnl nextgroup=vimStringCont
syn match vimStringCont contained +\(\\\\\|.\)\{-}[^\\]"+
+
syn match vimEscape contained "\\."
" syn match vimEscape contained +\\[befnrt\"]+
syn match vimEscape contained "\\\o\{1,3}\|\\[xX]\x\{1,2}\|\\u\x\{1,4}\|\\U\x\{1,8}"
syn match vimEscape contained "\\<" contains=vimNotation
syn match vimEscape contained "\\<\*[^>]*>\=>"
+syn match vimQuoteEscape contained "''"
-syn region vimString oneline start=+$'+ skip=+''+ end=+'+ contains=@vimStringInterpolation extend
-syn region vimString oneline start=+$"+ end=+"+ contains=@vimStringGroup,@vimStringInterpolation extend
+syn region vimString oneline matchgroup=vimString start=+$'+ skip=+''+ end=+'+ contains=vimQuoteEscape,@vimStringInterpolation extend
+syn region vimString oneline matchgroup=vimString start=+$"+ end=+"+ contains=@vimStringGroup,@vimStringInterpolation extend
syn region vimStringInterpolationExpr oneline contained matchgroup=vimSep start=+{+ end=+}+ contains=@vimExprList
syn match vimStringInterpolationBrace contained "{{"
syn match vimStringInterpolationBrace contained "}}"
@@ -1399,6 +1401,7 @@ if !exists("skip_vim_syntax_inits")
hi def link vimPattern Type
hi def link vimPlainMark vimMark
hi def link vimPlainRegister vimRegister
+ hi def link vimQuoteEscape vimEscape
hi def link vimRegister SpecialChar
hi def link vimScriptDelim Comment
hi def link vimSearchDelim Statement