commit 7838c242e96c4f6c6432a997234bb2dbdbfea658
parent 07d0da64ed51202f0dbd92d43c89aa5f246b175e
Author: Justin M. Keyes <justinkz@gmail.com>
Date: Tue, 14 Oct 2025 19:22:03 -0400
docs: types, news, lua-plugin
- mention "lua_ls", not "luals". https://github.com/neovim/neovim/discussions/36182
Co-authored-by: Maria Solano <majosolano99@gmail.com>
Diffstat:
13 files changed, 106 insertions(+), 52 deletions(-)
diff --git a/runtime/doc/dev_arch.txt b/runtime/doc/dev_arch.txt
@@ -25,8 +25,28 @@ Use `kvec.h` for most lists. When you absolutely need a linked list, use
`lib/queue_defs.h` which defines an "intrusive" linked list.
==============================================================================
+Events
+
+All new events must be implemented using `aucmd_defer()` (and where possible,
+old events should be migrated to this), so that they are processed in
+a predictable manner, which avoids crashes and race conditions. See
+`do_markset_autocmd` for an example.
+
+==============================================================================
UI events
+The long-term vision is that UI events are just another type of "editor event"
+(formerly known as "autocmds"). There is no real reason that we have separate
+types of user-facing or plugin-facing events. Events are events. Their
+"transport" is irrelevant and any event should be possible to emit over any
+transport (editor or RPC).
+
+Meanwhile the current situation is that UI events are a particular RPC event
+packaged in a generic `redraw` notification. They also can be listened to
+in-process via |vim.ui_attach()|.
+
+UI events are deferred to UIs, which implies a deepcopy of the UI event data.
+
The source files most directly involved with UI events are:
1. `src/nvim/ui.*`: calls handler functions of registered UI structs (independent from msgpack-rpc)
2. `src/nvim/api/ui.*`: forwards messages over msgpack-rpc to remote UIs.
@@ -38,12 +58,8 @@ functions used by the source files above. It also generates metadata
accessible as `api_info().ui_events`.
See commit d3a8e9217f39c59dd7762bd22a76b8bd03ca85ff for an example of adding
-a new UI event.
-
-UI events are deferred to UIs, which implies a deepcopy of the UI event data.
-
-Remember to bump NVIM_API_LEVEL if it wasn't already during this development
-cycle.
+a new UI event. Remember to bump NVIM_API_LEVEL if it wasn't already during
+this development cycle.
Other references:
- |msgpack-rpc|
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
@@ -475,6 +475,7 @@ everywhere, not "buffer" in some places and "buf" in others.
- chan: |channel|
- cmd: Command
- cmdline: Command-line UI or input
+ - dir: Directory
- fn: Function
- hl: Highlight
- pos: Position
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
@@ -87,6 +87,9 @@ g CTRL-G Prints the current position of the cursor in five
If the buffer did have a name, that name becomes the
|alternate-file| name. An unlisted buffer is created
to hold the old name.
+
+ See |nvim_buf_set_name()| to avoid filename escaping.
+
*:0file*
:0f[ile][!] Remove the name of the current buffer. The optional !
avoids truncating the message, as with |:file|.
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
@@ -30,7 +30,7 @@ Follow these steps to get LSP features:
2. Define a new config |lsp-new-config| (or install https://github.com/neovim/nvim-lspconfig).
Example: >lua
- vim.lsp.config['luals'] = {
+ vim.lsp.config['lua_ls'] = {
-- Command and arguments to start the server.
cmd = { 'lua-language-server' },
-- Filetypes to automatically attach to.
@@ -52,7 +52,7 @@ Follow these steps to get LSP features:
3. Use |vim.lsp.enable()| to enable the config.
Example: >lua
- vim.lsp.enable('luals')
+ vim.lsp.enable('lua_ls')
<
4. Open a code file matching one of the `filetypes` specified in the config.
Note: Depending on the LSP server, you may need to ensure your project has
@@ -997,8 +997,8 @@ config({name}, {cfg}) *vim.lsp.config()*
filetypes = { 'c', 'cpp' },
}
<
- • Get the resolved configuration for "luals": >lua
- local cfg = vim.lsp.config.luals
+ • Get the resolved configuration for "lua_ls": >lua
+ local cfg = vim.lsp.config.lua_ls
<
Attributes: ~
@@ -1014,7 +1014,7 @@ enable({name}, {enable}) *vim.lsp.enable()*
Examples: >lua
vim.lsp.enable('clangd')
- vim.lsp.enable({'luals', 'pyright'})
+ vim.lsp.enable({'lua_ls', 'pyright'})
<
Example: *lsp-restart* Passing `false` stops and detaches the client(s).
@@ -1689,12 +1689,12 @@ Lua module: vim.lsp.client *lsp-client*
Fields: ~
• {before_init}? (`fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)`)
- Callback invoked before the LSP "initialize"
- phase, where `params` contains the parameters
- being sent to the server and `config` is the
- config that was passed to |vim.lsp.start()|.
- You can use this to modify parameters before
- they are sent.
+ Callback which can modify parameters before
+ they are sent to the server. Invoked before LSP
+ "initialize" phase (after `cmd` is invoked),
+ where `params` is the parameters being sent to
+ the server and `config` is the config passed to
+ |vim.lsp.start()|.
• {capabilities}? (`lsp.ClientCapabilities`) Map overriding the
default capabilities defined by
|vim.lsp.protocol.make_client_capabilities()|,
diff --git a/runtime/doc/lua-plugin.txt b/runtime/doc/lua-plugin.txt
@@ -217,6 +217,11 @@ Consider making use of 'filetype' for any functionality that is specific to
a filetype, by putting the initialization logic in a `ftplugin/{filetype}.lua`
script.
+For buffers owned by your plugin (often used to show a custom UI or view),
+typically your plugin will set a custom 'filetype'. In that case, it's useful
+to set the 'filetype' "as late as possible", so that users can override
+buffer-local settings after your plugin has (re)initialized the buffer.
+
FILETYPE EXAMPLE
A plugin tailored to Rust development might have initialization in
@@ -240,6 +245,10 @@ A plugin tailored to Rust development might have initialization in
==============================================================================
Configuration *lua-plugin-config*
+To allow users to override buffer-local configuration for filetypes owned by
+your plugin, publish a |FileType| event, "as late as possible".
+|lua-plugin-filetype|
+
Once you have merged the default configuration with the user's config, you
should validate configs.
@@ -251,6 +260,32 @@ Validations could include:
check, to reduce overhead.
==============================================================================
+UI *lua-plugin-ui*
+
+Some plugins have their own "UI" which they present in a buffer that the
+plugin "owns". In that buffer typically you will want to provide custom
+actions.
+
+Besides creating |<Plug>| mappings, you may want to consider providing actions
+by defining an in-process LSP server. Offering actions as code-actions
+|vim.lsp.buf.code_action()| means the user can see all available actions using
+the default |gra| mapping to view the code-actions menu. They can even define
+mappings to a specific action by invoking `vim.lsp.buf.code_action()` with the
+`filter` + `apply` parameters: >lua
+
+ vim.lsp.buf.code_action({
+ apply = true,
+ filter = function(a)
+ return a.title == 'Do something'
+ end,
+ })
+<
+
+Example: See `runtime/lua/vim/pack/_lsp.lua` for how vim.pack defines an
+in-process LSP server to provide interactive features in its `nvim-pack://`
+buffer.
+
+==============================================================================
Troubleshooting *lua-plugin-troubleshooting*
While developing a plugin, you can use the |:restart| command to see the
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
@@ -1710,7 +1710,7 @@ vim.is_callable({f}) *vim.is_callable()*
Returns true if object `f` can be called as a function.
Parameters: ~
- • {f} (`any`) Any object
+ • {f} (`any?`) Any object
Return: ~
(`boolean`) `true` if `f` is callable, else `false`
@@ -1727,7 +1727,7 @@ vim.isarray({t}) *vim.isarray()*
|rpcrequest()| or |vim.fn|.
Parameters: ~
- • {t} (`table?`)
+ • {t} (`any?`)
Return: ~
(`boolean`) `true` if array-like table, else `false`.
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
@@ -80,7 +80,6 @@ EVENTS
message UI that mimics the legacy message grid. Benefit: reduced UI event
traffic and more flexibility for UIs.
The `msg_history_show` event has an additional "prev_cmd" argument.
-• A new `empty` message kind is emitted for an empty (e.g. `:echo ""`) message.
HIGHLIGHTS
@@ -88,12 +87,11 @@ HIGHLIGHTS
LSP
-• `root_markers` in |vim.lsp.Config| can now be ordered by priority.
+• JSON "null" values in LSP messages are represented as |vim.NIL| instead of `nil`.
+ Missing fields (as opposed to JSON "null") are still represented as `nil`.
• The function set with |vim.lsp.log.set_format_func()| is now given all
arguments corresponding to a log entry instead of the individual arguments.
-• `vim.lsp.semantic_tokens.start/stop` now renamed to
- `vim.lsp.semantic_tokens.enable`
-• Missing fields in LSP messages are now represented using |vim.NIL| instead of nil.
+• Renamed `vim.lsp.semantic_tokens` `start()/stop()` to `enable()`.
• |vim.lsp.util.convert_signature_help_to_markdown_lines()| activeParameter
handling updated:
• Values < 0 are now treated as `nil` instead of 0.
@@ -103,7 +101,6 @@ LSP
LUA
• Renamed `vim.diff` to `vim.text.diff`.
-• |vim.net.request()| adds a minimal HTTP GET API using curl.
OPTIONS
@@ -120,7 +117,6 @@ TREESITTER
`metadata[capture_id].offset`. The offset will be applied in
|vim.treesitter.get_range()|, which should be preferred over reading
metadata directly for retrieving node ranges.
-• |Query:iter_captures()| supports specifying starting and ending columns.
TUI
@@ -203,6 +199,7 @@ EDITOR
EVENTS
+• A new `empty` message kind is emitted for an empty (e.g. `:echo ""`) message.
• |CmdlineLeave| sets |v:char| to the character that stops the Cmdline mode.
• |CmdlineLeavePre| triggered before preparing to leave the command line.
• New `append` parameter for |ui-messages| `msg_show` event.
@@ -220,7 +217,7 @@ HIGHLIGHTS
LSP
• |vim.lsp.ClientConfig| gained `workspace_required`.
-• You can control priority of |vim.lsp.Config| `root_markers`.
+• You can control the priority of |vim.lsp.Config| `root_markers`.
• Support for `textDocument/documentColor`: |lsp-document_color|
https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentColor
• Support for `textDocument/colorPresentation |lsp-document_color|
@@ -261,6 +258,7 @@ LSP
LUA
+• |vim.net.request()| can fetch files via HTTP GET requests.
• |vim.wait()| returns the callback results.
• Lua type annotations for `vim.uv`.
• |vim.hl.range()| now allows multiple timed highlights.
@@ -330,6 +328,7 @@ TERMINAL
TREESITTER
+• |Query:iter_captures()| supports specifying starting and ending columns.
• |:EditQuery| command gained tab-completion, works with injected languages.
TUI
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
@@ -301,9 +301,9 @@ end
--- filetypes = { 'c', 'cpp' },
--- }
--- ```
---- - Get the resolved configuration for "luals":
+--- - Get the resolved configuration for "lua_ls":
--- ```lua
---- local cfg = vim.lsp.config.luals
+--- local cfg = vim.lsp.config.lua_ls
--- ```
---
---@since 13
@@ -522,7 +522,7 @@ end
---
--- ```lua
--- vim.lsp.enable('clangd')
---- vim.lsp.enable({'luals', 'pyright'})
+--- vim.lsp.enable({'lua_ls', 'pyright'})
--- ```
---
--- Example: [lsp-restart]() Passing `false` stops and detaches the client(s). Thus you can
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
@@ -34,9 +34,9 @@ local all_clients = {}
--- @class vim.lsp.ClientConfig
---
---- Callback invoked before the LSP "initialize" phase, where `params` contains the parameters
---- being sent to the server and `config` is the config that was passed to |vim.lsp.start()|.
---- You can use this to modify parameters before they are sent.
+--- Callback which can modify parameters before they are sent to the server. Invoked before LSP
+--- "initialize" phase (after `cmd` is invoked), where `params` is the parameters being sent to the
+--- server and `config` is the config passed to |vim.lsp.start()|.
--- @field before_init? fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)
---
--- Map overriding the default capabilities defined by |vim.lsp.protocol.make_client_capabilities()|,
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
@@ -826,7 +826,7 @@ end
---
---@see https://github.com/openresty/luajit2#tableisarray
---
----@param t? table
+---@param t? any
---@return boolean `true` if array-like table, else `false`.
function vim.isarray(t)
if type(t) ~= 'table' then
@@ -1246,7 +1246,7 @@ end
--- Returns true if object `f` can be called as a function.
---
----@param f any Any object
+---@param f? any Any object
---@return boolean `true` if `f` is callable, else `false`
function vim.is_callable(f)
if type(f) == 'function' then
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
@@ -135,7 +135,7 @@ char *server_address_new(const char *name)
return xstrdup(fmt);
}
-/// Check if this instance owns a pipe address.
+/// Check if this instance owns a pipe address (loopback).
bool server_owns_pipe_address(const char *address)
{
bool result = false;
diff --git a/src/nvim/path.c b/src/nvim/path.c
@@ -46,8 +46,7 @@ enum {
/// Compare two file names.
///
-/// @param s1 First file name. Environment variables in this name will be
-/// expanded.
+/// @param s1 First file name. Environment variables in this name will be expanded.
/// @param s2 Second file name.
/// @param checkname When both files don't exist, only compare their names.
/// @param expandenv Whether to expand environment variables in file names.
@@ -540,7 +539,6 @@ bool path_has_wildcard(const char *p)
return false;
}
-// Unix style wildcard expansion code.
static int pstrcmp(const void *a, const void *b)
{
return pathcmp(*(char **)a, *(char **)b, -1);
@@ -1956,8 +1954,10 @@ bool same_directory(char *f1, char *f2)
}
// Compare path "p[]" to "q[]".
-// If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]"
+// If `maxlen` >= 0 compare `p[maxlen]` to `q[maxlen]`
// Return value like strcmp(p, q), but consider path separators.
+//
+// See also `path_full_compare`.
int pathcmp(const char *p, const char *q, int maxlen)
{
int i, j;
@@ -2314,12 +2314,12 @@ int append_path(char *path, const char *to_append, size_t max_len)
return OK;
}
-/// Expand a given file to its absolute path.
+/// Used by `vim_FullName` and `fix_fname` to expand a filename to its full path.
///
-/// @param fname filename which should be expanded.
-/// @param buf buffer to store the absolute path of "fname".
-/// @param len length of "buf".
-/// @param force also expand when "fname" is already absolute.
+/// @param fname Filename to expand.
+/// @param buf Where to store the absolute path of "fname".
+/// @param len Length of `buf`.
+/// @param force Also expand when `fname` is already absolute.
///
/// @return FAIL for failure, OK for success.
static int path_to_absolute(const char *fname, char *buf, size_t len, int force)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
@@ -4616,7 +4616,7 @@ describe('API', function()
},
}, api.nvim_parse_cmd('4,6MyCommand! test it', {}))
end)
- it('works for commands separated by bar', function()
+ it('sets nextcmd for bar-separated commands', function()
eq({
cmd = 'argadd',
args = { 'a.txt' },
@@ -4655,6 +4655,12 @@ describe('API', function()
},
}, api.nvim_parse_cmd('argadd a.txt | argadd b.txt', {}))
end)
+ it('sets nextcmd after expr-arg commands #36029', function()
+ local result = api.nvim_parse_cmd('exe "ls"|edit foo', {})
+ eq({ '"ls"' }, result.args)
+ eq('execute', result.cmd)
+ eq('edit foo', result.nextcmd)
+ end)
it('parses :map commands with space in RHS', function()
eq({
addr = 'none',
@@ -4849,12 +4855,6 @@ describe('API', function()
result = api.nvim_parse_cmd('copen 5', {})
eq(5, result.count)
end)
- it('parses nextcmd for commands #36029', function()
- local result = api.nvim_parse_cmd('exe "ls"|edit foo', {})
- eq({ '"ls"' }, result.args)
- eq('execute', result.cmd)
- eq('edit foo', result.nextcmd)
- end)
end)
describe('nvim_cmd', function()