Compare commits

...

18 Commits

Author SHA1 Message Date
James 8a78915089
Merge 77c10671ed into 435dee74bb 2024-04-26 22:44:53 -05:00
zeertzjq 435dee74bb
vim-patch:9.1.0374: wrong botline in BufEnter (#28530)
Problem:  When :edit an existing buffer, line('w$') may return a
          wrong result.
Solution: Reset w_valid in curwin_init() (Jaehwang Jung)

`do_ecmd()` reinitializes the current window (`curwin_init()`) whose
`w_valid` field may have `VALID_BOTLINE` set. Resetting `w_botline`
without marking it as invalid makes subsequent `validate_botline()`
calls a no-op, thus resulting in wrong `line('w$')` value.

closes: vim/vim#14642

eb80b8304e

Co-authored-by: Jaehwang Jung <tomtomjhj@gmail.com>
2024-04-27 06:32:25 +08:00
zeertzjq 694756252b
Merge pull request #28529 from zeertzjq/vim-fe1e2b5e2d65
vim-patch: clarify syntax vs matching mechanism
2024-04-27 06:31:55 +08:00
zeertzjq e81eb34aa1 vim-patch:9525f6213604
runtime(doc): fix typo synconcealend -> synconcealed (vim/vim#14644)

9525f62136

Co-authored-by: Philip H <47042125+pheiduck@users.noreply.github.com>
2024-04-27 05:52:47 +08:00
zeertzjq a1568f5df0 vim-patch:00ae5c5cba7b
runtime(doc): fix typo

00ae5c5cba

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-04-27 05:52:15 +08:00
zeertzjq f1f5fb911b vim-patch:fe1e2b5e2d65
runtime(doc): clarify syntax vs matching mechanism

fixes: vim/vim#14643

fe1e2b5e2d

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-04-27 05:51:52 +08:00
Mathias Fußenegger 9b8a075539
fix(lsp): change `silent` in lsp.start.Opts to optional (#28524) 2024-04-26 20:26:21 +02:00
Gregory Anders 73034611c2
feat(diagnostic): add default mappings for diagnostics (#16230) 2024-04-26 13:16:12 -05:00
Brian Cao 3a7c30dc93
fix(man.vim): q quits after jump to different tag in MANPAGER modified (#28495) 2024-04-26 13:14:45 -05:00
Gregory Anders 6888607415
feat(lsp): add more LSP defaults (#28500)
- crn for rename
- crr for code actions
- gr for references
- <C-S> (in Insert mode) for signature help
2024-04-26 11:12:49 -05:00
Justin M. Keyes 9b028bd64f
refactor(vim.iter)!: rename xxback() => rxx() #28503
Problem:
vim.iter has both `rfind()` and various `*back()` methods, which work
in "reverse" or "backwards" order. It's inconsistent to have both kinds
of names, and "back" is fairly uncommon (rust) compared to python
(rfind, rstrip, rsplit, …).

Solution:
- Remove `nthback()` and let `nth()` take a negative index.
  - Because `rnth()` looks pretty obscure, and because it's intuitive
    for a function named `nth()` to take negative indexes.
- Rename `xxback()` methods to `rxx()`.
  - This informally groups the "list-iterator" functions under a common
    `r` prefix, which helps discoverability.
- Rename `peekback()` to `pop()`, in duality with the existing `peek`.
2024-04-26 08:43:29 -07:00
Lewis Russell b2c26a875b fix(lsp): ensure buffer is not attached more than once
Fixes regression introduced in #28030

If an LSP server is restarted, then the associated `nvim_buf_attach`
call will not detach if no buffer changes are sent between the client
stopping and a new one being created. This leads to `nvim_buf_attach`
being called multiple times for the same buffer, which then leads to
changetracking sending duplicate requests to the server (one per
attach).

To solve this, introduce separate tracking (client agnostic) on which
buffers have had calls to `nvim_buf_attach`.
2024-04-26 16:21:37 +01:00
Lewis Russell b8273c9a33 fix: lua annotations 2024-04-26 15:13:06 +01:00
TheLeoP c5b9fb2f25 fix(treesitter.foldexpr): check for all insert submodes 2024-04-26 15:07:10 +01:00
Gregory Anders 37d8e50459
fix(lsp): add "silent" option to vim.lsp.start (#28478)
vim.notify cannot be suppressed and it is not always necessary to
display a visible warning to the user if the RPC process fails to start.
For instance, a user may have the same LSP configuration across systems,
some of which may not have all of the LSP server executables installed.
In that case, the user receives a notification every time a file is
opened that they cannot suppress.

Instead of using vim.notify in vim.lsp.rpc, propagate a normal error up
through the call stack and use vim.notify in vim.lsp.start() only if
the "silent" option is not set.

This also updates lsp.start_client() to return an error message as its
second return value if an error occurred, rather than calling vim.notify
directly. Callers of lsp.start_client() will need to update call sites
appropriately if they wish to report errors to the user (or even better,
switch to vim.lsp.start).
2024-04-26 08:15:44 -05:00
Yi Ming 567f8a300b
refactor(lsp): rename foos_by_bar to bar_foos #28505 2024-04-26 04:25:55 -07:00
Mathias Fußenegger 47dbda97d2
fix(lsp): buffer messages until connected to server (#28507)
`handle:write(msg)` can fail if the socket is not yet connected to the
server.

Should address https://github.com/neovim/neovim/pull/28398#issuecomment-2078152491
2024-04-26 09:57:59 +02:00
James Tirta Halim 77c10671ed refactor: use libc stp[n]cpy 2024-04-18 20:07:56 +07:00
40 changed files with 764 additions and 619 deletions

View File

@ -49,6 +49,8 @@ endif()
check_function_exists(fseeko HAVE_FSEEKO)
check_function_exists(readv HAVE_READV)
check_function_exists(readlink HAVE_READLINK)
check_function_exists(stpcpy HAVE_STPCPY)
check_function_exists(stpncpy HAVE_STPNCPY)
check_function_exists(strnlen HAVE_STRNLEN)
check_function_exists(strcasecmp HAVE_STRCASECMP)
check_function_exists(strncasecmp HAVE_STRNCASECMP)

View File

@ -8208,6 +8208,10 @@ synconcealed({lnum}, {col}) *synconcealed()*
synconcealed(lnum, 5) [1, 'X', 2]
synconcealed(lnum, 6) [0, '', 0]
Note: Doesn't consider |matchadd()| highlighting items,
since syntax and matching highlighting are two different
mechanisms |syntax-vs-match|.
synstack({lnum}, {col}) *synstack()*
Return a |List|, which is the stack of syntax items at the
position {lnum} and {col} in the current window. {lnum} is

View File

@ -281,6 +281,10 @@ gr{char} Replace the virtual characters under the cursor with
that have a special meaning in Insert mode, such as
most CTRL-keys, cannot be used.
*gr-default*
Mapped to |vim.lsp.buf.references()| by default.
|default-mappings|
*digraph-arg*
The argument for Normal mode commands like |r| and |t| is a single character.
When 'cpo' doesn't contain the 'D' flag, this character can also be entered

View File

@ -61,47 +61,41 @@ options are not restored when the LSP client is stopped or detached.
- |K| is mapped to |vim.lsp.buf.hover()| unless |'keywordprg'| is customized or
a custom keymap for `K` exists.
*crr* *v_crr* *crn* *i_CTRL-S*
Some keymaps are created unconditionally when Nvim starts:
- "crn" is mapped in Normal mode to |vim.lsp.buf.rename()|
- "crr" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()|
- "gr" is mapped in Normal mode to |vim.lsp.buf.references()| |gr-default|
- CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()|
If not wanted, these keymaps can be removed at any time using
|vim.keymap.del()| or |:unmap|.
*lsp-defaults-disable*
To override the above defaults, set or unset the options on |LspAttach|: >lua
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(ev)
vim.bo[ev.buf].formatexpr = nil
vim.bo[ev.buf].omnifunc = nil
vim.keymap.del("n", "K", { buffer = ev.buf })
vim.keymap.del('n', 'K', { buffer = ev.buf })
end,
})
To use other LSP features like hover, rename, etc. you can set other keymaps
on |LspAttach|. Example: >lua
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = args.buf })
end,
})
To use other LSP features, set keymaps on |LspAttach|. Not all language
servers provide the same capabilities. To ensure you only set keymaps if the
language server supports a feature, guard keymaps behind capability checks.
Example: >lua
The most common functions are:
- |vim.lsp.buf.hover()|
- |vim.lsp.buf.format()|
- |vim.lsp.buf.references()|
- |vim.lsp.buf.implementation()|
- |vim.lsp.buf.code_action()|
Not all language servers provide the same capabilities. To ensure you only set
keymaps if the language server supports a feature, you can guard the keymap
calls behind capability checks:
>lua
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if client.server_capabilities.hoverProvider then
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = args.buf })
if client.supports_method('textDocument/implementation') then
vim.keymap.set('n', 'g<C-I>', vim.lsp.buf.implementation, { buffer = args.buf })
end
end,
})
<
To learn what capabilities are available you can run the following command in
a buffer with a started LSP client: >vim
@ -869,12 +863,14 @@ start({config}, {opts}) *vim.lsp.start()*
|vim.lsp.ClientConfig|.
• {opts} (`table?`) Optional keyword arguments
• {reuse_client}
(`fun(client: vim.lsp.Client, config: table): boolean`)
(`fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean`)
Predicate used to decide if a client should be re-used.
Used on all running clients. The default implementation
re-uses a client if name and root_dir matches.
• {bufnr} (`integer`) Buffer handle to attach to if starting
or re-using a client (0 for current).
• {silent}? (`boolean`) Suppress error reporting if the LSP
server fails to start (default false).
Return: ~
(`integer?`) client_id
@ -886,10 +882,11 @@ start_client({config}) *vim.lsp.start_client()*
• {config} (`vim.lsp.ClientConfig`) Configuration for the server. See
|vim.lsp.ClientConfig|.
Return: ~
Return (multiple): ~
(`integer?`) client_id |vim.lsp.get_client_by_id()| Note: client may
not be fully initialized. Use `on_init` to do any actions once the
client has been initialized.
(`string?`) Error message, if any
status() *vim.lsp.status()*
Consumes the latest progress messages from all clients and formats them as
@ -1073,7 +1070,7 @@ Lua module: vim.lsp.client *lsp-client*
*vim.lsp.ClientConfig*
Fields: ~
• {cmd} (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient?`)
• {cmd} (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
command string[] that launches the language
server (treated as in |jobstart()|, must be
absolute or on `$PATH`, shell constructs like
@ -2340,7 +2337,7 @@ start({cmd}, {dispatchers}, {extra_spawn_params}) *vim.lsp.rpc.start()*
See |vim.system()|
Return: ~
(`vim.lsp.rpc.PublicClient?`) Client RPC object, with these methods:
(`vim.lsp.rpc.PublicClient`) Client RPC object, with these methods:
• `notify()` |vim.lsp.rpc.notify()|
• `request()` |vim.lsp.rpc.request()|
• `is_closing()` returns a boolean indicating if the RPC is closing.

View File

@ -678,44 +678,47 @@ vim.diff({a}, {b}, {opts}) *vim.diff()*
Parameters: ~
• {a} (`string`) First string to compare
• {b} (`string`) Second string to compare
• {opts} (`table<string,any>`) Optional parameters:
• `on_hunk` (callback): Invoked for each hunk in the diff.
Return a negative number to cancel the callback for any
remaining hunks. Args:
• `start_a` (integer): Start line of hunk in {a}.
• `count_a` (integer): Hunk size in {a}.
• `start_b` (integer): Start line of hunk in {b}.
• `count_b` (integer): Hunk size in {b}.
• `result_type` (string): Form of the returned diff:
• "unified": (default) String in unified format.
• "indices": Array of hunk locations. Note: This option is
• {opts} (`table`) Optional parameters:
• {on_hunk}
(`fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer`)
Invoked for each hunk in the diff. Return a negative number
to cancel the callback for any remaining hunks. Arguments:
• `start_a` (`integer`): Start line of hunk in {a}.
• `count_a` (`integer`): Hunk size in {a}.
• `start_b` (`integer`): Start line of hunk in {b}.
• `count_b` (`integer`): Hunk size in {b}.
• {result_type} (`'unified'|'indices'`, default: `'unified'`)
Form of the returned diff:
• `unified`: String in unified format.
• `indices`: Array of hunk locations. Note: This option is
ignored if `on_hunk` is used.
• `linematch` (boolean|integer): Run linematch on the
{linematch} (`boolean|integer`) Run linematch on the
resulting hunks from xdiff. When integer, only hunks upto
this size in lines are run through linematch. Requires
`result_type = indices`, ignored otherwise.
• `algorithm` (string): Diff algorithm to use. Values:
• "myers" the default algorithm
• "minimal" spend extra time to generate the smallest
• {algorithm} (`'myers'|'minimal'|'patience'|'histogram'`,
default: `'myers'`) Diff algorithm to use. Values:
• `myers`: the default algorithm
• `minimal`: spend extra time to generate the smallest
possible diff
"patience" patience diff algorithm
"histogram" histogram diff algorithm
`ctxlen` (integer): Context length
`interhunkctxlen` (integer): Inter hunk context length
`ignore_whitespace` (boolean): Ignore whitespace
`ignore_whitespace_change` (boolean): Ignore whitespace
`patience`: patience diff algorithm
`histogram`: histogram diff algorithm
{ctxlen} (`integer`) Context length
{interhunkctxlen} (`integer`) Inter hunk context length
{ignore_whitespace} (`boolean`) Ignore whitespace
{ignore_whitespace_change} (`boolean`) Ignore whitespace
change
`ignore_whitespace_change_at_eol` (boolean) Ignore
{ignore_whitespace_change_at_eol} (`boolean`) Ignore
whitespace change at end-of-line.
`ignore_cr_at_eol` (boolean) Ignore carriage return at
{ignore_cr_at_eol} (`boolean`) Ignore carriage return at
end-of-line
`ignore_blank_lines` (boolean) Ignore blank lines
`indent_heuristic` (boolean): Use the indent heuristic for
{ignore_blank_lines} (`boolean`) Ignore blank lines
{indent_heuristic} (`boolean`) Use the indent heuristic for
the internal diff library.
Return: ~
(`string|table?`) See {opts.result_type}. `nil` if {opts.on_hunk} is
given.
(`string|integer[]`) See {opts.result_type}. `nil` if {opts.on_hunk}
is given.
==============================================================================
@ -829,8 +832,8 @@ vim.spell.check({str}) *vim.spell.check()*
• {str} (`string`)
Return: ~
(`{[1]: string, [2]: string, [3]: string}[]`) List of tuples with
three items:
(`{[1]: string, [2]: 'bad'|'rare'|'local'|'caps', [3]: integer}[]`)
List of tuples with three items:
• The badly spelled word.
• The type of the spelling error: "bad" spelling mistake "rare" rare
word "local" word only valid in another region "caps" word should
@ -911,7 +914,7 @@ vim.empty_dict() *vim.empty_dict()*
Return: ~
(`table`)
vim.iconv({str}, {from}, {to}, {opts}) *vim.iconv()*
vim.iconv({str}, {from}, {to}) *vim.iconv()*
The result is a String, which is the text {str} converted from encoding
{from} to encoding {to}. When the conversion fails `nil` is returned. When
some characters could not be converted they are replaced with "?". The
@ -920,9 +923,8 @@ vim.iconv({str}, {from}, {to}, {opts}) *vim.iconv()*
Parameters: ~
• {str} (`string`) Text to convert
• {from} (`number`) Encoding of {str}
• {to} (`number`) Target encoding
• {opts} (`table<string,any>?`)
• {from} (`string`) Encoding of {str}
• {to} (`string`) Target encoding
Return: ~
(`string?`) Converted string if conversion succeeds, `nil` otherwise.
@ -962,7 +964,7 @@ vim.schedule({fn}) *vim.schedule()*
|textlock| or other temporary restrictions.
Parameters: ~
• {fn} (`function`)
• {fn} (`fun()`)
vim.str_byteindex({str}, {index}, {use_utf16}) *vim.str_byteindex()*
Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not
@ -974,8 +976,8 @@ vim.str_byteindex({str}, {index}, {use_utf16}) *vim.str_byteindex()*
Parameters: ~
• {str} (`string`)
• {index} (`number`)
• {use_utf16} (`any?`)
• {index} (`integer`)
• {use_utf16} (`boolean?`)
vim.str_utf_end({str}, {index}) *vim.str_utf_end()*
Gets the distance (in bytes) from the last byte of the codepoint
@ -993,10 +995,10 @@ vim.str_utf_end({str}, {index}) *vim.str_utf_end()*
Parameters: ~
• {str} (`string`)
• {index} (`number`)
• {index} (`integer`)
Return: ~
(`number`)
(`integer`)
vim.str_utf_pos({str}) *vim.str_utf_pos()*
Gets a list of the starting byte positions of each UTF-8 codepoint in the
@ -1008,7 +1010,7 @@ vim.str_utf_pos({str}) *vim.str_utf_pos()*
• {str} (`string`)
Return: ~
(`table`)
(`integer[]`)
vim.str_utf_start({str}, {index}) *vim.str_utf_start()*
Gets the distance (in bytes) from the starting byte of the codepoint
@ -1029,10 +1031,10 @@ vim.str_utf_start({str}, {index}) *vim.str_utf_start()*
Parameters: ~
• {str} (`string`)
• {index} (`number`)
• {index} (`integer`)
Return: ~
(`number`)
(`integer`)
vim.str_utfindex({str}, {index}) *vim.str_utfindex()*
Convert byte index to UTF-32 and UTF-16 indices. If {index} is not
@ -1045,7 +1047,7 @@ vim.str_utfindex({str}, {index}) *vim.str_utfindex()*
Parameters: ~
• {str} (`string`)
• {index} (`number?`)
• {index} (`integer?`)
Return (multiple): ~
(`integer`) UTF-32 index
@ -4051,6 +4053,9 @@ Iter:last() *Iter:last()*
Return: ~
(`any`)
See also: ~
• Iter.rpeek
Iter:map({f}) *Iter:map()*
Maps the items of an iterator pipeline to the values returned by `f`.
@ -4092,53 +4097,28 @@ Iter:next() *Iter:next()*
Return: ~
(`any`)
Iter:nextback() *Iter:nextback()*
"Pops" a value from a |list-iterator| (gets the last value and decrements
the tail).
Example: >lua
local it = vim.iter({1, 2, 3, 4})
it:nextback()
-- 4
it:nextback()
-- 3
<
Return: ~
(`any`)
Iter:nth({n}) *Iter:nth()*
Gets the nth value of an iterator (and advances to it).
Example: >lua
If `n` is negative, offsets from the end of a |list-iterator|.
Example: >lua
local it = vim.iter({ 3, 6, 9, 12 })
it:nth(2)
-- 6
it:nth(2)
-- 12
<
Parameters: ~
• {n} (`number`) The index of the value to return.
Return: ~
(`any`)
Iter:nthback({n}) *Iter:nthback()*
Gets the nth value from the end of a |list-iterator| (and advances to it).
Example: >lua
local it = vim.iter({ 3, 6, 9, 12 })
it:nthback(2)
local it2 = vim.iter({ 3, 6, 9, 12 })
it2:nth(-2)
-- 9
it:nthback(2)
it2:nth(-2)
-- 3
<
Parameters: ~
• {n} (`number`) The index of the value to return.
• {n} (`number`) Index of the value to return. May be negative if the
source is a |list-iterator|.
Return: ~
(`any`)
@ -4160,19 +4140,16 @@ Iter:peek() *Iter:peek()*
Return: ~
(`any`)
Iter:peekback() *Iter:peekback()*
Gets the last value of a |list-iterator| without consuming it.
See also |Iter:last()|.
Iter:pop() *Iter:pop()*
"Pops" a value from a |list-iterator| (gets the last value and decrements
the tail).
Example: >lua
local it = vim.iter({1, 2, 3, 4})
it:peekback()
-- 4
it:peekback()
-- 4
it:nextback()
it:pop()
-- 4
it:pop()
-- 3
<
Return: ~
@ -4192,8 +4169,8 @@ Iter:rev() *Iter:rev()*
(`Iter`)
Iter:rfind({f}) *Iter:rfind()*
Gets the first value in a |list-iterator| that satisfies a predicate,
starting from the end.
Gets the first value satisfying a predicate, from the end of a
|list-iterator|.
Advances the iterator. Returns nil and drains the iterator if no value is
found.
@ -4216,6 +4193,42 @@ Iter:rfind({f}) *Iter:rfind()*
See also: ~
• Iter.find
Iter:rpeek() *Iter:rpeek()*
Gets the last value of a |list-iterator| without consuming it.
Example: >lua
local it = vim.iter({1, 2, 3, 4})
it:rpeek()
-- 4
it:rpeek()
-- 4
it:pop()
-- 4
<
Return: ~
(`any`)
See also: ~
• Iter.last
Iter:rskip({n}) *Iter:rskip()*
Discards `n` values from the end of a |list-iterator| pipeline.
Example: >lua
local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)
it:next()
-- 1
it:pop()
-- 3
<
Parameters: ~
• {n} (`number`) Number of values to skip.
Return: ~
(`Iter`)
Iter:skip({n}) *Iter:skip()*
Skips `n` values of an iterator pipeline.
@ -4232,27 +4245,10 @@ Iter:skip({n}) *Iter:skip()*
Return: ~
(`Iter`)
Iter:skipback({n}) *Iter:skipback()*
Skips `n` values backwards from the end of a |list-iterator| pipeline.
Example: >lua
local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2)
it:next()
-- 1
it:nextback()
-- 3
<
Parameters: ~
• {n} (`number`) Number of values to skip.
Return: ~
(`Iter`)
Iter:slice({first}, {last}) *Iter:slice()*
Sets the start and end of a |list-iterator| pipeline.
Equivalent to `:skip(first - 1):skipback(len - last + 1)`.
Equivalent to `:skip(first - 1):rskip(len - last + 1)`.
Parameters: ~
• {first} (`number`)

View File

@ -159,6 +159,14 @@ unreleased features on Nvim HEAD.
• Changed |vim.ui.open()| return-signature to match pcall() convention.
• Renamed Iter:nextback() to Iter:pop()
• Renamed Iter:peekback() to Iter:rpeek()
• Renamed Iter:skipback() to Iter:rskip()
• Removed Iter:nthback(), use Iter:nth() with negative index instead.
==============================================================================
NEW FEATURES *news-features*
@ -243,6 +251,8 @@ The following new APIs and features were added.
(e.g. `commitCharacters`). Note that this might affect plugins and
language servers that don't support the feature, and in such cases the
respective capability can be unset.
• |vim.lsp.start()| accepts a "silent" option for suppressing messages
if an LSP server failed to start.
• Treesitter
• Bundled parsers and queries (highlight, folds) for Markdown, Python, and
@ -398,6 +408,14 @@ The following changes to existing APIs or features add new behavior.
• 'comments' includes "fb:•".
• 'shortmess' includes the "C" flag.
• 'grepprg' defaults to using ripgrep if available.
• |crn| in Normal mode maps to |vim.lsp.buf.rename()|.
• |crr| in Normal and Visual mode maps to |vim.lsp.buf.code_action()|.
• "gr" in Normal mode maps to |vim.lsp.buf.references()| |gr-default|
• |i_CTRL-S| in Insert mode maps to |vim.lsp.buf.signature_help()|
• "]d" and "[d" in Normal mode map to |vim.diagnostic.goto_next()| and
|vim.diagnostic.goto_prev()|, respectively. |]d-default| |[d-default|
• <C-W>d (and <C-W><C-D>) map to |vim.diagnostic.open_float()|
|CTRL-W_d-default|
• Automatic linting of treesitter query files (see |ft-query-plugin|).
Can be disabled via: >lua
vim.g.query_lint_on = {}
@ -428,9 +446,10 @@ The following changes to existing APIs or features add new behavior.
:call netrw#BrowseX(expand(exists("g:netrw_gx")? g:netrw_gx : '<cfile>'), netrw#CheckIfRemote())<CR>
• |vim.lsp.start()| now maps |K| to use |vim.lsp.buf.hover()| if the server
supports it, unless |'keywordprg'| was customized before calling
|vim.lsp.start()|.
• |vim.lsp.start()| now creates the following default keymaps (assuming the
server supports the feature):
- |K| in Normal mode maps to |vim.lsp.buf.hover()|, unless |'keywordprg'|
was customized before calling |vim.lsp.start()|.
• Terminal buffers started with no arguments (and use 'shell') close
automatically if the job exited without error, eliminating the (often

View File

@ -1375,6 +1375,19 @@ Finally, these constructs are unique to Perl:
==============================================================================
10. Highlighting matches *match-highlight*
*syntax-vs-match*
Note that the match highlight mechanism is independent
of |syntax-highlighting|, which is (usually) a buffer-local
highlighting, while matching is window-local, both methods
can be freely mixed. Match highlighting functions give you
a bit more flexibility in when and how to apply, but are
typically only used for temporary highlighting, without strict
rules. Both methods can be used to conceal text.
Thus the matching functions like |matchadd()| won't consider
syntax rules and functions like |synconcealed()| and the
other way around.
*:mat* *:match*
:mat[ch] {group} /{pattern}/
Define a pattern to highlight in the current window. It will

View File

@ -3825,7 +3825,9 @@ Whether or not it is actually concealed depends on the value of the
'conceallevel' option. The 'concealcursor' option is used to decide whether
concealable items in the current line are displayed unconcealed to be able to
edit the line.
Another way to conceal text is with |matchadd()|.
Another way to conceal text is with |matchadd()|, but internally this works a
bit differently |syntax-vs-match|.
concealends *:syn-concealends*
@ -3833,7 +3835,9 @@ When the "concealends" argument is given, the start and end matches of
the region, but not the contents of the region, are marked as concealable.
Whether or not they are actually concealed depends on the setting on the
'conceallevel' option. The ends of a region can only be concealed separately
in this way when they have their own highlighting via "matchgroup"
in this way when they have their own highlighting via "matchgroup". The
|synconcealed()| function can be used to retrieve information about conealed
items.
cchar *:syn-cchar*
*E844*

View File

@ -780,9 +780,17 @@ CTRL-W i Open a new window, with the cursor on the first line
beginning of the file. If a count is given, the
count'th matching line is displayed.
*[d-default*
Mapped to |vim.diagnostic.goto_prev()| by default.
|default-mappings|
*]d*
]d like "[d", but start at the current cursor position.
*]d-default*
Mapped to |vim.diagnostic.goto_next()| by default.
|default-mappings|
*:ds* *:dsearch*
:[range]ds[earch][!] [count] [/]string[/]
Like "[d" and "]d", but search in [range] lines
@ -829,6 +837,10 @@ CTRL-W d Open a new window, with the cursor on the first
beginning of the file. If a count is given, the
count'th matching line is jumped to.
*CTRL-W_d-default*
Mapped to |vim.diagnostic.open_float()| by default.
|default-mappings|
*:dsp* *:dsplit*
:[range]dsp[lit][!] [count] [/]string[/]
Like "CTRL-W d", but search in [range] lines

View File

@ -731,8 +731,7 @@ get_captures_at_pos({bufnr}, {row}, {col})
• {col} (`integer`) Position column
Return: ~
(`table[]`) List of captures
`{ capture = "name", metadata = { ... } }`
(`{capture: string, lang: string, metadata: table}[]`)
get_node({opts}) *vim.treesitter.get_node()*
Returns the smallest named node at the given position

View File

@ -948,7 +948,7 @@ Syntax and highlighting: *syntax-functions* *highlighting-functions*
synIDattr() get a specific attribute of a syntax ID
synIDtrans() get translated syntax ID
synstack() get list of syntax IDs at a specific position
synconcealed() get info about concealing
synconcealed() get info about (syntax) concealing
diff_hlID() get highlight ID for diff mode at a position
matchadd() define a pattern to highlight (a "match")
matchaddpos() define a list of positions to highlight

View File

@ -137,6 +137,13 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y".
- * |v_star-default|
- gc |gc-default| |v_gc-default| |o_gc-default|
- gcc |gcc-default|
- |crn|
- |crr|
- gr |gr-default|
- <C-S> |i_CTRL-S|
- ]d |]d-default|
- [d |[d-default|
- <C-W>d |CTRL-W_d-default|
- Nvim LSP client defaults |lsp-defaults|
- K |K-lsp-default|

View File

@ -24,7 +24,7 @@ if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
nnoremap <silent> <buffer> k gk
nnoremap <silent> <buffer> gO :lua require'man'.show_toc()<CR>
nnoremap <silent> <buffer> <2-LeftMouse> :Man<CR>
if get(b:, 'pager')
if get(g:, 'pager')
nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>q
else
nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>c

View File

@ -411,15 +411,13 @@ local function find_man()
return false
end
---@param pager boolean
local function set_options(pager)
local function set_options()
vim.bo.swapfile = false
vim.bo.buftype = 'nofile'
vim.bo.bufhidden = 'unload'
vim.bo.modified = false
vim.bo.readonly = true
vim.bo.modifiable = false
vim.b.pager = pager
vim.bo.filetype = 'man'
end
@ -475,7 +473,7 @@ local function put_page(page)
vim.cmd([[silent! keeppatterns keepjumps %s/\s\{199,}/\=repeat(' ', 10)/g]])
vim.cmd('1') -- Move cursor to first line
highlight_man_page()
set_options(false)
set_options()
end
local function format_candidate(path, psect)
@ -662,7 +660,8 @@ function M.init_pager()
vim.cmd.file({ 'man://' .. fn.fnameescape(ref):lower(), mods = { silent = true } })
end
set_options(true)
vim.g.pager = true
set_options()
end
---@param count integer
@ -730,7 +729,7 @@ function M.open_page(count, smods, args)
if not ok then
error(ret)
else
set_options(false)
set_options()
end
vim.b.man_sect = sect

View File

@ -127,7 +127,9 @@ do
end, { desc = gx_desc })
end
--- Default maps for built-in commenting
--- Default maps for built-in commenting.
---
--- See |gc-default| and |gcc-default|.
do
local operator_rhs = function()
return require('vim._comment').operator()
@ -144,6 +146,60 @@ do
end
vim.keymap.set({ 'o' }, 'gc', textobject_rhs, { desc = 'Comment textobject' })
end
--- Default maps for LSP functions.
---
--- These are mapped unconditionally to avoid confusion. If no server is attached, or if a server
--- does not support a capability, an error message is displayed rather than exhibiting different
--- behavior.
---
--- See |gr-default|, |crn|, |crr|, |i_CTRL-S|.
do
vim.keymap.set('n', 'crn', function()
vim.lsp.buf.rename()
end, { desc = 'vim.lsp.buf.rename()' })
vim.keymap.set({ 'n', 'v' }, 'crr', function()
vim.lsp.buf.code_action()
end, { desc = 'vim.lsp.buf.code_action()' })
vim.keymap.set('n', 'gr', function()
vim.lsp.buf.references()
end, { desc = 'vim.lsp.buf.references()' })
vim.keymap.set('i', '<C-S>', function()
vim.lsp.buf.signature_help()
end, { desc = 'vim.lsp.buf.signature_help()' })
end
--- Map [d and ]d to move to the previous/next diagnostic. Map <C-W>d to open a floating window
--- for the diagnostic under the cursor.
---
--- See |[d-default|, |]d-default|, and |CTRL-W_d-default|.
do
vim.keymap.set('n', ']d', function()
vim.diagnostic.goto_next({ float = false })
end, {
desc = 'Jump to the next diagnostic with the highest severity',
})
vim.keymap.set('n', '[d', function()
vim.diagnostic.goto_prev({ float = false })
end, {
desc = 'Jump to the previous diagnostic with the highest severity',
})
vim.keymap.set('n', '<C-W>d', function()
vim.diagnostic.open_float({ border = 'rounded' })
end, {
desc = 'Open a floating window showing diagnostics under the cursor',
})
vim.keymap.set('n', '<C-W><C-D>', '<C-W>d', {
remap = true,
desc = 'Open a floating window showing diagnostics under the cursor',
})
end
end
--- Default menus
@ -196,6 +252,7 @@ do
group = nvim_terminal_augroup,
desc = 'Respond to OSC foreground/background color requests',
callback = function(args)
--- @type integer
local channel = vim.bo[args.buf].channel
if channel == 0 then
return
@ -242,229 +299,140 @@ do
vim.notify(('W325: Ignoring swapfile from Nvim process %d'):format(info.pid))
end,
})
end
-- Only do the following when the TUI is attached
local tty = nil
for _, ui in ipairs(vim.api.nvim_list_uis()) do
if ui.chan == 1 and ui.stdout_tty then
tty = ui
break
end
end
if tty then
local group = vim.api.nvim_create_augroup('nvim_tty', {})
--- Set an option after startup (so that OptionSet is fired), but only if not
--- already set by the user.
---
--- @param option string Option name
--- @param value any Option value
local function setoption(option, value)
if vim.api.nvim_get_option_info2(option, {}).was_set then
-- Don't do anything if option is already set
return
end
-- Wait until Nvim is finished starting to set the option to ensure the
-- OptionSet event fires.
if vim.v.vim_did_enter == 1 then
vim.o[option] = value
else
vim.api.nvim_create_autocmd('VimEnter', {
group = group,
once = true,
nested = true,
callback = function()
setoption(option, value)
end,
})
-- Only do the following when the TUI is attached
local tty = nil
for _, ui in ipairs(vim.api.nvim_list_uis()) do
if ui.chan == 1 and ui.stdout_tty then
tty = ui
break
end
end
--- Guess value of 'background' based on terminal color.
---
--- We write Operating System Command (OSC) 11 to the terminal to request the
--- terminal's background color. We then wait for a response. If the response
--- matches `rgba:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits, then
--- compute the luminance[1] of the RGB color and classify it as light/dark
--- accordingly. Note that the color components may have anywhere from one to
--- four hex digits, and require scaling accordingly as values out of 4, 8, 12,
--- or 16 bits. Also note the A(lpha) component is optional, and is parsed but
--- ignored in the calculations.
---
--- [1] https://en.wikipedia.org/wiki/Luma_%28video%29
do
--- Parse a string of hex characters as a color.
if tty then
local group = vim.api.nvim_create_augroup('nvim_tty', {})
--- Set an option after startup (so that OptionSet is fired), but only if not
--- already set by the user.
---
--- The string can contain 1 to 4 hex characters. The returned value is
--- between 0.0 and 1.0 (inclusive) representing the intensity of the color.
---
--- For instance, if only a single hex char "a" is used, then this function
--- returns 0.625 (10 / 16), while a value of "aa" would return 0.664 (170 /
--- 256).
---
--- @param c string Color as a string of hex chars
--- @return number? Intensity of the color
local function parsecolor(c)
if #c == 0 or #c > 4 then
return nil
--- @param option string Option name
--- @param value any Option value
local function setoption(option, value)
if vim.api.nvim_get_option_info2(option, {}).was_set then
-- Don't do anything if option is already set
return
end
local val = tonumber(c, 16)
if not val then
return nil
-- Wait until Nvim is finished starting to set the option to ensure the
-- OptionSet event fires.
if vim.v.vim_did_enter == 1 then
--- @diagnostic disable-next-line:no-unknown
vim.o[option] = value
else
vim.api.nvim_create_autocmd('VimEnter', {
group = group,
once = true,
nested = true,
callback = function()
setoption(option, value)
end,
})
end
local max = tonumber(string.rep('f', #c), 16)
return val / max
end
--- Parse an OSC 11 response
--- Guess value of 'background' based on terminal color.
---
--- Either of the two formats below are accepted:
--- We write Operating System Command (OSC) 11 to the terminal to request the
--- terminal's background color. We then wait for a response. If the response
--- matches `rgba:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits, then
--- compute the luminance[1] of the RGB color and classify it as light/dark
--- accordingly. Note that the color components may have anywhere from one to
--- four hex digits, and require scaling accordingly as values out of 4, 8, 12,
--- or 16 bits. Also note the A(lpha) component is optional, and is parsed but
--- ignored in the calculations.
---
--- OSC 11 ; rgb:<red>/<green>/<blue>
---
--- or
---
--- OSC 11 ; rgba:<red>/<green>/<blue>/<alpha>
---
--- where
---
--- <red>, <green>, <blue>, <alpha> := h | hh | hhh | hhhh
---
--- The alpha component is ignored, if present.
---
--- @param resp string OSC 11 response
--- @return string? Red component
--- @return string? Green component
--- @return string? Blue component
local function parseosc11(resp)
local r, g, b
r, g, b = resp:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
if not r and not g and not b then
local a
r, g, b, a = resp:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')
if not a or #a > 4 then
return nil, nil, nil
--- [1] https://en.wikipedia.org/wiki/Luma_%28video%29
do
--- Parse a string of hex characters as a color.
---
--- The string can contain 1 to 4 hex characters. The returned value is
--- between 0.0 and 1.0 (inclusive) representing the intensity of the color.
---
--- For instance, if only a single hex char "a" is used, then this function
--- returns 0.625 (10 / 16), while a value of "aa" would return 0.664 (170 /
--- 256).
---
--- @param c string Color as a string of hex chars
--- @return number? Intensity of the color
local function parsecolor(c)
if #c == 0 or #c > 4 then
return nil
end
local val = tonumber(c, 16)
if not val then
return nil
end
local max = tonumber(string.rep('f', #c), 16)
return val / max
end
if r and g and b and #r <= 4 and #g <= 4 and #b <= 4 then
return r, g, b
end
return nil, nil, nil
end
local timer = assert(vim.uv.new_timer())
local id = vim.api.nvim_create_autocmd('TermResponse', {
group = group,
nested = true,
callback = function(args)
local resp = args.data ---@type string
local r, g, b = parseosc11(resp)
if r and g and b then
local rr = parsecolor(r)
local gg = parsecolor(g)
local bb = parsecolor(b)
if rr and gg and bb then
local luminance = (0.299 * rr) + (0.587 * gg) + (0.114 * bb)
local bg = luminance < 0.5 and 'dark' or 'light'
setoption('background', bg)
--- Parse an OSC 11 response
---
--- Either of the two formats below are accepted:
---
--- OSC 11 ; rgb:<red>/<green>/<blue>
---
--- or
---
--- OSC 11 ; rgba:<red>/<green>/<blue>/<alpha>
---
--- where
---
--- <red>, <green>, <blue>, <alpha> := h | hh | hhh | hhhh
---
--- The alpha component is ignored, if present.
---
--- @param resp string OSC 11 response
--- @return string? Red component
--- @return string? Green component
--- @return string? Blue component
local function parseosc11(resp)
local r, g, b
r, g, b = resp:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
if not r and not g and not b then
local a
r, g, b, a = resp:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')
if not a or #a > 4 then
return nil, nil, nil
end
return true
end
end,
})
io.stdout:write('\027]11;?\007')
if r and g and b and #r <= 4 and #g <= 4 and #b <= 4 then
return r, g, b
end
timer:start(1000, 0, function()
-- Delete the autocommand if no response was received
vim.schedule(function()
-- Suppress error if autocommand has already been deleted
pcall(vim.api.nvim_del_autocmd, id)
end)
if not timer:is_closing() then
timer:close()
return nil, nil, nil
end
end)
end
--- If the TUI (term_has_truecolor) was able to determine that the host
--- terminal supports truecolor, enable 'termguicolors'. Otherwise, query the
--- terminal (using both XTGETTCAP and SGR + DECRQSS). If the terminal's
--- response indicates that it does support truecolor enable 'termguicolors',
--- but only if the user has not already disabled it.
do
if tty.rgb then
-- The TUI was able to determine truecolor support
setoption('termguicolors', true)
else
local caps = {} ---@type table<string, boolean>
require('vim.termcap').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found)
if not found then
return
end
caps[cap] = true
if caps.Tc or caps.RGB or (caps.setrgbf and caps.setrgbb) then
setoption('termguicolors', true)
end
end)
local timer = assert(vim.uv.new_timer())
-- Arbitrary colors to set in the SGR sequence
local r = 1
local g = 2
local b = 3
local id = vim.api.nvim_create_autocmd('TermResponse', {
group = group,
nested = true,
callback = function(args)
local resp = args.data ---@type string
local decrqss = resp:match('^\027P1%$r([%d;:]+)m$')
local r, g, b = parseosc11(resp)
if r and g and b then
local rr = parsecolor(r)
local gg = parsecolor(g)
local bb = parsecolor(b)
if decrqss then
-- The DECRQSS SGR response first contains attributes separated by
-- semicolons, followed by the SGR itself with parameters separated
-- by colons. Some terminals include "0" in the attribute list
-- unconditionally; others do not. Our SGR sequence did not set any
-- attributes, so there should be no attributes in the list.
local attrs = vim.split(decrqss, ';')
if #attrs ~= 1 and (#attrs ~= 2 or attrs[1] ~= '0') then
return false
end
-- The returned SGR sequence should begin with 48:2
local sgr = attrs[#attrs]:match('^48:2:([%d:]+)$')
if not sgr then
return false
end
-- The remaining elements of the SGR sequence should be the 3 colors
-- we set. Some terminals also include an additional parameter
-- (which can even be empty!), so handle those cases as well
local params = vim.split(sgr, ':')
if #params ~= 3 and (#params ~= 4 or (params[1] ~= '' and params[1] ~= '1')) then
return true
end
if
tonumber(params[#params - 2]) == r
and tonumber(params[#params - 1]) == g
and tonumber(params[#params]) == b
then
setoption('termguicolors', true)
if rr and gg and bb then
local luminance = (0.299 * rr) + (0.587 * gg) + (0.114 * bb)
local bg = luminance < 0.5 and 'dark' or 'light'
setoption('background', bg)
end
return true
@ -472,16 +440,7 @@ if tty then
end,
})
-- Write SGR followed by DECRQSS. This sets the background color then
-- immediately asks the terminal what the background color is. If the
-- terminal responds to the DECRQSS with the same SGR sequence that we
-- sent then the terminal supports truecolor.
local decrqss = '\027P$qm\027\\'
if os.getenv('TMUX') then
decrqss = string.format('\027Ptmux;%s\027\\', decrqss:gsub('\027', '\027\027'))
end
-- Reset attributes first, as other code may have set attributes.
io.stdout:write(string.format('\027[0m\027[48;2;%d;%d;%dm%s', r, g, b, decrqss))
io.stdout:write('\027]11;?\007')
timer:start(1000, 0, function()
-- Delete the autocommand if no response was received
@ -495,13 +454,115 @@ if tty then
end
end)
end
--- If the TUI (term_has_truecolor) was able to determine that the host
--- terminal supports truecolor, enable 'termguicolors'. Otherwise, query the
--- terminal (using both XTGETTCAP and SGR + DECRQSS). If the terminal's
--- response indicates that it does support truecolor enable 'termguicolors',
--- but only if the user has not already disabled it.
do
if tty.rgb then
-- The TUI was able to determine truecolor support
setoption('termguicolors', true)
else
local caps = {} ---@type table<string, boolean>
require('vim.termcap').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found)
if not found then
return
end
caps[cap] = true
if caps.Tc or caps.RGB or (caps.setrgbf and caps.setrgbb) then
setoption('termguicolors', true)
end
end)
local timer = assert(vim.uv.new_timer())
-- Arbitrary colors to set in the SGR sequence
local r = 1
local g = 2
local b = 3
local id = vim.api.nvim_create_autocmd('TermResponse', {
group = group,
nested = true,
callback = function(args)
local resp = args.data ---@type string
local decrqss = resp:match('^\027P1%$r([%d;:]+)m$')
if decrqss then
-- The DECRQSS SGR response first contains attributes separated by
-- semicolons, followed by the SGR itself with parameters separated
-- by colons. Some terminals include "0" in the attribute list
-- unconditionally; others do not. Our SGR sequence did not set any
-- attributes, so there should be no attributes in the list.
local attrs = vim.split(decrqss, ';')
if #attrs ~= 1 and (#attrs ~= 2 or attrs[1] ~= '0') then
return false
end
-- The returned SGR sequence should begin with 48:2
local sgr = attrs[#attrs]:match('^48:2:([%d:]+)$')
if not sgr then
return false
end
-- The remaining elements of the SGR sequence should be the 3 colors
-- we set. Some terminals also include an additional parameter
-- (which can even be empty!), so handle those cases as well
local params = vim.split(sgr, ':')
if #params ~= 3 and (#params ~= 4 or (params[1] ~= '' and params[1] ~= '1')) then
return true
end
if
tonumber(params[#params - 2]) == r
and tonumber(params[#params - 1]) == g
and tonumber(params[#params]) == b
then
setoption('termguicolors', true)
end
return true
end
end,
})
-- Write SGR followed by DECRQSS. This sets the background color then
-- immediately asks the terminal what the background color is. If the
-- terminal responds to the DECRQSS with the same SGR sequence that we
-- sent then the terminal supports truecolor.
local decrqss = '\027P$qm\027\\'
if os.getenv('TMUX') then
decrqss = string.format('\027Ptmux;%s\027\\', decrqss:gsub('\027', '\027\027'))
end
-- Reset attributes first, as other code may have set attributes.
io.stdout:write(string.format('\027[0m\027[48;2;%d;%d;%dm%s', r, g, b, decrqss))
timer:start(1000, 0, function()
-- Delete the autocommand if no response was received
vim.schedule(function()
-- Suppress error if autocommand has already been deleted
pcall(vim.api.nvim_del_autocmd, id)
end)
if not timer:is_closing() then
timer:close()
end
end)
end
end
end
end
--- Default 'grepprg' to ripgrep if available.
if vim.fn.executable('rg') == 1 then
-- Match :grep default, otherwise rg searches cwd by default
-- Use -uuu to make ripgrep not do its default filtering
vim.o.grepprg = 'rg --vimgrep -uuu $* ' .. (vim.fn.has('unix') == 1 and '/dev/null' or 'nul')
vim.o.grepformat = '%f:%l:%c:%m'
--- Default options
do
--- Default 'grepprg' to ripgrep if available.
if vim.fn.executable('rg') == 1 then
-- Match :grep default, otherwise rg searches cwd by default
-- Use -uuu to make ripgrep not do its default filtering
vim.o.grepprg = 'rg --vimgrep -uuu $* ' .. (vim.fn.has('unix') == 1 and '/dev/null' or 'nul')
vim.o.grepformat = '%f:%l:%c:%m'
end
end

View File

@ -55,8 +55,8 @@ function vim.inspect_pos(bufnr, row, col, filter)
bufnr = bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr
local results = {
treesitter = {},
syntax = {},
treesitter = {}, --- @type table[]
syntax = {}, --- @type table[]
extmarks = {},
semantic_tokens = {},
buffer = bufnr,
@ -93,7 +93,7 @@ function vim.inspect_pos(bufnr, row, col, filter)
end
-- namespace id -> name map
local nsmap = {}
local nsmap = {} --- @type table<integer,string>
for name, id in pairs(vim.api.nvim_get_namespaces()) do
nsmap[id] = name
end

View File

@ -3,11 +3,11 @@
--- Encode {str} using Base64.
---
--- @param str string String to encode
--- @return string Encoded string
--- @return string : Encoded string
function vim.base64.encode(str) end
--- Decode a Base64 encoded string.
---
--- @param str string Base64 encoded string
--- @return string Decoded string
--- @return string : Decoded string
function vim.base64.decode(str) end

View File

@ -119,15 +119,15 @@ function vim.stricmp(a, b) end
--- An {index} in the middle of a UTF-16 sequence is rounded upwards to
--- the end of that sequence.
--- @param str string
--- @param index number
--- @param use_utf16? any
--- @param index integer
--- @param use_utf16? boolean
function vim.str_byteindex(str, index, use_utf16) end
--- Gets a list of the starting byte positions of each UTF-8 codepoint in the given string.
---
--- Embedded NUL bytes are treated as terminating the string.
--- @param str string
--- @return table
--- @return integer[]
function vim.str_utf_pos(str) end
--- Gets the distance (in bytes) from the starting byte of the codepoint (character) that {index}
@ -148,8 +148,8 @@ function vim.str_utf_pos(str) end
--- ```
---
--- @param str string
--- @param index number
--- @return number
--- @param index integer
--- @return integer
function vim.str_utf_start(str, index) end
--- Gets the distance (in bytes) from the last byte of the codepoint (character) that {index} points
@ -168,8 +168,8 @@ function vim.str_utf_start(str, index) end
--- ```
---
--- @param str string
--- @param index number
--- @return number
--- @param index integer
--- @return integer
function vim.str_utf_end(str, index) end
--- Convert byte index to UTF-32 and UTF-16 indices. If {index} is not
@ -180,7 +180,7 @@ function vim.str_utf_end(str, index) end
--- {index} in the middle of a UTF-8 sequence is rounded upwards to the end of
--- that sequence.
--- @param str string
--- @param index? number
--- @param index? integer
--- @return integer UTF-32 index
--- @return integer UTF-16 index
function vim.str_utfindex(str, index) end
@ -193,15 +193,14 @@ function vim.str_utfindex(str, index) end
--- can accept, see ":Man 3 iconv".
---
--- @param str string Text to convert
--- @param from number Encoding of {str}
--- @param to number Target encoding
--- @param opts? table<string,any>
--- @return string|nil Converted string if conversion succeeds, `nil` otherwise.
--- @param from string Encoding of {str}
--- @param to string Target encoding
--- @return string? : Converted string if conversion succeeds, `nil` otherwise.
function vim.iconv(str, from, to, opts) end
--- Schedules {fn} to be invoked soon by the main event-loop. Useful
--- to avoid |textlock| or other temporary restrictions.
--- @param fn function
--- @param fn fun()
function vim.schedule(fn) end
--- Wait for {time} in milliseconds until {callback} returns `true`.

View File

@ -1,5 +1,46 @@
---@meta
--- Optional parameters:
--- @class vim.diff.Opts
--- @inlinedoc
---
--- Invoked for each hunk in the diff. Return a negative number
--- to cancel the callback for any remaining hunks.
--- Arguments:
--- - `start_a` (`integer`): Start line of hunk in {a}.
--- - `count_a` (`integer`): Hunk size in {a}.
--- - `start_b` (`integer`): Start line of hunk in {b}.
--- - `count_b` (`integer`): Hunk size in {b}.
--- @field on_hunk fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer
---
--- Form of the returned diff:
--- - `unified`: String in unified format.
--- - `indices`: Array of hunk locations.
--- Note: This option is ignored if `on_hunk` is used.
--- (default: `'unified'`)
--- @field result_type 'unified'|'indices'
---
--- Run linematch on the resulting hunks from xdiff. When integer, only hunks
--- upto this size in lines are run through linematch.
--- Requires `result_type = indices`, ignored otherwise.
--- @field linematch boolean|integer
---
--- Diff algorithm to use. Values:
--- - `myers`: the default algorithm
--- - `minimal`: spend extra time to generate the smallest possible diff
--- - `patience`: patience diff algorithm
--- - `histogram`: histogram diff algorithm
--- (default: `'myers'`)
--- @field algorithm 'myers'|'minimal'|'patience'|'histogram'
--- @field ctxlen integer Context length
--- @field interhunkctxlen integer Inter hunk context length
--- @field ignore_whitespace boolean Ignore whitespace
--- @field ignore_whitespace_change boolean Ignore whitespace change
--- @field ignore_whitespace_change_at_eol boolean Ignore whitespace change at end-of-line.
--- @field ignore_cr_at_eol boolean Ignore carriage return at end-of-line
--- @field ignore_blank_lines boolean Ignore blank lines
--- @field indent_heuristic boolean Use the indent heuristic for the internal diff library.
-- luacheck: no unused args
--- Run diff on strings {a} and {b}. Any indices returned by this function,
@ -24,47 +65,7 @@
---
---@param a string First string to compare
---@param b string Second string to compare
---@param opts table<string,any> Optional parameters:
--- - `on_hunk` (callback):
--- Invoked for each hunk in the diff. Return a negative number
--- to cancel the callback for any remaining hunks.
--- Args:
--- - `start_a` (integer): Start line of hunk in {a}.
--- - `count_a` (integer): Hunk size in {a}.
--- - `start_b` (integer): Start line of hunk in {b}.
--- - `count_b` (integer): Hunk size in {b}.
--- - `result_type` (string): Form of the returned diff:
--- - "unified": (default) String in unified format.
--- - "indices": Array of hunk locations.
--- Note: This option is ignored if `on_hunk` is used.
--- - `linematch` (boolean|integer): Run linematch on the resulting hunks
--- from xdiff. When integer, only hunks upto this size in
--- lines are run through linematch. Requires `result_type = indices`,
--- ignored otherwise.
--- - `algorithm` (string):
--- Diff algorithm to use. Values:
--- - "myers" the default algorithm
--- - "minimal" spend extra time to generate the
--- smallest possible diff
--- - "patience" patience diff algorithm
--- - "histogram" histogram diff algorithm
--- - `ctxlen` (integer): Context length
--- - `interhunkctxlen` (integer):
--- Inter hunk context length
--- - `ignore_whitespace` (boolean):
--- Ignore whitespace
--- - `ignore_whitespace_change` (boolean):
--- Ignore whitespace change
--- - `ignore_whitespace_change_at_eol` (boolean)
--- Ignore whitespace change at end-of-line.
--- - `ignore_cr_at_eol` (boolean)
--- Ignore carriage return at end-of-line
--- - `ignore_blank_lines` (boolean)
--- Ignore blank lines
--- - `indent_heuristic` (boolean):
--- Use the indent heuristic for the internal
--- diff library.
---
---@return string|table|nil
---@param opts vim.diff.Opts
---@return string|integer[][]?
--- See {opts.result_type}. `nil` if {opts.on_hunk} is given.
function vim.diff(a, b, opts) end

View File

@ -30,8 +30,8 @@ function vim.re.compile(string, defs) end
--- @param subject string
--- @param pattern vim.lpeg.Pattern|string
--- @param init? integer
--- @return integer|nil the index where the occurrence starts, nil if no match
--- @return integer|nil the index where the occurrence ends, nil if no match
--- @return integer|nil : the index where the occurrence starts, nil if no match
--- @return integer|nil : the index where the occurrence ends, nil if no match
function vim.re.find(subject, pattern, init) end
--- Does a global substitution, replacing all occurrences of {pattern} in the given {subject} by

View File

@ -3,11 +3,11 @@
-- luacheck: no unused args
--- Check {str} for spelling errors. Similar to the Vimscript function
--- |spellbadword()|.
--- [spellbadword()].
---
--- Note: The behaviour of this function is dependent on: 'spelllang',
--- 'spellfile', 'spellcapcheck' and 'spelloptions' which can all be local to
--- the buffer. Consider calling this with |nvim_buf_call()|.
--- the buffer. Consider calling this with [nvim_buf_call()].
---
--- Example:
---
@ -20,7 +20,7 @@
--- ```
---
--- @param str string
--- @return {[1]: string, [2]: string, [3]: string}[]
--- @return {[1]: string, [2]: 'bad'|'rare'|'local'|'caps', [3]: integer}[]
--- List of tuples with three items:
--- - The badly spelled word.
--- - The type of the spelling error:

View File

@ -9752,6 +9752,10 @@ function vim.fn.synIDtrans(synID) end
--- synconcealed(lnum, 5) [1, 'X', 2]
--- synconcealed(lnum, 6) [0, '', 0]
---
--- Note: Doesn't consider |matchadd()| highlighting items,
--- since syntax and matching highlighting are two different
--- mechanisms |syntax-vs-match|.
---
--- @param lnum integer
--- @param col integer
--- @return {[1]: integer, [2]: string, [3]: integer}

View File

@ -630,7 +630,7 @@ function Iter:find(f)
return unpack(result)
end
--- Gets the first value in a |list-iterator| that satisfies a predicate, starting from the end.
--- Gets the first value satisfying a predicate, from the end of a |list-iterator|.
---
--- Advances the iterator. Returns nil and drains the iterator if no value is found.
---
@ -717,19 +717,19 @@ end
---
--- ```lua
--- local it = vim.iter({1, 2, 3, 4})
--- it:nextback()
--- it:pop()
--- -- 4
--- it:nextback()
--- it:pop()
--- -- 3
--- ```
---
---@return any
function Iter:nextback()
error('nextback() requires a list-like table')
function Iter:pop()
error('pop() requires a list-like table')
end
--- @nodoc
function ListIter:nextback()
function ListIter:pop()
if self._head ~= self._tail then
local inc = self._head < self._tail and 1 or -1
self._tail = self._tail - inc
@ -739,27 +739,27 @@ end
--- Gets the last value of a |list-iterator| without consuming it.
---
--- See also |Iter:last()|.
---
--- Example:
---
--- ```lua
--- local it = vim.iter({1, 2, 3, 4})
--- it:peekback()
--- it:rpeek()
--- -- 4
--- it:peekback()
--- it:rpeek()
--- -- 4
--- it:nextback()
--- it:pop()
--- -- 4
--- ```
---
---@see Iter.last
---
---@return any
function Iter:peekback()
error('peekback() requires a list-like table')
function Iter:rpeek()
error('rpeek() requires a list-like table')
end
---@nodoc
function ListIter:peekback()
function ListIter:rpeek()
if self._head ~= self._tail then
local inc = self._head < self._tail and 1 or -1
return self._table[self._tail - inc]
@ -797,27 +797,27 @@ function ListIter:skip(n)
return self
end
--- Skips `n` values backwards from the end of a |list-iterator| pipeline.
--- Discards `n` values from the end of a |list-iterator| pipeline.
---
--- Example:
---
--- ```lua
--- local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2)
--- local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)
--- it:next()
--- -- 1
--- it:nextback()
--- it:pop()
--- -- 3
--- ```
---
---@param n number Number of values to skip.
---@return Iter
---@diagnostic disable-next-line: unused-local
function Iter:skipback(n) -- luacheck: no unused args
error('skipback() requires a list-like table')
function Iter:rskip(n) -- luacheck: no unused args
error('rskip() requires a list-like table')
end
---@private
function ListIter:skipback(n)
function ListIter:rskip(n)
local inc = self._head < self._tail and n or -n
self._tail = self._tail - inc
if (inc > 0 and self._head > self._tail) or (inc < 0 and self._head < self._tail) then
@ -828,51 +828,37 @@ end
--- Gets the nth value of an iterator (and advances to it).
---
--- If `n` is negative, offsets from the end of a |list-iterator|.
---
--- Example:
---
--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 })
--- it:nth(2)
--- -- 6
--- it:nth(2)
--- -- 12
---
--- local it2 = vim.iter({ 3, 6, 9, 12 })
--- it2:nth(-2)
--- -- 9
--- it2:nth(-2)
--- -- 3
--- ```
---
---@param n number The index of the value to return.
---@param n number Index of the value to return. May be negative if the source is a |list-iterator|.
---@return any
function Iter:nth(n)
if n > 0 then
return self:skip(n - 1):next()
end
end
--- Gets the nth value from the end of a |list-iterator| (and advances to it).
---
--- Example:
---
--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 })
--- it:nthback(2)
--- -- 9
--- it:nthback(2)
--- -- 3
---
--- ```
---
---@param n number The index of the value to return.
---@return any
function Iter:nthback(n)
if n > 0 then
return self:skipback(n - 1):nextback()
elseif n < 0 then
return self:rskip(math.abs(n) - 1):pop()
end
end
--- Sets the start and end of a |list-iterator| pipeline.
---
--- Equivalent to `:skip(first - 1):skipback(len - last + 1)`.
--- Equivalent to `:skip(first - 1):rskip(len - last + 1)`.
---
---@param first number
---@param last number
@ -884,7 +870,7 @@ end
---@private
function ListIter:slice(first, last)
return self:skip(math.max(0, first - 1)):skipback(math.max(0, self._tail - last - 1))
return self:skip(math.max(0, first - 1)):rskip(math.max(0, self._tail - last - 1))
end
--- Returns true if any of the items in the iterator match the given predicate.
@ -950,6 +936,8 @@ end
---
--- ```
---
---@see Iter.rpeek
---
---@return any
function Iter:last()
local last = self:next()
@ -1016,6 +1004,26 @@ function ListIter:enumerate()
return self
end
---@deprecated
function Iter:nextback()
error('Iter:nextback() was renamed to Iter:pop()')
end
---@deprecated
function Iter:peekback()
error('Iter:peekback() was renamed to Iter:rpeek()')
end
---@deprecated
function Iter:skipback()
error('Iter:skipback() was renamed to Iter:rskip()')
end
---@deprecated
function Iter:nthback()
error('Iter:nthback() was removed, use Iter:nth() with negative index')
end
--- Creates a new Iter object from a table or other |iterable|.
---
---@param src table|function Table or iterator to drain values from

View File

@ -195,10 +195,13 @@ end
--- Predicate used to decide if a client should be re-used. Used on all
--- running clients. The default implementation re-uses a client if name and
--- root_dir matches.
--- @field reuse_client fun(client: vim.lsp.Client, config: table): boolean
--- @field reuse_client fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
---
--- Buffer handle to attach to if starting or re-using a client (0 for current).
--- @field bufnr integer
---
--- Suppress error reporting if the LSP server fails to start (default false).
--- @field silent? boolean
--- Create a new LSP client and start a language server or reuses an already
--- running client if one is found matching `name` and `root_dir`.
@ -246,19 +249,25 @@ function lsp.start(config, opts)
for _, client in pairs(all_clients) do
if reuse_client(client, config) then
lsp.buf_attach_client(bufnr, client.id)
return client.id
if lsp.buf_attach_client(bufnr, client.id) then
return client.id
end
end
end
local client_id = lsp.start_client(config)
if not client_id then
return -- lsp.start_client will have printed an error
local client_id, err = lsp.start_client(config)
if err then
if not opts.silent then
vim.notify(err, vim.log.levels.WARN)
end
return nil
end
lsp.buf_attach_client(bufnr, client_id)
return client_id
if client_id and lsp.buf_attach_client(bufnr, client_id) then
return client_id
end
return nil
end
--- Consumes the latest progress messages from all clients and formats them as a string.
@ -339,7 +348,7 @@ function lsp._set_defaults(client, bufnr)
and is_empty_or_default(bufnr, 'keywordprg')
and vim.fn.maparg('K', 'n', false, false) == ''
then
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr })
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr, desc = 'vim.lsp.buf.hover()' })
end
end)
if client.supports_method(ms.textDocument_diagnostic) then
@ -420,16 +429,18 @@ end
--- Starts and initializes a client with the given configuration.
--- @param config vim.lsp.ClientConfig Configuration for the server.
--- @return integer|nil client_id |vim.lsp.get_client_by_id()| Note: client may not be
--- fully initialized. Use `on_init` to do any actions once
--- the client has been initialized.
--- @return integer? client_id |vim.lsp.get_client_by_id()| Note: client may not be
--- fully initialized. Use `on_init` to do any actions once
--- the client has been initialized.
--- @return string? # Error message, if any
function lsp.start_client(config)
local client = require('vim.lsp.client').create(config)
if not client then
return
local ok, res = pcall(require('vim.lsp.client').create, config)
if not ok then
return nil, res --[[@as string]]
end
local client = assert(res)
--- @diagnostic disable-next-line: invisible
table.insert(client._on_exit_cbs, on_client_exit)
@ -437,31 +448,7 @@ function lsp.start_client(config)
client:initialize()
return client.id
end
--- Notify all attached clients that a buffer has changed.
---@param _ integer
---@param bufnr integer
---@param changedtick integer
---@param firstline integer
---@param lastline integer
---@param new_lastline integer
---@return true?
local function text_document_did_change_handler(
_,
bufnr,
changedtick,
firstline,
lastline,
new_lastline
)
-- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached
if #lsp.get_clients({ bufnr = bufnr }) == 0 then
return true
end
util.buf_versions[bufnr] = changedtick
changetracking.send_changes(bufnr, firstline, lastline, new_lastline)
return client.id, nil
end
---Buffer lifecycle handler for textDocument/didSave
@ -505,11 +492,18 @@ local function text_document_did_save_handler(bufnr)
end
end
--- @type table<integer,true>
local attached_buffers = {}
--- @param bufnr integer
--- @param client_id integer
local function buf_attach(bufnr, client_id)
local function buf_attach(bufnr)
if attached_buffers[bufnr] then
return
end
attached_buffers[bufnr] = true
local uri = vim.uri_from_bufnr(bufnr)
local augroup = ('lsp_c_%d_b_%d_save'):format(client_id, bufnr)
local augroup = ('lsp_b_%d_save'):format(bufnr)
local group = api.nvim_create_augroup(augroup, { clear = true })
api.nvim_create_autocmd('BufWritePre', {
group = group,
@ -548,7 +542,14 @@ local function buf_attach(bufnr, client_id)
})
-- First time, so attach and set up stuff.
api.nvim_buf_attach(bufnr, false, {
on_lines = text_document_did_change_handler,
on_lines = function(_, _, changedtick, firstline, lastline, new_lastline)
if #lsp.get_clients({ bufnr = bufnr }) == 0 then
return true -- detach
end
util.buf_versions[bufnr] = changedtick
changetracking.send_changes(bufnr, firstline, lastline, new_lastline)
end,
on_reload = function()
local params = { textDocument = { uri = uri } }
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
@ -559,6 +560,7 @@ local function buf_attach(bufnr, client_id)
client:_text_document_did_open_handler(bufnr)
end
end,
on_detach = function()
local params = { textDocument = { uri = uri } }
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
@ -571,7 +573,9 @@ local function buf_attach(bufnr, client_id)
client.attached_buffers[bufnr] = nil
end
util.buf_versions[bufnr] = nil
attached_buffers[bufnr] = nil
end,
-- TODO if we know all of the potential clients ahead of time, then we
-- could conditionally set this.
-- utf_sizes = size_index > 1;
@ -597,16 +601,14 @@ function lsp.buf_attach_client(bufnr, client_id)
log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
return false
end
-- This is our first time attaching to this buffer.
if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
buf_attach(bufnr, client_id)
end
local client = lsp.get_client_by_id(client_id)
if not client then
return false
end
buf_attach(bufnr)
if client.attached_buffers[bufnr] then
return true
end

View File

@ -37,7 +37,7 @@ local validate = vim.validate
--- `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()|
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient?
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient
---
--- Directory to launch the `cmd` process. Not related to `root_dir`.
--- (default: cwd)
@ -506,25 +506,17 @@ function Client.create(config)
}
-- Start the RPC client.
local rpc --- @type vim.lsp.rpc.PublicClient?
local config_cmd = config.cmd
if type(config_cmd) == 'function' then
rpc = config_cmd(dispatchers)
self.rpc = config_cmd(dispatchers)
else
rpc = lsp.rpc.start(config_cmd, dispatchers, {
self.rpc = lsp.rpc.start(config_cmd, dispatchers, {
cwd = config.cmd_cwd,
env = config.cmd_env,
detached = config.detached,
})
end
-- Return nil if the rpc client fails to start
if not rpc then
return
end
self.rpc = rpc
setmetatable(self, Client)
return self

View File

@ -41,13 +41,13 @@ function M.on_inlayhint(err, result, ctx, _)
bufstate.client_hints = vim.defaulttable()
bufstate.version = ctx.version
end
local hints_by_client = bufstate.client_hints
local client_hints = bufstate.client_hints
local client = assert(vim.lsp.get_client_by_id(client_id))
local new_hints_by_lnum = vim.defaulttable()
local new_lnum_hints = vim.defaulttable()
local num_unprocessed = #result
if num_unprocessed == 0 then
hints_by_client[client_id] = {}
client_hints[client_id] = {}
bufstate.version = ctx.version
api.nvim__buf_redraw_range(bufnr, 0, -1)
return
@ -73,10 +73,10 @@ function M.on_inlayhint(err, result, ctx, _)
for _, hint in ipairs(result) do
local lnum = hint.position.line
hint.position.character = pos_to_byte(hint.position)
table.insert(new_hints_by_lnum[lnum], hint)
table.insert(new_lnum_hints[lnum], hint)
end
hints_by_client[client_id] = new_hints_by_lnum
client_hints[client_id] = new_lnum_hints
bufstate.version = ctx.version
api.nvim__buf_redraw_range(bufnr, 0, -1)
end
@ -175,19 +175,19 @@ function M.get(filter)
end
--- @type vim.lsp.inlay_hint.get.ret[]
local hints = {}
local result = {}
for _, client in pairs(clients) do
local hints_by_lnum = bufstate.client_hints[client.id]
if hints_by_lnum then
local lnum_hints = bufstate.client_hints[client.id]
if lnum_hints then
for lnum = range.start.line, range['end'].line do
local line_hints = hints_by_lnum[lnum] or {}
for _, hint in pairs(line_hints) do
local hints = lnum_hints[lnum] or {}
for _, hint in pairs(hints) do
local line, char = hint.position.line, hint.position.character
if
(line > range.start.line or char >= range.start.character)
and (line < range['end'].line or char <= range['end'].character)
then
table.insert(hints, {
table.insert(result, {
bufnr = bufnr,
client_id = client.id,
inlay_hint = hint,
@ -197,7 +197,7 @@ function M.get(filter)
end
end
end
return hints
return result
end
--- Clear inlay hints
@ -315,14 +315,14 @@ api.nvim_set_decoration_provider(namespace, {
if not bufstate.client_hints then
return
end
local hints_by_client = assert(bufstate.client_hints)
local client_hints = assert(bufstate.client_hints)
for lnum = topline, botline do
if bufstate.applied[lnum] ~= bufstate.version then
api.nvim_buf_clear_namespace(bufnr, namespace, lnum, lnum + 1)
for _, hints_by_lnum in pairs(hints_by_client) do
local line_hints = hints_by_lnum[lnum] or {}
for _, hint in pairs(line_hints) do
for _, lnum_hints in pairs(client_hints) do
local hints = lnum_hints[lnum] or {}
for _, hint in pairs(hints) do
local text = ''
local label = hint.label
if type(label) == 'string' then

View File

@ -645,9 +645,23 @@ function M.connect(host_or_path, port)
or assert(uv.new_tcp(), 'Could not create new TCP socket')
)
local closing = false
-- Connect returns a PublicClient synchronously so the caller
-- can immediately send messages before the connection is established
-- -> Need to buffer them until that happens
local connected = false
-- size should be enough because the client can't really do anything until initialization is done
-- which required a response from the server - implying the connection got established
local msgbuf = vim.ringbuf(10)
local transport = {
write = function(msg)
handle:write(msg)
if connected then
local _, err = handle:write(msg)
if err and not closing then
log.error('Error on handle:write: %q', err)
end
else
msgbuf:push(msg)
end
end,
is_closing = function()
return closing
@ -679,6 +693,10 @@ function M.connect(host_or_path, port)
handle:read_start(M.create_read_loop(handle_body, transport.terminate, function(read_err)
client:on_error(M.client_errors.READ_ERROR, read_err)
end))
connected = true
for msg in msgbuf do
handle:write(msg)
end
end
if port == nil then
handle:connect(host_or_path, on_connect)
@ -704,7 +722,7 @@ end
--- @param cmd string[] Command to start the LSP server.
--- @param dispatchers? vim.lsp.rpc.Dispatchers
--- @param extra_spawn_params? vim.lsp.rpc.ExtraSpawnParams
--- @return vim.lsp.rpc.PublicClient? : Client RPC object, with these methods:
--- @return vim.lsp.rpc.PublicClient : Client RPC object, with these methods:
--- - `notify()` |vim.lsp.rpc.notify()|
--- - `request()` |vim.lsp.rpc.request()|
--- - `is_closing()` returns a boolean indicating if the RPC is closing.
@ -779,8 +797,7 @@ function M.start(cmd, dispatchers, extra_spawn_params)
end
local msg =
string.format('Spawning language server with cmd: `%s` failed%s', vim.inspect(cmd), sfx)
vim.notify(msg, vim.log.levels.WARN)
return nil
error(msg)
end
sysobj = sysobj_or_err --[[@as vim.SystemObj]]

View File

@ -257,7 +257,7 @@ end
---@param row integer Position row
---@param col integer Position column
---
---@return table[] List of captures `{ capture = "name", metadata = { ... } }`
---@return {capture: string, lang: string, metadata: table}[]
function M.get_captures_at_pos(bufnr, row, col)
if bufnr == 0 then
bufnr = api.nvim_get_current_buf()

View File

@ -258,7 +258,7 @@ function FoldInfo:foldupdate(bufnr, srow, erow)
self.foldupdate_range = { srow, erow }
end
if api.nvim_get_mode().mode == 'i' then
if api.nvim_get_mode().mode:match('^i') then
-- foldUpdate() is guarded in insert mode. So update folds on InsertLeave
if #(api.nvim_get_autocmds({
group = group,

View File

@ -47,8 +47,8 @@ typedef struct {
#define VALID_VIRTCOL 0x04 // w_virtcol (file col) is valid
#define VALID_CHEIGHT 0x08 // w_cline_height and w_cline_folded valid
#define VALID_CROW 0x10 // w_cline_row is valid
#define VALID_BOTLINE 0x20 // w_botine and w_empty_rows are valid
#define VALID_BOTLINE_AP 0x40 // w_botine is approximated
#define VALID_BOTLINE 0x20 // w_botline and w_empty_rows are valid
#define VALID_BOTLINE_AP 0x40 // w_botline is approximated
#define VALID_TOPLINE 0x80 // w_topline is valid (for cursor position)
// flags for b_flags

View File

@ -918,15 +918,15 @@ char *ExpandOne(expand_T *xp, char *str, char *orig, int options, int mode)
for (int i = 0; i < xp->xp_numfiles; i++) {
if (i > 0) {
if (xp->xp_prefix == XP_PREFIX_NO) {
ssp = xstpcpy(ssp, "no");
ssp = STPCPY(ssp, "no");
} else if (xp->xp_prefix == XP_PREFIX_INV) {
ssp = xstpcpy(ssp, "inv");
ssp = STPCPY(ssp, "inv");
}
}
ssp = xstpcpy(ssp, xp->xp_files[i]);
ssp = STPCPY(ssp, xp->xp_files[i]);
if (i != xp->xp_numfiles - 1) {
ssp = xstpcpy(ssp, (options & WILD_USE_NL) ? "\n" : " ");
ssp = STPCPY(ssp, (options & WILD_USE_NL) ? "\n" : " ");
}
}
}

View File

@ -11621,6 +11621,10 @@ M.funcs = {
synconcealed(lnum, 4) [1, 'X', 2]
synconcealed(lnum, 5) [1, 'X', 2]
synconcealed(lnum, 6) [0, '', 0]
Note: Doesn't consider |matchadd()| highlighting items,
since syntax and matching highlighting are two different
mechanisms |syntax-vs-match|.
]=],
name = 'synconcealed',
params = { { 'lnum', 'integer' }, { 'col', 'integer' } },

View File

@ -156,8 +156,8 @@ char *ga_concat_strings_sep(const garray_T *gap, const char *sep)
char *s = ret;
for (size_t i = 0; i < nelem - 1; i++) {
s = xstpcpy(s, strings[i]);
s = xstpcpy(s, sep);
s = STPCPY(s, strings[i]);
s = STPCPY(s, sep);
}
strcpy(s, strings[nelem - 1]); // NOLINT(runtime/printf)

View File

@ -333,7 +333,7 @@ int ml_open(buf_T *buf)
b0p->b0_magic_int = B0_MAGIC_INT;
b0p->b0_magic_short = (int16_t)B0_MAGIC_SHORT;
b0p->b0_magic_char = B0_MAGIC_CHAR;
xstrlcpy(xstpcpy(b0p->b0_version, "VIM "), Version, 6);
xstrlcpy(STPCPY(b0p->b0_version, "VIM "), Version, 6);
long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
if (!buf->b_spell) {

View File

@ -347,43 +347,16 @@ size_t memcnt(const void *data, char c, size_t len)
return cnt;
}
/// Copies the string pointed to by src (including the terminating NUL
/// character) into the array pointed to by dst.
///
/// @returns pointer to the terminating NUL char copied into the dst buffer.
/// This is the only difference with strcpy(), which returns dst.
///
/// WARNING: If copying takes place between objects that overlap, the behavior
/// is undefined.
///
/// Nvim version of POSIX 2008 stpcpy(3). We do not require POSIX 2008, so
/// implement our own version.
///
/// @param dst
/// @param src
#ifndef HAVE_STPCPY
char *xstpcpy(char *restrict dst, const char *restrict src)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
const size_t len = strlen(src);
return (char *)memcpy(dst, src, len + 1) + len;
}
#endif
/// Copies not more than n bytes (bytes that follow a NUL character are not
/// copied) from the array pointed to by src to the array pointed to by dst.
///
/// If a NUL character is written to the destination, xstpncpy() returns the
/// address of the first such NUL character. Otherwise, it shall return
/// &dst[maxlen].
///
/// WARNING: If copying takes place between objects that overlap, the behavior
/// is undefined.
///
/// WARNING: xstpncpy will ALWAYS write maxlen bytes. If src is shorter than
/// maxlen, zeroes will be written to the remaining bytes.
///
/// @param dst
/// @param src
/// @param maxlen
#ifndef HAVE_STPNCPY
char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
@ -398,6 +371,7 @@ char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
return dst + maxlen;
}
}
#endif
/// xstrlcpy - Copy a NUL-terminated string into a sized buffer
///

View File

@ -68,6 +68,19 @@ EXTERN size_t arena_alloc_count INIT( = 0);
# define strnlen xstrnlen // Older versions of SunOS may not have strnlen
#endif
// MacOS doesn't have HAVE_STPCPY defined and defines its own stpcpy in Xcode. So just define STPCPY
#ifdef HAVE_STPCPY
# define STPCPY stpcpy
#else
# define STPCPY xstpcpy
#endif
#ifdef HAVE_STPNCPY
# define STPNCPY stpncpy
#else
# define STPNCPY xstpncpy
#endif
#define STRCPY(d, s) strcpy((char *)(d), (char *)(s)) // NOLINT(runtime/printf)
// Like strcpy() but allows overlapped source and destination.

View File

@ -2467,6 +2467,7 @@ void win_init_empty(win_T *wp)
wp->w_topline = 1;
wp->w_topfill = 0;
wp->w_botline = 2;
wp->w_valid = 0;
wp->w_s = &wp->w_buffer->b_s;
}

View File

@ -169,19 +169,19 @@ describe('vim.iter', function()
end
end)
it('skipback()', function()
it('rskip()', function()
do
local q = { 4, 3, 2, 1 }
eq(q, vim.iter(q):skipback(0):totable())
eq({ 4, 3, 2 }, vim.iter(q):skipback(1):totable())
eq({ 4, 3 }, vim.iter(q):skipback(2):totable())
eq({ 4 }, vim.iter(q):skipback(#q - 1):totable())
eq({}, vim.iter(q):skipback(#q):totable())
eq({}, vim.iter(q):skipback(#q + 1):totable())
eq(q, vim.iter(q):rskip(0):totable())
eq({ 4, 3, 2 }, vim.iter(q):rskip(1):totable())
eq({ 4, 3 }, vim.iter(q):rskip(2):totable())
eq({ 4 }, vim.iter(q):rskip(#q - 1):totable())
eq({}, vim.iter(q):rskip(#q):totable())
eq({}, vim.iter(q):rskip(#q + 1):totable())
end
local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
matches('skipback%(%) requires a list%-like table', pcall_err(it.skipback, it, 0))
matches('rskip%(%) requires a list%-like table', pcall_err(it.rskip, it, 0))
end)
it('slice()', function()
@ -222,19 +222,19 @@ describe('vim.iter', function()
end
end)
it('nthback()', function()
it('nth(-x) advances in reverse order starting from end', function()
do
local q = { 4, 3, 2, 1 }
eq(nil, vim.iter(q):nthback(0))
eq(1, vim.iter(q):nthback(1))
eq(2, vim.iter(q):nthback(2))
eq(3, vim.iter(q):nthback(3))
eq(4, vim.iter(q):nthback(4))
eq(nil, vim.iter(q):nthback(5))
eq(nil, vim.iter(q):nth(0))
eq(1, vim.iter(q):nth(-1))
eq(2, vim.iter(q):nth(-2))
eq(3, vim.iter(q):nth(-3))
eq(4, vim.iter(q):nth(-4))
eq(nil, vim.iter(q):nth(-5))
end
local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
matches('skipback%(%) requires a list%-like table', pcall_err(it.nthback, it, 1))
matches('rskip%(%) requires a list%-like table', pcall_err(it.nth, it, -1))
end)
it('take()', function()
@ -421,34 +421,34 @@ describe('vim.iter', function()
end
end)
it('nextback()', function()
it('pop()', function()
do
local it = vim.iter({ 1, 2, 3, 4 })
eq(4, it:nextback())
eq(3, it:nextback())
eq(2, it:nextback())
eq(1, it:nextback())
eq(nil, it:nextback())
eq(nil, it:nextback())
eq(4, it:pop())
eq(3, it:pop())
eq(2, it:pop())
eq(1, it:pop())
eq(nil, it:pop())
eq(nil, it:pop())
end
do
local it = vim.iter(vim.gsplit('hi', ''))
matches('nextback%(%) requires a list%-like table', pcall_err(it.nextback, it))
matches('pop%(%) requires a list%-like table', pcall_err(it.pop, it))
end
end)
it('peekback()', function()
it('rpeek()', function()
do
local it = vim.iter({ 1, 2, 3, 4 })
eq(4, it:peekback())
eq(4, it:peekback())
eq(4, it:nextback())
eq(4, it:rpeek())
eq(4, it:rpeek())
eq(4, it:pop())
end
do
local it = vim.iter(vim.gsplit('hi', ''))
matches('peekback%(%) requires a list%-like table', pcall_err(it.peekback, it))
matches('rpeek%(%) requires a list%-like table', pcall_err(it.rpeek, it))
end
end)

View File

@ -192,6 +192,7 @@ describe(':Man', function()
'--headless',
'+autocmd VimLeave * echo "quit works!!"',
'+Man!',
'+tag ls',
'+call nvim_input("q")',
}
matches('quit works!!', fn.system(args, { 'manpage contents' }))

View File

@ -4105,4 +4105,16 @@ func Test_SwapExists_set_other_buf_modified()
bwipe!
endfunc
func Test_BufEnter_botline()
set hidden
call writefile(range(10), 'Xxx1', 'D')
call writefile(range(20), 'Xxx2', 'D')
edit Xxx1
edit Xxx2
au BufEnter Xxx1 call assert_true(line('w$') > 1)
edit Xxx1
au! BufEnter Xxx1
set hidden&vim
endfunc
" vim: shiftwidth=2 sts=2 expandtab