summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2026-04-14 06:09:54 -0400
committerJustin M. Keyes <justinkz@gmail.com>2026-04-14 13:27:29 +0200
commitccba8a8f2d566373cccb6b1b1b68d05c368bf323 (patch)
treee17ed01815e52c2ce4b329e046cdaf9b25456e01
parent53038d2c381e79fcb2ba9c7c5b2e637e3db76f6a (diff)
docs: lsp, options, api
- revert bogus change to `_meta/builtin_types.lua` from 3a4a66017b74 Co-authored-by: David Mejorado <david.mejorado@gmail.com>
-rw-r--r--.github/scripts/labeler_configuration.yml16
-rw-r--r--runtime/doc/api.txt18
-rw-r--r--runtime/doc/lsp.txt96
-rw-r--r--runtime/doc/message.txt3
-rw-r--r--runtime/doc/options.txt18
-rw-r--r--runtime/lua/vim/_meta/api.gen.lua16
-rw-r--r--runtime/lua/vim/_meta/builtin_types.lua6
-rw-r--r--runtime/lua/vim/_meta/options.gen.lua18
-rw-r--r--runtime/lua/vim/lsp.lua2
-rw-r--r--runtime/lua/vim/lsp/_changetracking.lua4
-rw-r--r--runtime/lua/vim/lsp/client.lua8
-rw-r--r--runtime/lua/vim/lsp/util.lua6
-rw-r--r--src/nvim/api/vim.c16
-rw-r--r--src/nvim/options.lua18
14 files changed, 152 insertions, 93 deletions
diff --git a/.github/scripts/labeler_configuration.yml b/.github/scripts/labeler_configuration.yml
index 7469468cb1..eea63a41eb 100644
--- a/.github/scripts/labeler_configuration.yml
+++ b/.github/scripts/labeler_configuration.yml
@@ -2,10 +2,6 @@ build:
- changed-files:
- any-glob-to-any-file: [ CMakeLists.txt, "**/CMakeLists.txt", "**/Makefile", "**/*.cmake", cmake.deps/**/* ]
-checkhealth:
- - changed-files:
- - any-glob-to-any-file: [ "**/health.lua" ]
-
ci:
- changed-files:
- any-glob-to-any-file: [ .github/actions/**, .github/workflows/**, .github/scripts/** ]
@@ -38,10 +34,6 @@ documentation:
- changed-files:
- any-glob-to-all-files: [ runtime/doc/*, "**/*.md" ]
-editorconfig:
- - changed-files:
- - any-glob-to-any-file: [ .editorconfig, runtime/lua/editorconfig.lua, runtime/plugin/editorconfig.lua ]
-
filetype:
- changed-files:
- any-glob-to-any-file: [ runtime/lua/vim/filetype.lua, runtime/lua/vim/filetype/detect.lua ]
@@ -66,6 +58,10 @@ netrw:
- changed-files:
- any-glob-to-any-file: [ runtime/autoload/netrw.vim, runtime/plugin/netrwPlugin.vim ]
+plugin-editorconfig:
+ - changed-files:
+ - any-glob-to-any-file: [ .editorconfig, runtime/lua/editorconfig.lua, runtime/plugin/editorconfig.lua ]
+
snippet:
- changed-files:
- any-glob-to-any-file: [ runtime/lua/vim/snippet.lua ]
@@ -89,3 +85,7 @@ treesitter:
tui:
- changed-files:
- any-glob-to-any-file: [ src/nvim/tui/tui.* ]
+
+ux-visibility:
+ - changed-files:
+ - any-glob-to-any-file: [ "**/health.lua" ]
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 710db79e0c..851368dd7f 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1530,13 +1530,11 @@ nvim_set_current_win({window}) *nvim_set_current_win()*
• {window} (`integer`) |window-ID| to focus
nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()*
- Sets a highlight group.
+ Sets a highlight group. By default, replaces the entire definition (e.g.
+ `nvim_set_hl(0, 'Visual', {})` will clear the "Visual" group), unless
+ `update` is specified.
Note: ~
- • Unlike the `:highlight` command which can update a highlight group,
- this function completely replaces the definition. For example:
- `nvim_set_hl(0, 'Visual', {})` will clear the highlight group
- 'Visual'.
• The fg and bg keys also accept the string values `"fg"` or `"bg"`
which act as aliases to the corresponding foreground and background
values of the Normal group. If the Normal group has not been defined,
@@ -1573,19 +1571,19 @@ nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()*
• default: boolean Don't override existing definition
|:hi-default|
• dim: boolean
- • fg: color name or "#RRGGBB", see note.
+ • fg: Color name or "#RRGGBB", see note.
• fg_indexed: boolean (default false) If true, fg is a
terminal palette index (0-255).
- • force: if true force update the highlight group when it
- exists.
+ • force: boolean (default false) Update the highlight group
+ even if it already exists.
• italic: boolean
• link: Name of highlight group to link to. |:hi-link|
• link_global: Like "link", but always resolved in the global
- (ns=0) namespace.
+ namespace (ns=0).
• nocombine: boolean
• overline: boolean
• reverse: boolean
- • sp: color name or "#RRGGBB"
+ • sp: Color name or "#RRGGBB"
• standout: boolean
• strikethrough: boolean
• undercurl: boolean
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 31e2e1432f..1f0a770d45 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -357,13 +357,16 @@ FAQ *lsp-faq*
================================================================================
LSP API *lsp-api*
-The |lsp-core| API provides core functions for creating and managing clients.
-The |lsp-buf| functions perform operations for LSP clients attached to the
-current buffer.
+The |lsp-core| API provides core functions for creating and managing clients,
+You can even create creating custom (in-process) |lsp-server|s.
+The |lsp-buf| functions operate LSP clients attached to the current buffer.
+
+------------------------------------------------------------------------------
+CONCEPTS
*lsp-method*
Requests and notifications defined by the LSP specification are referred to as
-"LSP methods". These are handled by Lua |lsp-handler| functions.
+"LSP methods". These are handled by |lsp-handler| functions.
*lsp-handler*
LSP handlers are functions that handle |lsp-response|s to requests made by Nvim
@@ -453,7 +456,8 @@ Handlers can be set by (in increasing priority):
Log levels are defined in |vim.log.levels|
-VIM.LSP.PROTOCOL *vim.lsp.protocol*
+------------------------------------------------------------------------------
+PROTOCOL *vim.lsp.protocol*
Module `vim.lsp.protocol` defines constants dictated by the LSP specification,
and helper functions for creating protocol-related objects.
@@ -485,6 +489,70 @@ LSP notification shape: >
<
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#notificationMessage
+------------------------------------------------------------------------------
+IN-PROCESS LSP SERVER *lsp-server*
+
+For maximum flexibility you may want to create your own server. This allows
+you to hook into Nvim LSP features automatically. The "server" can be an
+in-process Lua function instead of an external process. For example see
+`runtime/lua/vim/pack/_lsp.lua` which provides features like "docs
+hover" in the vim.pack "Confirm Updates" UI.
+
+This is possible because |vim.lsp.start()| accepts `cmd` as a Lua function.
+The function must accept `vim.lsp.rpc.Dispatchers` and return a table in the
+form of |vim.lsp.rpc.PublicClient|. Use `dispatchers.on_exit()` to signal that
+the server has stopped.
+
+Example (select and run the code with `:lua`, then check `:che vim.lsp` and
+look for "my-server"): >lua
+
+ local function cmd_fn(dispatchers)
+ local closing = false
+ local request_id = 0
+
+ local srv = {}
+ function srv.request(method, params, callback)
+ if method == 'initialize' then
+ callback(nil, {
+ capabilities = {
+ hoverProvider = true,
+ },
+ })
+ elseif method == 'shutdown' then
+ callback(nil, nil)
+ end
+ request_id = request_id + 1
+ return true, request_id
+ end
+ function srv.notify(method, params)
+ if method == 'exit' then
+ dispatchers.on_exit(0, 15)
+ end
+ end
+ function srv.is_closing()
+ return closing
+ end
+ function srv.terminate()
+ closing = true
+ end
+
+ return srv
+ end
+
+ -- Define a config for the server, then enable it...
+ vim.lsp.config['my-server'] = {
+ cmd = cmd_fn,
+ filetypes = { 'lua' },
+ root_markers = { '.git' },
+ }
+ vim.lsp.enable('my-server')
+
+ -- ...or call start() directly.
+ vim.lsp.start(
+ { cmd = cmd_fn, name = 'my-server', root_dir = vim.uv.cwd() },
+ { attach = true })
+<
+
================================================================================
LSP HIGHLIGHT *lsp-highlight*
@@ -1252,7 +1320,7 @@ start({config}, {opts}) *vim.lsp.start()*
are:
• `name` arbitrary name for the LSP client. Should be unique per language
server.
- • `cmd` command string[] or function.
+ • `cmd` command string[] or function. See also |lsp-server|.
• `root_dir` path to the project root. By default this is used to decide
if an existing client should be re-used. The example above uses
|vim.fs.root()| to detect the root by traversing the file system upwards
@@ -1757,14 +1825,14 @@ Lua module: vim.lsp.client *lsp-client*
server (treated as in |jobstart()|, must be
absolute or on `$PATH`, shell constructs like
"~" are not expanded), or function that creates
- an RPC client. Function receives a
- `dispatchers` table and the resolved `config`,
- and must return a table with member functions
- `request`, `notify`, `is_closing` and
- `terminate`. See |vim.lsp.rpc.request()|,
- |vim.lsp.rpc.notify()|. For TCP there is a
- builtin RPC client factory:
- |vim.lsp.rpc.connect()|
+ an RPC client (or an in-process |lsp-server|).
+ Function receives a `dispatchers` table and the
+ resolved `config`, and must return an object in
+ the form of |vim.lsp.rpc.PublicClient|.
+ • See |vim.lsp.rpc.request()|
+ |vim.lsp.rpc.notify()|
+ • For TCP there is a builtin RPC client
+ factory: |vim.lsp.rpc.connect()|
• {cmd_cwd}? (`string`, default: cwd) Directory to launch
the `cmd` process. Not related to `root_dir`.
• {cmd_env}? (`table`) Environment variables passed to the
diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt
index 9cfc21e391..f25fe45633 100644
--- a/runtime/doc/message.txt
+++ b/runtime/doc/message.txt
@@ -896,8 +896,9 @@ Events: ~
Example: >lua
local progress = {
kind = 'progress',
- status = 'running',
percent = 10,
+ source = 'my-plugin',
+ status = 'running',
title = 'term',
}
progress.id = vim.api.nvim_echo({ { 'searching...' } }, true, progress)
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 400c0a4d77..34ff9f3c13 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -3202,15 +3202,15 @@ A jump table for the options with a short description can be found at |Q_op|.
'formatprg' 'fp' string (default "")
global or local to buffer |global-local|
Disallowed in |modeline|. |no-modeline-option|
- The name of an external program that will be used to format the lines
- selected with the |gq| operator. The program must take the input on
- stdin and produce the output on stdout. The Unix program "fmt" is
- such a program.
- If the 'formatexpr' option is not empty it will be used instead.
- Otherwise, if 'formatprg' option is an empty string, the internal
- format function will be used |C-indenting|.
- Environment variables are expanded |:set_env|. See |option-backslash|
- about including spaces and backslashes.
+ External program used to format lines with |gq|. Ignored if
+ 'formatexpr' is set.
+
+ If empty, the internal |C-indenting| function will be used.
+
+ The program must take input on stdin and produce output on stdout. The
+ Unix program "fmt" is such a program. Environment variables are
+ expanded |:set_env|. See |option-backslash| about including spaces
+ and backslashes.
*'fsync'* *'fs'* *'nofsync'* *'nofs'*
'fsync' 'fs' boolean (default on)
diff --git a/runtime/lua/vim/_meta/api.gen.lua b/runtime/lua/vim/_meta/api.gen.lua
index 2cc2322f48..1a2bfa4f97 100644
--- a/runtime/lua/vim/_meta/api.gen.lua
+++ b/runtime/lua/vim/_meta/api.gen.lua
@@ -2204,14 +2204,10 @@ function vim.api.nvim_set_current_win(window) end
--- ```
function vim.api.nvim_set_decoration_provider(ns_id, opts) end
---- Sets a highlight group.
+--- Sets a highlight group. By default, replaces the entire definition (e.g. `nvim_set_hl(0, 'Visual', {})`
+--- will clear the "Visual" group), unless `update` is specified.
---
--- Note:
---- Unlike the `:highlight` command which can update a highlight group,
---- this function completely replaces the definition. For example:
---- `nvim_set_hl(0, 'Visual', {})` will clear the highlight group
---- 'Visual'.
----
--- The fg and bg keys also accept the string values `"fg"` or `"bg"`
--- which act as aliases to the corresponding foreground and background
--- values of the Normal group. If the Normal group has not been defined,
@@ -2240,16 +2236,16 @@ function vim.api.nvim_set_decoration_provider(ns_id, opts) end
--- - ctermfg: Sets foreground of cterm color `ctermfg`
--- - default: boolean Don't override existing definition `:hi-default`
--- - dim: boolean
---- - fg: color name or "#RRGGBB", see note.
+--- - fg: Color name or "#RRGGBB", see note.
--- - fg_indexed: boolean (default false) If true, fg is a terminal palette index (0-255).
---- - force: if true force update the highlight group when it exists.
+--- - force: boolean (default false) Update the highlight group even if it already exists.
--- - italic: boolean
--- - link: Name of highlight group to link to. `:hi-link`
---- - link_global: Like "link", but always resolved in the global (ns=0) namespace.
+--- - link_global: Like "link", but always resolved in the global namespace (ns=0).
--- - nocombine: boolean
--- - overline: boolean
--- - reverse: boolean
---- - sp: color name or "#RRGGBB"
+--- - sp: Color name or "#RRGGBB"
--- - standout: boolean
--- - strikethrough: boolean
--- - undercurl: boolean
diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua
index d7081a7454..1754853182 100644
--- a/runtime/lua/vim/_meta/builtin_types.lua
+++ b/runtime/lua/vim/_meta/builtin_types.lua
@@ -201,7 +201,7 @@ error('Cannot require a meta file')
--- @field priority? integer
--- @class vim.fn.sign_placelist.list.item
---- @field buf integer|string
+--- @field buffer integer|string
--- @field group? string
--- @field id? integer
--- @field lnum? integer|string
@@ -209,11 +209,11 @@ error('Cannot require a meta file')
--- @field priority? integer
--- @class vim.fn.sign_unplace.dict
---- @field buf? integer|string
+--- @field buffer? integer|string
--- @field id? integer
--- @class vim.fn.sign_unplacelist.list.item
---- @field buf? integer|string
+--- @field buffer? integer|string
--- @field group? string
--- @field id? integer
diff --git a/runtime/lua/vim/_meta/options.gen.lua b/runtime/lua/vim/_meta/options.gen.lua
index cb60dd0f0e..74221e9a04 100644
--- a/runtime/lua/vim/_meta/options.gen.lua
+++ b/runtime/lua/vim/_meta/options.gen.lua
@@ -2956,15 +2956,15 @@ vim.o.fo = vim.o.formatoptions
vim.bo.formatoptions = vim.o.formatoptions
vim.bo.fo = vim.bo.formatoptions
---- The name of an external program that will be used to format the lines
---- selected with the `gq` operator. The program must take the input on
---- stdin and produce the output on stdout. The Unix program "fmt" is
---- such a program.
---- If the 'formatexpr' option is not empty it will be used instead.
---- Otherwise, if 'formatprg' option is an empty string, the internal
---- format function will be used `C-indenting`.
---- Environment variables are expanded `:set_env`. See `option-backslash`
---- about including spaces and backslashes.
+--- External program used to format lines with `gq`. Ignored if
+--- 'formatexpr' is set.
+---
+--- If empty, the internal `C-indenting` function will be used.
+---
+--- The program must take input on stdin and produce output on stdout. The
+--- Unix program "fmt" is such a program. Environment variables are
+--- expanded `:set_env`. See `option-backslash` about including spaces
+--- and backslashes.
---
--- @type string
vim.o.formatprg = ""
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 11e6bca4d2..1869f1a106 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -702,7 +702,7 @@ end
--- See |vim.lsp.ClientConfig| for all available options. The most important are:
---
--- - `name` arbitrary name for the LSP client. Should be unique per language server.
---- - `cmd` command string[] or function.
+--- - `cmd` command string[] or function. See also |lsp-server|.
--- - `root_dir` path to the project root. By default this is used to decide if an existing client
--- should be re-used. The example above uses |vim.fs.root()| to detect the root by traversing
--- the file system upwards starting from the current directory until either a `pyproject.toml`
diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua
index 8e5a17ac05..bf8000f6c0 100644
--- a/runtime/lua/vim/lsp/_changetracking.lua
+++ b/runtime/lua/vim/lsp/_changetracking.lua
@@ -165,9 +165,12 @@ function M.init(client, bufnr)
end
end
+--- Sends didOpen/didClose/didSave to all client groups.
+---
--- @param bufnr integer
function M._send_did_save(bufnr)
local groups = {} ---@type table<string,vim.lsp.CTGroup>
+ -- Collect all client groups.
for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do
local group = get_group(client)
groups[group_key(group)] = group
@@ -176,6 +179,7 @@ function M._send_did_save(bufnr)
local uri = vim.uri_from_bufnr(bufnr)
local text = vim.func._memoize('concat', vim.lsp._buf_get_full_text)
+ -- Send didOpen/didClose/didSave to all client groups.
for _, group in pairs(groups) do
local name = api.nvim_buf_get_name(bufnr)
local state = state_by_group[group]
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index a8f6dbbe4d..6603f18212 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -51,10 +51,10 @@ local all_clients = {}
---
--- Command `string[]` that launches the language server (treated as in |jobstart()|, must be
--- absolute or on `$PATH`, shell constructs like "~" are not expanded), or function that creates an
---- RPC client. Function receives a `dispatchers` table and the resolved `config`, and must return
---- a table with member functions `request`, `notify`, `is_closing` and `terminate`.
---- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|.
---- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
+--- RPC client (or an in-process |lsp-server|). Function receives a `dispatchers` table and the
+--- resolved `config`, and must return an object in the form of |vim.lsp.rpc.PublicClient|.
+--- - See |vim.lsp.rpc.request()| |vim.lsp.rpc.notify()|
+--- - For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient
---
--- Directory to launch the `cmd` process. Not related to `root_dir`.
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 71bc86d8c2..340cfb8239 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1050,11 +1050,7 @@ function M.show_document(location, position_encoding, opts)
if vim.api.nvim_get_mode().mode == 'i' then
local line = api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] or ''
if col >= #line then
- vim.api.nvim_feedkeys(
- vim.api.nvim_replace_termcodes('<End>', true, false, true),
- 'n',
- false
- )
+ vim.api.nvim_feedkeys(vim.keycode('<End>'), 'n', false)
end
end
end
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 2d63965b94..3b33441c58 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -120,12 +120,8 @@ DictAs(get_hl_info) nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena
return ns_get_hl_defs((NS)ns_id, opts, arena, err);
}
-/// Sets a highlight group.
-///
-/// @note Unlike the `:highlight` command which can update a highlight group,
-/// this function completely replaces the definition. For example:
-/// `nvim_set_hl(0, 'Visual', {})` will clear the highlight group
-/// 'Visual'.
+/// Sets a highlight group. By default, replaces the entire definition (e.g. `nvim_set_hl(0, 'Visual', {})`
+/// will clear the "Visual" group), unless `update` is specified.
///
/// @note The fg and bg keys also accept the string values `"fg"` or `"bg"`
/// which act as aliases to the corresponding foreground and background
@@ -154,16 +150,16 @@ DictAs(get_hl_info) nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena
/// - ctermfg: Sets foreground of cterm color |ctermfg|
/// - default: boolean Don't override existing definition |:hi-default|
/// - dim: boolean
-/// - fg: color name or "#RRGGBB", see note.
+/// - fg: Color name or "#RRGGBB", see note.
/// - fg_indexed: boolean (default false) If true, fg is a terminal palette index (0-255).
-/// - force: if true force update the highlight group when it exists.
+/// - force: boolean (default false) Update the highlight group even if it already exists.
/// - italic: boolean
/// - link: Name of highlight group to link to. |:hi-link|
-/// - link_global: Like "link", but always resolved in the global (ns=0) namespace.
+/// - link_global: Like "link", but always resolved in the global namespace (ns=0).
/// - nocombine: boolean
/// - overline: boolean
/// - reverse: boolean
-/// - sp: color name or "#RRGGBB"
+/// - sp: Color name or "#RRGGBB"
/// - standout: boolean
/// - strikethrough: boolean
/// - undercurl: boolean
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 8ee3102a46..f871df51af 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -3758,15 +3758,15 @@ local options = {
abbreviation = 'fp',
defaults = '',
desc = [=[
- The name of an external program that will be used to format the lines
- selected with the |gq| operator. The program must take the input on
- stdin and produce the output on stdout. The Unix program "fmt" is
- such a program.
- If the 'formatexpr' option is not empty it will be used instead.
- Otherwise, if 'formatprg' option is an empty string, the internal
- format function will be used |C-indenting|.
- Environment variables are expanded |:set_env|. See |option-backslash|
- about including spaces and backslashes.
+ External program used to format lines with |gq|. Ignored if
+ 'formatexpr' is set.
+
+ If empty, the internal |C-indenting| function will be used.
+
+ The program must take input on stdin and produce output on stdout. The
+ Unix program "fmt" is such a program. Environment variables are
+ expanded |:set_env|. See |option-backslash| about including spaces
+ and backslashes.
]=],
expand = true,
full_name = 'formatprg',