mirror of
https://github.com/neovim/neovim.git
synced 2026-11-06 05:16:52 +00:00
ci(lua): enable annotation and style checks
Problem: - annotation-usage-error and code-style-check are disabled. - vim.inspect relies on a dummy self-assignment for docgen, and its help omits parameter and option details. - LuaLS fallback types obscure iterator inference. - Docgen hardcodes public function names and appends separately sorted files, leaving shared helpers under the inspector heading. Solution: - Enable annotation-usage-error and code-style-check, and fix misplaced annotations. - Document vim.inspect's callable module directly, removing the dummy assignment. Describe its parameters, option defaults and process callback. - Remove LuaLS iterator fallbacks, correct iterator signatures and check values that the improved inference identifies as optional. - Parse callable modules, require bindings and parent module references. Derive public names and inherited function docs from these links, including missing help for vim.async.semaphore() and vim.version(). - Export vim.lsp.tagfunc directly with lazy loading and document its implementation instead of maintaining a wrapper. - Group files in section_order, replacing append_only and merge_files. Merge declarations before sorting each section, placing shared helpers in the main vim section and keeping vim.inspect in alphabetical order. - Add basic parser coverage for callable modules and module links. AI-assisted
This commit is contained in:
1 parent
9f7fb8b27d
commit
364b7a3402
28 files changed
+919
-711
No files matched your search
+1
-2
@@ -27,8 +27,6 @@
|
||||
},
|
||||
"diagnostics": {
|
||||
"disable": [
|
||||
"annotation-usage-error",
|
||||
"code-style-check",
|
||||
"incomplete-signature-doc",
|
||||
"iter-variable-reassign",
|
||||
"unnecessary-if"
|
||||
@@ -42,6 +40,7 @@
|
||||
"unused": "warning"
|
||||
},
|
||||
"enables": [
|
||||
"code-style-check",
|
||||
"missing-global-doc",
|
||||
"non-literal-expressions-in-assert",
|
||||
"unknown-doc-tag"
|
||||
|
||||
@@ -248,6 +248,7 @@ Docstring format:
|
||||
0), it is marked as "experimental".
|
||||
- See scripts/util.lua for the mapping of api-level to Nvim version.
|
||||
- Use `@deprecated` to mark deprecated functions.
|
||||
- For callable module tables, document `__call` in `setmetatable(M, { ... })`.
|
||||
- Use `@nodoc` to prevent documentation generation.
|
||||
- Use `@private` for private functions.
|
||||
- Naming a function with an underscore prefix ("_foo", not "foo") implies
|
||||
|
||||
@@ -380,6 +380,20 @@ run({func}, {...}) *vim.async.run()*
|
||||
Return: ~
|
||||
(`vim.async.Task<R...>`)
|
||||
|
||||
semaphore({permits}) *vim.async.semaphore()*
|
||||
Create an async semaphore that allows up to a given number of
|
||||
acquisitions.
|
||||
|
||||
Prefer |Semaphore:with()| for most uses so permits are released reliably.
|
||||
Use |Semaphore:acquire()| and |Semaphore:release()| directly only when the
|
||||
acquire and release points cannot be expressed as one function call.
|
||||
|
||||
Parameters: ~
|
||||
• {permits} (`integer?`) (default: 1)
|
||||
|
||||
Return: ~
|
||||
(`vim.async.Semaphore`)
|
||||
|
||||
Semaphore:acquire() *Semaphore:acquire()*
|
||||
Acquire a semaphore permit.
|
||||
|
||||
|
||||
+456
-446
@@ -1182,6 +1182,36 @@ vim.wo[{winid}][{bufnr}] *vim.wo*
|
||||
==============================================================================
|
||||
Lua module: vim *lua-vim*
|
||||
|
||||
*vim.Ringbuf*
|
||||
|
||||
Fields: ~
|
||||
• {clear} (`fun()`) See |Ringbuf:clear()|.
|
||||
• {peek} (`fun(): T?`) See |Ringbuf:peek()|.
|
||||
• {pop} (`fun(): T?`) See |Ringbuf:pop()|.
|
||||
• {push} (`fun(item: T)`) See |Ringbuf:push()|.
|
||||
|
||||
|
||||
Ringbuf:clear() *Ringbuf:clear()*
|
||||
Clear all items
|
||||
|
||||
Ringbuf:peek() *Ringbuf:peek()*
|
||||
Returns the first unread item without removing it
|
||||
|
||||
Return: ~
|
||||
(`T?`)
|
||||
|
||||
Ringbuf:pop() *Ringbuf:pop()*
|
||||
Removes and returns the first unread item
|
||||
|
||||
Return: ~
|
||||
(`T?`)
|
||||
|
||||
Ringbuf:push({item}) *Ringbuf:push()*
|
||||
Adds an item, overriding the oldest item if the buffer is full.
|
||||
|
||||
Parameters: ~
|
||||
• {item} (`T`)
|
||||
|
||||
vim.cmd({cmd}) *vim.cmd()*
|
||||
Executes Vimscript (|Ex-command|s).
|
||||
|
||||
@@ -1228,443 +1258,6 @@ vim.cmd({cmd}) *vim.cmd()*
|
||||
See also: ~
|
||||
• |ex-cmd-index|
|
||||
|
||||
vim.defer_fn({fn}, {timeout}) *vim.defer_fn()*
|
||||
Defers calling {fn} until {timeout} ms passes.
|
||||
|
||||
Use to do a one-shot timer that calls {fn}. Note: The {fn} is |schedule|d
|
||||
automatically, so API functions are safe to call.
|
||||
|
||||
Parameters: ~
|
||||
• {fn} (`function`) Callback to call once `timeout` expires
|
||||
• {timeout} (`integer`) Number of milliseconds to wait before calling
|
||||
`fn`
|
||||
|
||||
Return: ~
|
||||
(`uv.uv_timer_t`) timer luv timer object
|
||||
|
||||
*vim.deprecate()*
|
||||
vim.deprecate({name}, {alternative}, {version}, {plugin}, {backtrace})
|
||||
Shows a deprecation message to the user.
|
||||
|
||||
Parameters: ~
|
||||
• {name} (`string`) Deprecated feature (function, API, etc.).
|
||||
• {alternative} (`string?`) Suggested alternative feature.
|
||||
• {version} (`string`) Version when the deprecated function will be
|
||||
removed.
|
||||
• {plugin} (`string?`) Name of the plugin that owns the deprecated
|
||||
feature. Defaults to "Nvim".
|
||||
• {backtrace} (`boolean?`) Prints backtrace. Defaults to true.
|
||||
|
||||
Return: ~
|
||||
(`string?`) Deprecation message, or nil if no message was shown.
|
||||
|
||||
vim.inspect() *vim.inspect()*
|
||||
Gets a human-readable representation of the given object.
|
||||
|
||||
Overloads: ~
|
||||
• `fun(x: any, opts?: vim.inspect.Opts): string`
|
||||
|
||||
Return: ~
|
||||
(`string`)
|
||||
|
||||
See also: ~
|
||||
• |vim.print()|
|
||||
• https://github.com/kikito/inspect.lua
|
||||
• https://github.com/mpeterv/vinspect
|
||||
|
||||
vim.keycode({keys}, {info}) *vim.keycode()*
|
||||
Converts keys from |key-notation| to the internal encoding. Optionally
|
||||
returns structured *key-chord* info as retval 2.
|
||||
|
||||
Inverse of |keytrans()|, which converts the internal encoding back to
|
||||
|key-notation|.
|
||||
|
||||
Examples: >lua
|
||||
local k = vim.keycode
|
||||
vim.g.mapleader = k'<bs>'
|
||||
|
||||
-- Split a key sequence into chords, e.g. to inspect modifiers.
|
||||
local _, chords = vim.keycode('<C-w>v', true)
|
||||
assert(chords[1].key == 'w' and chords[1].mod[1] == 'C')
|
||||
|
||||
-- keytrans() is the inverse: internal encoding => key-notation.
|
||||
assert(vim.fn.keytrans(vim.keycode('<C-a>')) == '<C-A>')
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {keys} (`string`) Keys in |key-notation|.
|
||||
• {info} (`boolean?`) Also return key-chord info.
|
||||
|
||||
Return (multiple): ~
|
||||
(`string`) Internal representation of the given `keys`.
|
||||
(`table?`) List of parsed key-chords, each with fields:
|
||||
• {key} (`string`) Key without modifiers. Example: `<C-A>` has
|
||||
`key="a"`.
|
||||
• {key_alt} (`string?`) Alternative spelling of `key`, or nil if There
|
||||
Is No Alternative (TINA). Example: `"<"` has `key_alt="lt"`.
|
||||
• {keys} (`string`) Full key-chord in canonical key-notation (as
|
||||
produced by |keytrans()|), including modifiers. Example: `<A-f>` has
|
||||
`keys="<M-f>"`.
|
||||
• {mod} (`('M'|'T'|'C'|'S'|'2'|'3'|'4'|'D')[]`) List of key-chord
|
||||
modifiers. Example: `<C-S-f>` has `mod={ 'C', 'S' }`.
|
||||
|
||||
See also: ~
|
||||
• |nvim_replace_termcodes()|
|
||||
• |keytrans()|
|
||||
|
||||
vim.lua_omnifunc({find_start}) *vim.lua_omnifunc()*
|
||||
Omnifunc for completing Lua values from the runtime Lua interpreter,
|
||||
similar to the builtin completion for the `:lua` command.
|
||||
|
||||
Activate using `vim.bo.omnifunc = vim.lua_omnifunc` in a Lua buffer.
|
||||
|
||||
Parameters: ~
|
||||
• {find_start} (`1|0`)
|
||||
|
||||
vim.notify({msg}, {level}, {opts}) *vim.notify()*
|
||||
Displays a notification to the user.
|
||||
|
||||
This function can be overridden by plugins to display notifications using
|
||||
a custom provider (such as the system notification provider). By default,
|
||||
writes to |:messages|.
|
||||
|
||||
Parameters: ~
|
||||
• {msg} (`string`) Content of the notification to show to the user.
|
||||
• {level} (`integer?`) One of the values from |vim.log.levels|.
|
||||
• {opts} (`table?`) Optional parameters. Unused by default.
|
||||
|
||||
vim.notify_once({msg}, {level}, {opts}) *vim.notify_once()*
|
||||
Displays a notification only one time.
|
||||
|
||||
Like |vim.notify()|, but subsequent calls with the same message will not
|
||||
display a notification.
|
||||
|
||||
Parameters: ~
|
||||
• {msg} (`string`) Content of the notification to show to the user.
|
||||
• {level} (`integer?`) One of the values from |vim.log.levels|.
|
||||
• {opts} (`table?`) Optional parameters. Unused by default.
|
||||
|
||||
Return: ~
|
||||
(`boolean`) true if message was displayed, else false
|
||||
|
||||
vim.on_key({fn}, {ns_id}, {opts}) *vim.on_key()*
|
||||
Registers function {fn} with |namespace| {ns_id} as a listener to EVERY
|
||||
input key (except keys consumed by |getchar()|, by {fn} itself, or by a
|
||||
<Cmd> payload).
|
||||
|
||||
To parse |key-chord|s, see |vim.keycode()|. Example: >lua
|
||||
local keychords = vim.keycode(vim.fn.keytrans(key), true)
|
||||
<
|
||||
|
||||
Note: ~
|
||||
• If {fn} returns an empty string, {key} is discarded/ignored; if {key}
|
||||
is <Cmd> then the "<Cmd>…<CR>" sequence is discarded as a whole.
|
||||
• Non-recursive: if {fn} itself consumes input, it won't be invoked for
|
||||
those keys.
|
||||
• Not invoked for keys consumed by getchar()/getcharstr(): they never
|
||||
reach the main loop.
|
||||
• To UNregister a given {ns_id}, pass `nil` {fn}.
|
||||
• {fn} will be removed on error.
|
||||
• {fn} will not be cleared by |nvim_buf_clear_namespace()|
|
||||
• The |-w| command-line option is related but does not support callbacks
|
||||
and cannot be toggled dynamically.
|
||||
|
||||
Parameters: ~
|
||||
• {fn} (`fun(key: string, typed: string): string??`) Function
|
||||
invoked for every input key, after mappings have been applied
|
||||
but before further processing. Arguments {key} and {typed}
|
||||
are raw input (use |keytrans()| to get |keycodes|).
|
||||
• {key} is the key after mappings are applied.
|
||||
• {typed} is the input before mappings are applied; may be
|
||||
empty if {key} was produced by non-typed key(s) or by the
|
||||
same typed key(s) that produced a previous {key}.
|
||||
• {ns_id} (`integer?`) Namespace ID. If nil or 0, returns a new
|
||||
|namespace| id.
|
||||
• {opts} (`table?`) Optional parameters
|
||||
|
||||
Return: ~
|
||||
(`integer`) Namespace id associated with {fn}. Or count of all
|
||||
callbacks if on_key() is called without arguments.
|
||||
|
||||
See also: ~
|
||||
• |keytrans()|
|
||||
• |vim.keycode()|
|
||||
|
||||
vim.paste({lines}, {phase}) *vim.paste()*
|
||||
Paste handler, invoked by |nvim_paste()|.
|
||||
|
||||
Note: This is provided only as a "hook", don't call it directly; call
|
||||
|nvim_paste()| instead, which arranges redo (dot-repeat) and invokes
|
||||
`vim.paste`.
|
||||
|
||||
Example: To remove ANSI color codes when pasting: >lua
|
||||
vim.paste = (function(overridden)
|
||||
return function(lines, phase)
|
||||
for i,line in ipairs(lines) do
|
||||
-- Scrub ANSI color codes from paste input.
|
||||
lines[i] = line:gsub('\27%[[0-9;mK]+', '')
|
||||
end
|
||||
return overridden(lines, phase)
|
||||
end
|
||||
end)(vim.paste)
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {lines} (`string[]`) |readfile()|-style list of lines to paste.
|
||||
|channel-lines|
|
||||
• {phase} (`-1|1|2|3`) -1: "non-streaming" paste: the call contains all
|
||||
lines. If paste is "streamed", `phase` indicates the stream
|
||||
state:
|
||||
• 1: starts the paste (exactly once)
|
||||
• 2: continues the paste (zero or more times)
|
||||
• 3: ends the paste (exactly once)
|
||||
|
||||
Return: ~
|
||||
(`boolean`) result false if client should cancel the paste.
|
||||
|
||||
See also: ~
|
||||
• |paste|
|
||||
|
||||
vim.print({...}) *vim.print()*
|
||||
"Pretty prints" the given arguments and returns them unmodified.
|
||||
|
||||
Example: >lua
|
||||
local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' }))
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {...} (`any`)
|
||||
|
||||
Return: ~
|
||||
(`any`) given arguments.
|
||||
|
||||
See also: ~
|
||||
• |vim.inspect()|
|
||||
• |:=|
|
||||
|
||||
vim.schedule_wrap({fn}) *vim.schedule_wrap()*
|
||||
Returns a function which calls {fn} via |vim.schedule()|.
|
||||
|
||||
The returned function passes all arguments to {fn}.
|
||||
|
||||
Example: >lua
|
||||
function notify_readable(_err, readable)
|
||||
vim.notify("readable? " .. tostring(readable))
|
||||
end
|
||||
vim.uv.fs_access(vim.fn.stdpath("config"), "R", vim.schedule_wrap(notify_readable))
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {fn} (`function`)
|
||||
|
||||
Return: ~
|
||||
(`function`)
|
||||
|
||||
See also: ~
|
||||
• |lua-loop-callbacks|
|
||||
• |vim.schedule()|
|
||||
• |vim.in_fast_event()|
|
||||
|
||||
*vim.str_byteindex()*
|
||||
vim.str_byteindex({s}, {encoding}, {index}, {strict_indexing})
|
||||
Convert UTF-32, UTF-16 or UTF-8 {index} to byte index. If
|
||||
{strict_indexing} is false then an out of range index will return byte
|
||||
length instead of throwing an error.
|
||||
|
||||
Invalid UTF-8 and NUL is treated like in |vim.str_utfindex()|. An {index}
|
||||
in the middle of a UTF-16 sequence is rounded upwards to the end of that
|
||||
sequence.
|
||||
|
||||
Parameters: ~
|
||||
• {s} (`string`)
|
||||
• {encoding} (`"utf-8"|"utf-16"|"utf-32"`)
|
||||
• {index} (`integer`)
|
||||
• {strict_indexing} (`boolean?`) default: true
|
||||
|
||||
Return: ~
|
||||
(`integer`)
|
||||
|
||||
*vim.str_utfindex()*
|
||||
vim.str_utfindex({s}, {encoding}, {index}, {strict_indexing})
|
||||
Convert byte index to UTF-32, UTF-16 or UTF-8 indices. If {index} is not
|
||||
supplied, the length of the string is used. All indices are zero-based.
|
||||
|
||||
If {strict_indexing} is false then an out of range index will return
|
||||
string length instead of throwing an error. Invalid UTF-8 bytes, and
|
||||
embedded surrogates are counted as one code point each. An {index} in the
|
||||
middle of a UTF-8 sequence is rounded upwards to the end of that sequence.
|
||||
|
||||
Parameters: ~
|
||||
• {s} (`string`)
|
||||
• {encoding} (`"utf-8"|"utf-16"|"utf-32"`)
|
||||
• {index} (`integer?`)
|
||||
• {strict_indexing} (`boolean?`) default: true
|
||||
|
||||
Return: ~
|
||||
(`integer`)
|
||||
|
||||
vim.wait({time}, {callback}, {interval}, {fast_only}) *vim.wait()*
|
||||
Waits up to `time` milliseconds, until `callback` returns `true`
|
||||
(success). Executes `callback` immediately, then on user events, internal
|
||||
events, and approximately every `interval` milliseconds (default 200).
|
||||
Returns `true` plus any remaining callback results on success.
|
||||
|
||||
Nvim processes other events while waiting. Cannot be called during an
|
||||
|api-fast| event.
|
||||
|
||||
Examples: >lua
|
||||
-- Wait for 100 ms, allowing other events to process.
|
||||
vim.wait(100)
|
||||
|
||||
-- Wait up to 1000 ms or until `vim.g.foo` is true, at intervals of ~500 ms.
|
||||
vim.wait(1000, function() return vim.g.foo end, 500)
|
||||
|
||||
-- Wait indefinitely until `vim.g.foo` is true, and get the callback results.
|
||||
local ok, rv1, rv2, rv3 = vim.wait(math.huge, function()
|
||||
return vim.g.foo, 'a', 42, { ok = { 'yes' } }
|
||||
end)
|
||||
|
||||
-- Schedule a function to set a value in 100ms. This would wait 10s if blocked, but actually
|
||||
-- only waits 100ms because `vim.wait` processes other events while waiting.
|
||||
vim.defer_fn(function() vim.g.timer_result = true end, 100)
|
||||
if vim.wait(10000, function() return vim.g.timer_result end) then
|
||||
print('Only waiting a little bit of time!')
|
||||
end
|
||||
|
||||
-- Yield via vim.wait() to allow CTRL-C to interrupt Lua code.
|
||||
while true do
|
||||
-- ...work...
|
||||
local _, code = vim.wait(0, nil, 0)
|
||||
if code == -2 then -- CTRL-C.
|
||||
break
|
||||
end
|
||||
end
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {time} (`number`) Number of milliseconds to wait. Must be
|
||||
non-negative number, any fractional part is truncated.
|
||||
• {callback} (`fun(): boolean, ...?`) Optional callback. Waits until
|
||||
{callback} returns true
|
||||
• {interval} (`integer?`) (Approximate) number of milliseconds to wait
|
||||
between polls
|
||||
• {fast_only} (`boolean?`) If true, only |api-fast| events will be
|
||||
processed.
|
||||
|
||||
Return (multiple): ~
|
||||
(`boolean`)
|
||||
(`-1|-2?`)
|
||||
• If callback returns `true` before timeout: `true, ...` (remaining
|
||||
callback results).
|
||||
• On timeout: `false, -1`
|
||||
• On interrupt: `false, -2`
|
||||
• On error: the error is raised.
|
||||
|
||||
|
||||
==============================================================================
|
||||
Lua module: vim.inspector *vim.inspector*
|
||||
|
||||
vim.inspect_pos({buf}, {row}, {col}, {filter}) *vim.inspect_pos()*
|
||||
Get all the items at a given buffer position.
|
||||
|
||||
Can also be pretty-printed with `:Inspect!`. *:Inspect!*
|
||||
|
||||
Attributes: ~
|
||||
Since: 0.9.0
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer?`) defaults to the current buffer
|
||||
• {row} (`integer?`) row to inspect, 0-based. Defaults to the row of
|
||||
the current cursor
|
||||
• {col} (`integer?`) col to inspect, 0-based. Defaults to the col of
|
||||
the current cursor
|
||||
• {filter} (`table?`) Table with key-value pairs to filter the items
|
||||
• {extmarks} (`boolean|"all"`, default: true) Include
|
||||
extmarks. When `all`, then extmarks without a `hl_group`
|
||||
will also be included.
|
||||
• {semantic_tokens} (`boolean`, default: true) Include
|
||||
semantic token highlights.
|
||||
• {syntax} (`boolean`, default: `true`) Include syntax based
|
||||
highlight groups.
|
||||
• {treesitter} (`boolean`, default: `true`) Include
|
||||
treesitter based highlight groups.
|
||||
|
||||
Return: ~
|
||||
(`table`) a table with the following key-value pairs. Items are in
|
||||
"traversal order":
|
||||
• treesitter: a list of treesitter captures
|
||||
• syntax: a list of syntax groups
|
||||
• semantic_tokens: a list of semantic tokens
|
||||
• extmarks: a list of extmarks
|
||||
• buffer: the buffer used to get the items
|
||||
• row: the row used to get the items
|
||||
• col: the col used to get the items
|
||||
|
||||
vim.show_pos({buf}, {row}, {col}, {filter}) *vim.show_pos()*
|
||||
Show all the items at a given buffer position.
|
||||
|
||||
Can also be shown with `:Inspect`. *:Inspect*
|
||||
|
||||
See also |:marks| to list all extmarks.
|
||||
|
||||
Example: To bind this function to the vim-scriptease inspired `zS` in
|
||||
Normal mode: >lua
|
||||
vim.keymap.set('n', 'zS', vim.show_pos)
|
||||
<
|
||||
|
||||
Attributes: ~
|
||||
Since: 0.9.0
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer?`) defaults to the current buffer
|
||||
• {row} (`integer?`) row to inspect, 0-based. Defaults to the row of
|
||||
the current cursor
|
||||
• {col} (`integer?`) col to inspect, 0-based. Defaults to the col of
|
||||
the current cursor
|
||||
• {filter} (`table?`) A table with the following fields:
|
||||
• {extmarks} (`boolean|"all"`, default: true) Include
|
||||
extmarks. When `all`, then extmarks without a `hl_group`
|
||||
will also be included.
|
||||
• {semantic_tokens} (`boolean`, default: true) Include
|
||||
semantic token highlights.
|
||||
• {syntax} (`boolean`, default: `true`) Include syntax based
|
||||
highlight groups.
|
||||
• {treesitter} (`boolean`, default: `true`) Include
|
||||
treesitter based highlight groups.
|
||||
|
||||
|
||||
|
||||
|
||||
*vim.Ringbuf*
|
||||
|
||||
Fields: ~
|
||||
• {clear} (`fun()`) See |Ringbuf:clear()|.
|
||||
• {peek} (`fun(): T?`) See |Ringbuf:peek()|.
|
||||
• {pop} (`fun(): T?`) See |Ringbuf:pop()|.
|
||||
• {push} (`fun(item: T)`) See |Ringbuf:push()|.
|
||||
|
||||
|
||||
Ringbuf:clear() *Ringbuf:clear()*
|
||||
Clear all items
|
||||
|
||||
Ringbuf:peek() *Ringbuf:peek()*
|
||||
Returns the first unread item without removing it
|
||||
|
||||
Return: ~
|
||||
(`T?`)
|
||||
|
||||
Ringbuf:pop() *Ringbuf:pop()*
|
||||
Removes and returns the first unread item
|
||||
|
||||
Return: ~
|
||||
(`T?`)
|
||||
|
||||
Ringbuf:push({item}) *Ringbuf:push()*
|
||||
Adds an item, overriding the oldest item if the buffer is full.
|
||||
|
||||
Parameters: ~
|
||||
• {item} (`T`)
|
||||
|
||||
vim.deep_equal({a}, {b}) *vim.deep_equal()*
|
||||
Deep compare values for equality
|
||||
|
||||
@@ -1718,6 +1311,36 @@ vim.defaulttable({createfn}) *vim.defaulttable()*
|
||||
Return: ~
|
||||
(`table`) Empty table with `__index` metamethod.
|
||||
|
||||
vim.defer_fn({fn}, {timeout}) *vim.defer_fn()*
|
||||
Defers calling {fn} until {timeout} ms passes.
|
||||
|
||||
Use to do a one-shot timer that calls {fn}. Note: The {fn} is |schedule|d
|
||||
automatically, so API functions are safe to call.
|
||||
|
||||
Parameters: ~
|
||||
• {fn} (`function`) Callback to call once `timeout` expires
|
||||
• {timeout} (`integer`) Number of milliseconds to wait before calling
|
||||
`fn`
|
||||
|
||||
Return: ~
|
||||
(`uv.uv_timer_t`) timer luv timer object
|
||||
|
||||
*vim.deprecate()*
|
||||
vim.deprecate({name}, {alternative}, {version}, {plugin}, {backtrace})
|
||||
Shows a deprecation message to the user.
|
||||
|
||||
Parameters: ~
|
||||
• {name} (`string`) Deprecated feature (function, API, etc.).
|
||||
• {alternative} (`string?`) Suggested alternative feature.
|
||||
• {version} (`string`) Version when the deprecated function will be
|
||||
removed.
|
||||
• {plugin} (`string?`) Name of the plugin that owns the deprecated
|
||||
feature. Defaults to "Nvim".
|
||||
• {backtrace} (`boolean?`) Prints backtrace. Defaults to true.
|
||||
|
||||
Return: ~
|
||||
(`string?`) Deprecation message, or nil if no message was shown.
|
||||
|
||||
vim.endswith({s}, {suffix}) *vim.endswith()*
|
||||
Tests if `s` ends with `suffix`.
|
||||
|
||||
@@ -1764,6 +1387,34 @@ vim.gsplit({s}, {sep}, {opts}) *vim.gsplit()*
|
||||
• https://www.lua.org/pil/20.2.html
|
||||
• http://lua-users.org/wiki/StringLibraryTutorial
|
||||
|
||||
vim.inspect({root}, {options}) *vim.inspect()*
|
||||
Gets a human-readable representation of the given object.
|
||||
|
||||
Parameters: ~
|
||||
• {root} (`any`)
|
||||
• {options} (`table?`) A table with the following fields:
|
||||
• {depth}? (`integer`, default: unlimited) Maximum table
|
||||
nesting depth. Deeper tables are shown as `{...}`.
|
||||
• {indent}? (`string`, default: `" "`) String repeated for
|
||||
each level of indentation.
|
||||
• {newline}? (`string`, default: `"\n"`) String used for
|
||||
line breaks.
|
||||
• {process}? (`fun(item: any, path: any[]): any`)
|
||||
Transforms values, keys, and metatables before
|
||||
formatting. Return a replacement value, or `nil` to omit
|
||||
a table entry. {path} lists the keys leading to {item},
|
||||
with `vim.inspect.KEY` appended for keys or
|
||||
`vim.inspect.METATABLE` for metatables. The root has an
|
||||
empty path.
|
||||
|
||||
Return: ~
|
||||
(`string`)
|
||||
|
||||
See also: ~
|
||||
• |vim.print()|
|
||||
• https://github.com/kikito/inspect.lua
|
||||
• https://github.com/mpeterv/vinspect
|
||||
|
||||
vim.is_callable({f}) *vim.is_callable()*
|
||||
Returns true if object `f` can be called as a function.
|
||||
|
||||
@@ -1822,6 +1473,46 @@ vim.isnil({t}) *vim.isnil()*
|
||||
Return: ~
|
||||
(`boolean`) `true` if `nil` or |vim.NIL|, else `false`.
|
||||
|
||||
vim.keycode({keys}, {info}) *vim.keycode()*
|
||||
Converts keys from |key-notation| to the internal encoding. Optionally
|
||||
returns structured *key-chord* info as retval 2.
|
||||
|
||||
Inverse of |keytrans()|, which converts the internal encoding back to
|
||||
|key-notation|.
|
||||
|
||||
Examples: >lua
|
||||
local k = vim.keycode
|
||||
vim.g.mapleader = k'<bs>'
|
||||
|
||||
-- Split a key sequence into chords, e.g. to inspect modifiers.
|
||||
local _, chords = vim.keycode('<C-w>v', true)
|
||||
assert(chords[1].key == 'w' and chords[1].mod[1] == 'C')
|
||||
|
||||
-- keytrans() is the inverse: internal encoding => key-notation.
|
||||
assert(vim.fn.keytrans(vim.keycode('<C-a>')) == '<C-A>')
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {keys} (`string`) Keys in |key-notation|.
|
||||
• {info} (`boolean?`) Also return key-chord info.
|
||||
|
||||
Return (multiple): ~
|
||||
(`string`) Internal representation of the given `keys`.
|
||||
(`table?`) List of parsed key-chords, each with fields:
|
||||
• {key} (`string`) Key without modifiers. Example: `<C-A>` has
|
||||
`key="a"`.
|
||||
• {key_alt} (`string?`) Alternative spelling of `key`, or nil if There
|
||||
Is No Alternative (TINA). Example: `"<"` has `key_alt="lt"`.
|
||||
• {keys} (`string`) Full key-chord in canonical key-notation (as
|
||||
produced by |keytrans()|), including modifiers. Example: `<A-f>` has
|
||||
`keys="<M-f>"`.
|
||||
• {mod} (`('M'|'T'|'C'|'S'|'2'|'3'|'4'|'D')[]`) List of key-chord
|
||||
modifiers. Example: `<C-S-f>` has `mod={ 'C', 'S' }`.
|
||||
|
||||
See also: ~
|
||||
• |nvim_replace_termcodes()|
|
||||
• |keytrans()|
|
||||
|
||||
vim.list.bisect({t}, {val}, {opts}) *vim.list.bisect()*
|
||||
Search for a position in a sorted |lua-list| {t} where {val} can be
|
||||
inserted while keeping the list sorted.
|
||||
@@ -1970,6 +1661,15 @@ vim.list_slice({list}, {start}, {finish}) *vim.list_slice()*
|
||||
Return: ~
|
||||
(`any[]`) Copy of table sliced from start to finish (inclusive)
|
||||
|
||||
vim.lua_omnifunc({find_start}) *vim.lua_omnifunc()*
|
||||
Omnifunc for completing Lua values from the runtime Lua interpreter,
|
||||
similar to the builtin completion for the `:lua` command.
|
||||
|
||||
Activate using `vim.bo.omnifunc = vim.lua_omnifunc` in a Lua buffer.
|
||||
|
||||
Parameters: ~
|
||||
• {find_start} (`1|0`)
|
||||
|
||||
vim.nonnil({...}) *vim.nonnil()*
|
||||
Returns the first argument which is not nil.
|
||||
|
||||
@@ -1992,6 +1692,32 @@ vim.nonnil({...}) *vim.nonnil()*
|
||||
Return: ~
|
||||
(`any`)
|
||||
|
||||
vim.notify({msg}, {level}, {opts}) *vim.notify()*
|
||||
Displays a notification to the user.
|
||||
|
||||
This function can be overridden by plugins to display notifications using
|
||||
a custom provider (such as the system notification provider). By default,
|
||||
writes to |:messages|.
|
||||
|
||||
Parameters: ~
|
||||
• {msg} (`string`) Content of the notification to show to the user.
|
||||
• {level} (`integer?`) One of the values from |vim.log.levels|.
|
||||
• {opts} (`table?`) Optional parameters. Unused by default.
|
||||
|
||||
vim.notify_once({msg}, {level}, {opts}) *vim.notify_once()*
|
||||
Displays a notification only one time.
|
||||
|
||||
Like |vim.notify()|, but subsequent calls with the same message will not
|
||||
display a notification.
|
||||
|
||||
Parameters: ~
|
||||
• {msg} (`string`) Content of the notification to show to the user.
|
||||
• {level} (`integer?`) One of the values from |vim.log.levels|.
|
||||
• {opts} (`table?`) Optional parameters. Unused by default.
|
||||
|
||||
Return: ~
|
||||
(`boolean`) true if message was displayed, else false
|
||||
|
||||
vim.npcall({fn}, {...}) *vim.npcall()*
|
||||
Calls the function `fn` in `protected mode` like |pcall()|, but returns
|
||||
`nil` on error.
|
||||
@@ -2006,6 +1732,84 @@ vim.npcall({fn}, {...}) *vim.npcall()*
|
||||
Return: ~
|
||||
(`any`) ...
|
||||
|
||||
vim.on_key({fn}, {ns_id}, {opts}) *vim.on_key()*
|
||||
Registers function {fn} with |namespace| {ns_id} as a listener to EVERY
|
||||
input key (except keys consumed by |getchar()|, by {fn} itself, or by a
|
||||
<Cmd> payload).
|
||||
|
||||
To parse |key-chord|s, see |vim.keycode()|. Example: >lua
|
||||
local keychords = vim.keycode(vim.fn.keytrans(key), true)
|
||||
<
|
||||
|
||||
Note: ~
|
||||
• If {fn} returns an empty string, {key} is discarded/ignored; if {key}
|
||||
is <Cmd> then the "<Cmd>…<CR>" sequence is discarded as a whole.
|
||||
• Non-recursive: if {fn} itself consumes input, it won't be invoked for
|
||||
those keys.
|
||||
• Not invoked for keys consumed by getchar()/getcharstr(): they never
|
||||
reach the main loop.
|
||||
• To UNregister a given {ns_id}, pass `nil` {fn}.
|
||||
• {fn} will be removed on error.
|
||||
• {fn} will not be cleared by |nvim_buf_clear_namespace()|
|
||||
• The |-w| command-line option is related but does not support callbacks
|
||||
and cannot be toggled dynamically.
|
||||
|
||||
Parameters: ~
|
||||
• {fn} (`fun(key: string, typed: string): string??`) Function
|
||||
invoked for every input key, after mappings have been applied
|
||||
but before further processing. Arguments {key} and {typed}
|
||||
are raw input (use |keytrans()| to get |keycodes|).
|
||||
• {key} is the key after mappings are applied.
|
||||
• {typed} is the input before mappings are applied; may be
|
||||
empty if {key} was produced by non-typed key(s) or by the
|
||||
same typed key(s) that produced a previous {key}.
|
||||
• {ns_id} (`integer?`) Namespace ID. If nil or 0, returns a new
|
||||
|namespace| id.
|
||||
• {opts} (`table?`) Optional parameters
|
||||
|
||||
Return: ~
|
||||
(`integer`) Namespace id associated with {fn}. Or count of all
|
||||
callbacks if on_key() is called without arguments.
|
||||
|
||||
See also: ~
|
||||
• |keytrans()|
|
||||
• |vim.keycode()|
|
||||
|
||||
vim.paste({lines}, {phase}) *vim.paste()*
|
||||
Paste handler, invoked by |nvim_paste()|.
|
||||
|
||||
Note: This is provided only as a "hook", don't call it directly; call
|
||||
|nvim_paste()| instead, which arranges redo (dot-repeat) and invokes
|
||||
`vim.paste`.
|
||||
|
||||
Example: To remove ANSI color codes when pasting: >lua
|
||||
vim.paste = (function(overridden)
|
||||
return function(lines, phase)
|
||||
for i,line in ipairs(lines) do
|
||||
-- Scrub ANSI color codes from paste input.
|
||||
lines[i] = line:gsub('\27%[[0-9;mK]+', '')
|
||||
end
|
||||
return overridden(lines, phase)
|
||||
end
|
||||
end)(vim.paste)
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {lines} (`string[]`) |readfile()|-style list of lines to paste.
|
||||
|channel-lines|
|
||||
• {phase} (`-1|1|2|3`) -1: "non-streaming" paste: the call contains all
|
||||
lines. If paste is "streamed", `phase` indicates the stream
|
||||
state:
|
||||
• 1: starts the paste (exactly once)
|
||||
• 2: continues the paste (zero or more times)
|
||||
• 3: ends the paste (exactly once)
|
||||
|
||||
Return: ~
|
||||
(`boolean`) result false if client should cancel the paste.
|
||||
|
||||
See also: ~
|
||||
• |paste|
|
||||
|
||||
vim.pesc({s}) *vim.pesc()*
|
||||
Escapes magic chars in |lua-pattern|s.
|
||||
|
||||
@@ -2018,6 +1822,23 @@ vim.pesc({s}) *vim.pesc()*
|
||||
See also: ~
|
||||
• https://github.com/rxi/lume
|
||||
|
||||
vim.print({...}) *vim.print()*
|
||||
"Pretty prints" the given arguments and returns them unmodified.
|
||||
|
||||
Example: >lua
|
||||
local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' }))
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {...} (`any`)
|
||||
|
||||
Return: ~
|
||||
(`any`) given arguments.
|
||||
|
||||
See also: ~
|
||||
• |vim.inspect()|
|
||||
• |:=|
|
||||
|
||||
vim.ringbuf({size}) *vim.ringbuf()*
|
||||
Create a ring buffer limited to a maximal number of items. Once the buffer
|
||||
is full, adding a new entry overrides the oldest entry. >lua
|
||||
@@ -2048,6 +1869,29 @@ vim.ringbuf({size}) *vim.ringbuf()*
|
||||
Return: ~
|
||||
(`vim.Ringbuf<any>`) ringbuf
|
||||
|
||||
vim.schedule_wrap({fn}) *vim.schedule_wrap()*
|
||||
Returns a function which calls {fn} via |vim.schedule()|.
|
||||
|
||||
The returned function passes all arguments to {fn}.
|
||||
|
||||
Example: >lua
|
||||
function notify_readable(_err, readable)
|
||||
vim.notify("readable? " .. tostring(readable))
|
||||
end
|
||||
vim.uv.fs_access(vim.fn.stdpath("config"), "R", vim.schedule_wrap(notify_readable))
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {fn} (`function`)
|
||||
|
||||
Return: ~
|
||||
(`function`)
|
||||
|
||||
See also: ~
|
||||
• |lua-loop-callbacks|
|
||||
• |vim.schedule()|
|
||||
• |vim.in_fast_event()|
|
||||
|
||||
vim.spairs({t}) *vim.spairs()*
|
||||
Enumerates key-value pairs of a table, ordered by key.
|
||||
|
||||
@@ -2100,6 +1944,44 @@ vim.startswith({s}, {prefix}) *vim.startswith()*
|
||||
Return: ~
|
||||
(`boolean`) `true` if `prefix` is a prefix of `s`
|
||||
|
||||
*vim.str_byteindex()*
|
||||
vim.str_byteindex({s}, {encoding}, {index}, {strict_indexing})
|
||||
Convert UTF-32, UTF-16 or UTF-8 {index} to byte index. If
|
||||
{strict_indexing} is false then an out of range index will return byte
|
||||
length instead of throwing an error.
|
||||
|
||||
Invalid UTF-8 and NUL is treated like in |vim.str_utfindex()|. An {index}
|
||||
in the middle of a UTF-16 sequence is rounded upwards to the end of that
|
||||
sequence.
|
||||
|
||||
Parameters: ~
|
||||
• {s} (`string`)
|
||||
• {encoding} (`"utf-8"|"utf-16"|"utf-32"`)
|
||||
• {index} (`integer`)
|
||||
• {strict_indexing} (`boolean?`) default: true
|
||||
|
||||
Return: ~
|
||||
(`integer`)
|
||||
|
||||
*vim.str_utfindex()*
|
||||
vim.str_utfindex({s}, {encoding}, {index}, {strict_indexing})
|
||||
Convert byte index to UTF-32, UTF-16 or UTF-8 indices. If {index} is not
|
||||
supplied, the length of the string is used. All indices are zero-based.
|
||||
|
||||
If {strict_indexing} is false then an out of range index will return
|
||||
string length instead of throwing an error. Invalid UTF-8 bytes, and
|
||||
embedded surrogates are counted as one code point each. An {index} in the
|
||||
middle of a UTF-8 sequence is rounded upwards to the end of that sequence.
|
||||
|
||||
Parameters: ~
|
||||
• {s} (`string`)
|
||||
• {encoding} (`"utf-8"|"utf-16"|"utf-32"`)
|
||||
• {index} (`integer?`)
|
||||
• {strict_indexing} (`boolean?`) default: true
|
||||
|
||||
Return: ~
|
||||
(`integer`)
|
||||
|
||||
vim.tbl_contains({t}, {value}, {opts}) *vim.tbl_contains()*
|
||||
Checks if a table contains a given value, specified either directly or via
|
||||
a predicate that is checked for each value.
|
||||
@@ -2358,6 +2240,135 @@ vim.validate({name}, {value}, {validator}, {optional}, {message})
|
||||
• `fun(name: string, val: any, validator: vim.validate.Validator, message: string)`
|
||||
• `fun(spec: table<string,[any, vim.validate.Validator, boolean|string]>)`
|
||||
|
||||
vim.wait({time}, {callback}, {interval}, {fast_only}) *vim.wait()*
|
||||
Waits up to `time` milliseconds, until `callback` returns `true`
|
||||
(success). Executes `callback` immediately, then on user events, internal
|
||||
events, and approximately every `interval` milliseconds (default 200).
|
||||
Returns `true` plus any remaining callback results on success.
|
||||
|
||||
Nvim processes other events while waiting. Cannot be called during an
|
||||
|api-fast| event.
|
||||
|
||||
Examples: >lua
|
||||
-- Wait for 100 ms, allowing other events to process.
|
||||
vim.wait(100)
|
||||
|
||||
-- Wait up to 1000 ms or until `vim.g.foo` is true, at intervals of ~500 ms.
|
||||
vim.wait(1000, function() return vim.g.foo end, 500)
|
||||
|
||||
-- Wait indefinitely until `vim.g.foo` is true, and get the callback results.
|
||||
local ok, rv1, rv2, rv3 = vim.wait(math.huge, function()
|
||||
return vim.g.foo, 'a', 42, { ok = { 'yes' } }
|
||||
end)
|
||||
|
||||
-- Schedule a function to set a value in 100ms. This would wait 10s if blocked, but actually
|
||||
-- only waits 100ms because `vim.wait` processes other events while waiting.
|
||||
vim.defer_fn(function() vim.g.timer_result = true end, 100)
|
||||
if vim.wait(10000, function() return vim.g.timer_result end) then
|
||||
print('Only waiting a little bit of time!')
|
||||
end
|
||||
|
||||
-- Yield via vim.wait() to allow CTRL-C to interrupt Lua code.
|
||||
while true do
|
||||
-- ...work...
|
||||
local _, code = vim.wait(0, nil, 0)
|
||||
if code == -2 then -- CTRL-C.
|
||||
break
|
||||
end
|
||||
end
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {time} (`number`) Number of milliseconds to wait. Must be
|
||||
non-negative number, any fractional part is truncated.
|
||||
• {callback} (`fun(): boolean, ...?`) Optional callback. Waits until
|
||||
{callback} returns true
|
||||
• {interval} (`integer?`) (Approximate) number of milliseconds to wait
|
||||
between polls
|
||||
• {fast_only} (`boolean?`) If true, only |api-fast| events will be
|
||||
processed.
|
||||
|
||||
Return (multiple): ~
|
||||
(`boolean`)
|
||||
(`-1|-2?`)
|
||||
• If callback returns `true` before timeout: `true, ...` (remaining
|
||||
callback results).
|
||||
• On timeout: `false, -1`
|
||||
• On interrupt: `false, -2`
|
||||
• On error: the error is raised.
|
||||
|
||||
|
||||
==============================================================================
|
||||
Lua module: vim.inspector *vim.inspector*
|
||||
|
||||
vim.inspect_pos({buf}, {row}, {col}, {filter}) *vim.inspect_pos()*
|
||||
Get all the items at a given buffer position.
|
||||
|
||||
Can also be pretty-printed with `:Inspect!`. *:Inspect!*
|
||||
|
||||
Attributes: ~
|
||||
Since: 0.9.0
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer?`) defaults to the current buffer
|
||||
• {row} (`integer?`) row to inspect, 0-based. Defaults to the row of
|
||||
the current cursor
|
||||
• {col} (`integer?`) col to inspect, 0-based. Defaults to the col of
|
||||
the current cursor
|
||||
• {filter} (`table?`) Table with key-value pairs to filter the items
|
||||
• {extmarks} (`boolean|"all"`, default: true) Include
|
||||
extmarks. When `all`, then extmarks without a `hl_group`
|
||||
will also be included.
|
||||
• {semantic_tokens} (`boolean`, default: true) Include
|
||||
semantic token highlights.
|
||||
• {syntax} (`boolean`, default: `true`) Include syntax based
|
||||
highlight groups.
|
||||
• {treesitter} (`boolean`, default: `true`) Include
|
||||
treesitter based highlight groups.
|
||||
|
||||
Return: ~
|
||||
(`table`) a table with the following key-value pairs. Items are in
|
||||
"traversal order":
|
||||
• treesitter: a list of treesitter captures
|
||||
• syntax: a list of syntax groups
|
||||
• semantic_tokens: a list of semantic tokens
|
||||
• extmarks: a list of extmarks
|
||||
• buffer: the buffer used to get the items
|
||||
• row: the row used to get the items
|
||||
• col: the col used to get the items
|
||||
|
||||
vim.show_pos({buf}, {row}, {col}, {filter}) *vim.show_pos()*
|
||||
Show all the items at a given buffer position.
|
||||
|
||||
Can also be shown with `:Inspect`. *:Inspect*
|
||||
|
||||
See also |:marks| to list all extmarks.
|
||||
|
||||
Example: To bind this function to the vim-scriptease inspired `zS` in
|
||||
Normal mode: >lua
|
||||
vim.keymap.set('n', 'zS', vim.show_pos)
|
||||
<
|
||||
|
||||
Attributes: ~
|
||||
Since: 0.9.0
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer?`) defaults to the current buffer
|
||||
• {row} (`integer?`) row to inspect, 0-based. Defaults to the row of
|
||||
the current cursor
|
||||
• {col} (`integer?`) col to inspect, 0-based. Defaults to the col of
|
||||
the current cursor
|
||||
• {filter} (`table?`) A table with the following fields:
|
||||
• {extmarks} (`boolean|"all"`, default: true) Include
|
||||
extmarks. When `all`, then extmarks without a `hl_group`
|
||||
will also be included.
|
||||
• {semantic_tokens} (`boolean`, default: true) Include
|
||||
semantic token highlights.
|
||||
• {syntax} (`boolean`, default: `true`) Include syntax based
|
||||
highlight groups.
|
||||
• {treesitter} (`boolean`, default: `true`) Include
|
||||
treesitter based highlight groups.
|
||||
|
||||
|
||||
==============================================================================
|
||||
Lua module: vim.base64 *vim.base64*
|
||||
@@ -3306,10 +3317,7 @@ Iter:find({f}) *Iter:find()*
|
||||
Since: 0.10.0
|
||||
|
||||
Parameters: ~
|
||||
• {f} (`(fun(v: V1, ...: V...): boolean)|any`)
|
||||
|
||||
Overloads: ~
|
||||
• `fun<V1, V...>(self: vim.IterArray<V1, V...>, f: V1|fun(v: V1, ...: V...): boolean): V1?, V...`
|
||||
• {f} (`V1|fun(v: V1, ...: V...): any`)
|
||||
|
||||
Return (multiple): ~
|
||||
(`V1?`)
|
||||
@@ -3584,10 +3592,6 @@ Iter:totable() *Iter:totable()*
|
||||
Attributes: ~
|
||||
Since: 0.10.0
|
||||
|
||||
Overloads: ~
|
||||
• `fun<T>(self: vim.Iter<T, never>): T[]`
|
||||
• `fun<V1, V2, V...>(self: vim.Iter<V1, V2, V...>): [V1, V2, V...][]`
|
||||
|
||||
Return: ~
|
||||
(`any[]`)
|
||||
|
||||
@@ -5871,7 +5875,7 @@ Example: >lua
|
||||
end
|
||||
<
|
||||
|
||||
*vim.version()* returns the version of the current Nvim process.
|
||||
|vim.version()| returns the version of the current Nvim process.
|
||||
|
||||
VERSION RANGE SPEC *version-range*
|
||||
|
||||
@@ -5948,6 +5952,12 @@ VersionRange:has({version}) *VersionRange:has()*
|
||||
See also: ~
|
||||
• https://github.com/npm/node-semver#ranges
|
||||
|
||||
vim.version() *vim.version()*
|
||||
Returns the current Nvim version.
|
||||
|
||||
Return: ~
|
||||
(`vim.Version`)
|
||||
|
||||
vim.version.cmp({v1}, {v2}) *vim.version.cmp()*
|
||||
Parses and compares two version objects (the result of
|
||||
|vim.version.parse()|, or specified literally as a `{major, minor, patch}`
|
||||
|
||||
+15
-19
@@ -1577,6 +1577,21 @@ This Lua |treesitter-query| interface allows you to create queries and use
|
||||
them to parse text. See |vim.treesitter.query.parse()| for a working example.
|
||||
|
||||
|
||||
*TSQuery*
|
||||
Extends: |userdata|
|
||||
|
||||
Reference to an object held by the treesitter library that is used as a
|
||||
component of the |vim.treesitter.Query| for language feature support. See
|
||||
|treesitter-query| for more about queries or
|
||||
|vim.treesitter.query.parse()| for an example of how to obtain a query
|
||||
object.
|
||||
|
||||
Fields: ~
|
||||
• {disable_capture} (`fun(self: TSQuery, capture_name: string)`) See
|
||||
|TSQuery:disable_capture()|.
|
||||
• {disable_pattern} (`fun(self: TSQuery, pattern_index: integer)`) See
|
||||
|TSQuery:disable_pattern()|.
|
||||
|
||||
*vim.treesitter.Query*
|
||||
Parsed query, see |vim.treesitter.query.parse()|
|
||||
|
||||
@@ -1871,25 +1886,6 @@ set({lang}, {query_name}, {text}) *vim.treesitter.query.set()*
|
||||
• {query_name} (`string`) Name of the query (e.g., "highlights")
|
||||
• {text} (`string`) Query text (unparsed).
|
||||
|
||||
|
||||
|
||||
|
||||
*TSQuery*
|
||||
Extends: |userdata|
|
||||
|
||||
Reference to an object held by the treesitter library that is used as a
|
||||
component of the |vim.treesitter.Query| for language feature support. See
|
||||
|treesitter-query| for more about queries or
|
||||
|vim.treesitter.query.parse()| for an example of how to obtain a query
|
||||
object.
|
||||
|
||||
Fields: ~
|
||||
• {disable_capture} (`fun(self: TSQuery, capture_name: string)`) See
|
||||
|TSQuery:disable_capture()|.
|
||||
• {disable_pattern} (`fun(self: TSQuery, pattern_index: integer)`) See
|
||||
|TSQuery:disable_pattern()|.
|
||||
|
||||
|
||||
TSQuery:disable_capture({capture_name}) *TSQuery:disable_capture()*
|
||||
Disable a specific capture in this query; once disabled the capture cannot
|
||||
be re-enabled. {capture_name} should not include a leading "@".
|
||||
|
||||
@@ -55,7 +55,7 @@ local function check_line(line)
|
||||
{ details = true }
|
||||
))
|
||||
:filter(function(extmark)
|
||||
return not extmark[4].invalid
|
||||
return not assert(extmark[4]).invalid
|
||||
end)
|
||||
:totable()
|
||||
|
||||
|
||||
@@ -243,22 +243,6 @@ function vim._os_proc_children(ppid)
|
||||
return children
|
||||
end
|
||||
|
||||
--- @nodoc
|
||||
--- @class vim.inspect.Opts
|
||||
--- @field depth? integer
|
||||
--- @field newline? string
|
||||
--- @field indent? string
|
||||
--- @field process? fun(item: any, path: any[]): any
|
||||
|
||||
--- Gets a human-readable representation of the given object.
|
||||
---
|
||||
---@see |vim.print()|
|
||||
---@see https://github.com/kikito/inspect.lua
|
||||
---@see https://github.com/mpeterv/vinspect
|
||||
---@return string
|
||||
---@overload fun(x: any, opts?: vim.inspect.Opts): string
|
||||
vim.inspect = vim.inspect
|
||||
|
||||
do
|
||||
local startpos --- @type integer[]?
|
||||
local tdots = 0
|
||||
@@ -1119,7 +1103,7 @@ function vim._expand_pat(pat, env)
|
||||
local vars = vim.fn.getcompletion(prefix .. match_part, type) --- @type string[]
|
||||
insert_keys(vim
|
||||
.iter(vars)
|
||||
:map(function(s) ---@param s string
|
||||
:map(function(s)
|
||||
s = s:gsub('[()]+$', '') -- strip '(' and ')' for function completions
|
||||
return s:sub(#prefix + 1) -- strip the prefix, e.g., 'g:foo' => 'foo'
|
||||
end)
|
||||
|
||||
@@ -189,7 +189,6 @@ function M.lsp_complete(_, line)
|
||||
local subcmd = split[2]
|
||||
return vim
|
||||
.iter(complete_args[subcmd]())
|
||||
--- @param n string
|
||||
:map(function(n)
|
||||
return vim.fn.escape(n, ' \t')
|
||||
end)
|
||||
|
||||
@@ -37,7 +37,7 @@ function M.serverlist(opts, addrs)
|
||||
if want_info then
|
||||
local self_pid = vim.fn.getpid()
|
||||
local self_active = vim.v.useractive
|
||||
peers = vim.tbl_map(function(addr) ---@param addr vim.ServerInfo
|
||||
peers = vim.tbl_map(function(addr)
|
||||
return {
|
||||
addr = addr,
|
||||
pid = self_pid,
|
||||
|
||||
@@ -329,6 +329,8 @@ function M.show_msg(tgt, kind, content, replace_last, append, id)
|
||||
or (api.nvim_buf_line_count(buf) - ((replace_last or cr or append) and 1 or 0))
|
||||
local curline = (cr or append) and api.nvim_buf_get_lines(buf, row, row + 1, false)[1]
|
||||
col = mark[2] or (append and not cr and math.min(col, #curline) or 0)
|
||||
--- EmmyLuaLs/emmylua-analyzer-rust#1269
|
||||
--- @type integer, integer, integer
|
||||
local start_row, start_col, lines = row, col, o.lines
|
||||
|
||||
local function set_target_pos()
|
||||
|
||||
@@ -7,61 +7,6 @@ error('Cannot require a meta file')
|
||||
---@type uv
|
||||
vim.uv = ...
|
||||
|
||||
--- LuaLS fallback surface for the richer iterator annotations in `vim.iter`.
|
||||
--- EmmyLua reads the precise generics from `runtime/lua/vim/iter.lua`; LuaLS uses
|
||||
--- these broader shapes for downstream type-checking.
|
||||
--- @class vim.Iter
|
||||
--- @field all fun(self: vim.Iter, pred: fun(...): boolean): boolean
|
||||
--- @field any fun(self: vim.Iter, pred: fun(...): boolean): boolean
|
||||
--- @field count fun(self: vim.Iter): integer
|
||||
--- @field each fun(self: vim.Iter, f: fun(...)): nil
|
||||
--- @field enumerate fun(self: vim.Iter): vim.Iter
|
||||
--- @field filter fun(self: vim.Iter, f: fun(...): boolean): vim.Iter
|
||||
--- @field find fun(self: vim.Iter, f: any): any
|
||||
--- @field flatten fun(self: vim.Iter, depth?: integer): vim.IterArray
|
||||
--- @field fold fun(self: vim.Iter, init: any, f: fun(acc: any, ...): any): any
|
||||
--- @field join fun(self: vim.Iter, delim: string): string
|
||||
--- @field last fun(self: vim.Iter): any
|
||||
--- @field map fun(self: vim.Iter, f: fun(...): ...): vim.Iter
|
||||
--- @field next fun(self: vim.Iter): any
|
||||
--- @field nth fun(self: vim.Iter, n: integer): any
|
||||
--- @field peek fun(self: vim.Iter): any
|
||||
--- @field pop fun(self: vim.Iter): any
|
||||
--- @field rev fun(self: vim.Iter): vim.IterArray
|
||||
--- @field rfind fun(self: vim.Iter, f: any): any
|
||||
--- @field rpeek fun(self: vim.Iter): any
|
||||
--- @field rskip fun(self: vim.Iter, n: integer): vim.IterArray
|
||||
--- @field skip fun(self: vim.Iter, n: integer|fun(...): boolean): vim.Iter
|
||||
--- @field slice fun(self: vim.Iter, first: integer, last: integer): vim.IterArray
|
||||
--- @field take fun(self: vim.Iter, n: integer|fun(...): boolean): vim.Iter
|
||||
--- @field totable fun(self: vim.Iter): table
|
||||
--- @field unique fun(self: vim.Iter, key?: fun(...): any): vim.Iter
|
||||
|
||||
--- @class vim.IterArray : vim.Iter
|
||||
--- @field count fun(self: vim.IterArray): integer
|
||||
--- @field enumerate fun(self: vim.IterArray): vim.IterArray
|
||||
--- @field filter fun(self: vim.IterArray, f: fun(...): boolean): vim.IterArray
|
||||
--- @field find fun(self: vim.IterArray, f: any): any
|
||||
--- @field flatten fun(self: vim.IterArray, depth?: integer): vim.IterArray
|
||||
--- @field fold fun(self: vim.IterArray, init: any, f: fun(acc: any, ...): any): any
|
||||
--- @field last fun(self: vim.IterArray): any
|
||||
--- @field map fun(self: vim.IterArray, f: fun(...): ...): vim.IterArray
|
||||
--- @field next fun(self: vim.IterArray): any
|
||||
--- @field peek fun(self: vim.IterArray): any
|
||||
--- @field pop fun(self: vim.IterArray): any
|
||||
--- @field rev fun(self: vim.IterArray): vim.IterArray
|
||||
--- @field rfind fun(self: vim.IterArray, f: any): any
|
||||
--- @field rpeek fun(self: vim.IterArray): any
|
||||
--- @field rskip fun(self: vim.IterArray, n: integer): vim.IterArray
|
||||
--- @field skip fun(self: vim.IterArray, n: integer|fun(...): boolean): vim.IterArray
|
||||
--- @field slice fun(self: vim.IterArray, first: integer, last: integer): vim.IterArray
|
||||
--- @field take fun(self: vim.IterArray, n: integer|fun(...): boolean): vim.IterArray
|
||||
--- @field totable fun(self: vim.IterArray): table
|
||||
--- @field unique fun(self: vim.IterArray, key?: fun(...): any): vim.IterArray
|
||||
|
||||
--- @class vim.IterModule
|
||||
--- @operator call: fun(src: any, ...): vim.Iter
|
||||
|
||||
--- The following modules are loaded specially in _init_packages.lua
|
||||
|
||||
vim.F = require('vim.F')
|
||||
@@ -75,11 +20,8 @@ vim.func = require('vim.func')
|
||||
vim.glob = require('vim.glob')
|
||||
vim.health = require('vim.health')
|
||||
vim.hl = require('vim.hl')
|
||||
local iter = require('vim.iter')
|
||||
-- `require('vim.iter')` carries the richer EmmyLua generic surface. Force
|
||||
-- LuaLS onto the fallback module shape above so `make luals` stays clean.
|
||||
---@cast iter vim.IterModule
|
||||
vim.iter = iter
|
||||
vim.inspect = require('vim.inspect')
|
||||
vim.iter = require('vim.iter')
|
||||
vim.keymap = require('vim.keymap')
|
||||
vim.loader = require('vim.loader')
|
||||
vim.log = require('vim.log')
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
--- @diagnostic disable: annotation-usage-error
|
||||
|
||||
-- Contains filetype detection functions for use in filetype.lua that are either:
|
||||
-- * used more than once or
|
||||
-- * complex (e.g. check more than one line or use conditionals).
|
||||
|
||||
@@ -144,6 +144,8 @@ local function filepath_to_healthcheck(path)
|
||||
:find(function(dir)
|
||||
return vim.fs.relpath(dir, path)
|
||||
end)
|
||||
-- The healthcheck path came from nvim_get_runtime_file(), so a runtime directory must match.
|
||||
assert(rtp_lua)
|
||||
-- "/path/to/rtp/lua/foo/bar/health.lua" => "foo/bar/health.lua"
|
||||
-- "/another/rtp/lua/baz/health/init.lua" => "baz/health/init.lua"
|
||||
local subpath = path:gsub('^' .. vim.pesc(rtp_lua), ''):gsub('^/+', '')
|
||||
|
||||
@@ -762,9 +762,9 @@ local function check_sysinfo()
|
||||
vim.health.start('System Info')
|
||||
|
||||
-- Use :version because `vim.version().build` returns "Homebrew" for brew installs.
|
||||
local version_out = vim.api.nvim_exec2('version', { output = true }).output
|
||||
local version_out = vim.api.nvim_exec2('version', { output = true }).output --[[@as string]]
|
||||
local nvim_version = version_out:match('NVIM (v[^\n]+)') or 'unknown'
|
||||
local commit --[[@type string]] = (version_out:match('%+g(%x+)') or ''):sub(1, 12)
|
||||
local commit = (version_out:match('%+g(%x+)') or ''):sub(1, 12)
|
||||
|
||||
if vim.fn.executable('git') ~= 1 then
|
||||
vim.health.warn('Cannot check for updates: git not found')
|
||||
|
||||
@@ -156,7 +156,6 @@ function M.range(buf, ns, hlgroup, start, finish, opts)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
---@class (private) vim.hl.OnEventState
|
||||
---@field timer? uv.uv_timer_t Timer to clear the highlight.
|
||||
---@field clear? fun() Function to clear the highlight immediately.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
--- @diagnostic disable: no-unknown
|
||||
--- @class (private) vim.InspectModule
|
||||
--- @overload fun(root: any, options?: vim.inspect.Opts): string
|
||||
local inspect = {
|
||||
_VERSION = 'inspect.lua 3.1.0',
|
||||
_URL = 'http://github.com/kikito/inspect.lua',
|
||||
@@ -311,6 +312,7 @@ local function tabify(inspector)
|
||||
puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level))
|
||||
end
|
||||
|
||||
--- @nodoc
|
||||
--- @param v any
|
||||
function Inspector:getId(v)
|
||||
local id = self.ids[v]
|
||||
@@ -323,6 +325,7 @@ function Inspector:getId(v)
|
||||
return tostring(id)
|
||||
end
|
||||
|
||||
--- @nodoc
|
||||
--- @param v any
|
||||
function Inspector:putValue(v)
|
||||
local buf = self.buf
|
||||
@@ -407,8 +410,31 @@ function Inspector:putValue(v)
|
||||
end
|
||||
end
|
||||
|
||||
--- @inlinedoc
|
||||
--- @class vim.inspect.Opts
|
||||
---
|
||||
--- Maximum table nesting depth. Deeper tables are shown as `{...}`.
|
||||
--- (default: unlimited)
|
||||
--- @field depth? integer
|
||||
---
|
||||
--- String used for line breaks.
|
||||
--- (default: `"\n"`)
|
||||
--- @field newline? string
|
||||
---
|
||||
--- String repeated for each level of indentation.
|
||||
--- (default: `" "`)
|
||||
--- @field indent? string
|
||||
---
|
||||
--- Transforms values, keys, and metatables before formatting. Return a replacement value,
|
||||
--- or `nil` to omit a table entry. {path} lists the keys leading to {item}, with
|
||||
--- `vim.inspect.KEY` appended for keys or `vim.inspect.METATABLE` for metatables.
|
||||
--- The root has an empty path.
|
||||
--- @field process? fun(item: any, path: any[]): any
|
||||
|
||||
--- @nodoc
|
||||
--- @param root any
|
||||
--- @param options? vim.inspect.Opts
|
||||
--- @return string
|
||||
function inspect.inspect(root, options)
|
||||
options = options or {}
|
||||
|
||||
@@ -440,6 +466,14 @@ function inspect.inspect(root, options)
|
||||
end
|
||||
|
||||
setmetatable(inspect, {
|
||||
--- Gets a human-readable representation of the given object.
|
||||
---
|
||||
--- @see |vim.print()|
|
||||
--- @see https://github.com/kikito/inspect.lua
|
||||
--- @see https://github.com/mpeterv/vinspect
|
||||
--- @param root any
|
||||
--- @param options? vim.inspect.Opts
|
||||
--- @return string
|
||||
__call = function(_, root, options)
|
||||
return inspect.inspect(root, options)
|
||||
end,
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
--- @overload fun<T>(src: T[]): vim.IterArray<T, never>
|
||||
--- @overload fun<K, V>(src: table<K, V>): vim.Iter<K, V>
|
||||
--- @overload fun(src: table, ...): vim.Iter<any, any...>
|
||||
--- @overload fun(src: function, ...): vim.Iter<any, any...>
|
||||
--- @overload fun<S, C, R1, R...>(src: (fun(state: S, control: C): R1, R...), state?: S, control?: C): vim.Iter<R1, R...>
|
||||
local M = {}
|
||||
|
||||
--- @nodoc
|
||||
@@ -440,7 +440,7 @@ function Iter:each(f)
|
||||
end
|
||||
end
|
||||
|
||||
--- @private
|
||||
--- @nodoc
|
||||
--- @param f fun(v: V1, ...: V...)
|
||||
function IterArray:each(f)
|
||||
local inc = self._head < self._tail and 1 or -1
|
||||
@@ -475,8 +475,6 @@ end
|
||||
---
|
||||
---
|
||||
--- @since 12
|
||||
--- @overload fun<T>(self: vim.Iter<T, never>): T[]
|
||||
--- @overload fun<V1, V2, V...>(self: vim.Iter<V1, V2, V...>): [V1, V2, V...][]
|
||||
--- @return any[]
|
||||
function Iter:totable()
|
||||
local t = {}
|
||||
@@ -493,8 +491,6 @@ function Iter:totable()
|
||||
end
|
||||
|
||||
--- @nodoc
|
||||
--- @overload fun<T>(self: vim.IterArray<T, never>): T[]
|
||||
--- @overload fun<V1, V2, V...>(self: vim.IterArray<V1, V2, V...>): [V1, V2, V...][]
|
||||
--- @return any[]
|
||||
function IterArray:totable()
|
||||
if self.next ~= IterArray.next or self._head >= self._tail then
|
||||
@@ -627,7 +623,7 @@ function Iter:next()
|
||||
return self._next()
|
||||
end
|
||||
|
||||
--- @package
|
||||
--- @nodoc
|
||||
--- @return V1?, V...
|
||||
function IterArray:next()
|
||||
if self._head ~= self._tail then
|
||||
@@ -693,7 +689,7 @@ function Iter:peek()
|
||||
return unpack(self._peeked)
|
||||
end
|
||||
|
||||
--- @private
|
||||
--- @nodoc
|
||||
--- @return V1?, V...
|
||||
function IterArray:peek()
|
||||
if self._head ~= self._tail then
|
||||
@@ -723,8 +719,7 @@ end
|
||||
---
|
||||
--- ```
|
||||
--- @since 12
|
||||
--- @param f (fun(v: V1, ...: V...): boolean)|any
|
||||
--- @overload fun<V1, V...>(self: vim.IterArray<V1, V...>, f: V1|fun(v: V1, ...: V...): boolean): V1?, V...
|
||||
--- @param f V1|fun(v: V1, ...: V...): any
|
||||
--- @return V1?, V...
|
||||
function Iter:find(f)
|
||||
if type(f) ~= 'function' then
|
||||
@@ -862,7 +857,7 @@ function Iter:take(n)
|
||||
return self
|
||||
end
|
||||
|
||||
--- @private
|
||||
--- @nodoc
|
||||
--- @param n integer|fun(v: V1, ...: V...): boolean
|
||||
--- @return vim.IterArray<V1, V...>
|
||||
function IterArray:take(n)
|
||||
@@ -997,7 +992,7 @@ function Iter:skip(n)
|
||||
return self
|
||||
end
|
||||
|
||||
--- @private
|
||||
--- @nodoc
|
||||
--- @param n integer|fun(v: V1, ...: V...): boolean
|
||||
--- @return vim.IterArray<V1, V...>
|
||||
function IterArray:skip(n)
|
||||
@@ -1185,7 +1180,7 @@ function Iter:last()
|
||||
return last
|
||||
end
|
||||
|
||||
--- @private
|
||||
--- @nodoc
|
||||
--- @return V1?, V...
|
||||
function IterArray:last()
|
||||
if self._head == self._tail then
|
||||
@@ -1236,7 +1231,7 @@ function Iter:enumerate()
|
||||
end)
|
||||
end
|
||||
|
||||
--- @private
|
||||
--- @nodoc
|
||||
--- @return vim.IterArray<integer, V1, V...>
|
||||
function IterArray:enumerate()
|
||||
local inc = self._head < self._tail and 1 or -1
|
||||
|
||||
+5
-22
@@ -7,7 +7,6 @@ local lsp = vim._defer_require('vim.lsp', {
|
||||
_changetracking = ..., --- @module 'vim.lsp._changetracking'
|
||||
_folding_range = ..., --- @module 'vim.lsp._folding_range'
|
||||
_snippet_grammar = ..., --- @module 'vim.lsp._snippet_grammar'
|
||||
_tagfunc = ..., --- @module 'vim.lsp._tagfunc'
|
||||
_watchfiles = ..., --- @module 'vim.lsp._watchfiles'
|
||||
buf = ..., --- @module 'vim.lsp.buf'
|
||||
client = ..., --- @module 'vim.lsp.client'
|
||||
@@ -24,6 +23,9 @@ local lsp = vim._defer_require('vim.lsp', {
|
||||
protocol = ..., --- @module 'vim.lsp.protocol'
|
||||
rpc = ..., --- @module 'vim.lsp.rpc'
|
||||
semantic_tokens = ..., --- @module 'vim.lsp.semantic_tokens'
|
||||
-- Work around EmmyLuaLs/emmylua-analyzer-rust#1238 for function exports.
|
||||
--- @type fun(pattern: string, flags: string): table[]|vim.NIL
|
||||
tagfunc = ..., --- @module 'vim.lsp.tagfunc'
|
||||
util = ..., --- @module 'vim.lsp.util'
|
||||
})
|
||||
|
||||
@@ -396,19 +398,17 @@ lsp.config = setmetatable({ _configs = {} }, {
|
||||
local function get_config_names()
|
||||
local config_names = vim
|
||||
.iter(api.nvim_get_runtime_file('lsp/*.lua', true))
|
||||
--- @param path string
|
||||
:map(function(path)
|
||||
local file_name = path:match('[^/]*.lua$')
|
||||
local file_name = assert(path:match('[^/]*.lua$'))
|
||||
return file_name:sub(0, #file_name - 4)
|
||||
end)
|
||||
:totable()
|
||||
:totable() --[[@as string[] ]]
|
||||
|
||||
vim.list_extend(config_names, vim.tbl_keys(lsp.config._configs))
|
||||
|
||||
return vim
|
||||
.iter(config_names)
|
||||
:unique()
|
||||
--- @param name string
|
||||
:filter(function(name)
|
||||
return name ~= '*'
|
||||
end)
|
||||
@@ -1443,23 +1443,6 @@ function lsp.formatexpr(opts)
|
||||
return 0
|
||||
end
|
||||
|
||||
--- Provides an interface between the built-in client and 'tagfunc'.
|
||||
---
|
||||
--- When used with normal mode commands (e.g. |CTRL-]|) this will invoke
|
||||
--- the "textDocument/definition" LSP method to find the tag under the cursor.
|
||||
--- Otherwise, uses "workspace/symbol". If no results are returned from
|
||||
--- any LSP servers, falls back to using built-in tags.
|
||||
---
|
||||
---@param pattern string Pattern used to find a workspace symbol
|
||||
---@param flags string See |tag-function|
|
||||
---
|
||||
---@return table[]|vim.NIL tags A list of matching tags, or `vim.NIL` to use the built-in tags.
|
||||
function lsp.tagfunc(pattern, flags)
|
||||
-- EmmyLua incorrectly treats function exports referenced by @module as non-callable.
|
||||
--- @diagnostic disable-next-line:call-non-callable EmmyLuaLs/emmylua-analyzer-rust#1238
|
||||
return vim.lsp._tagfunc(pattern, flags)
|
||||
end
|
||||
|
||||
--- Provides an interface between the built-in client and a `foldexpr` function.
|
||||
---
|
||||
--- To use, set 'foldmethod' to "expr" and set the value of 'foldexpr':
|
||||
|
||||
@@ -92,7 +92,7 @@ function M:destroy()
|
||||
api.nvim_del_augroup_by_id(self.augroup)
|
||||
self.active[self.bufnr] = nil
|
||||
|
||||
buf_capabilities[self.bufnr] = vim.tbl_filter(function(cap) ---@param cap vim.lsp.Capability
|
||||
buf_capabilities[self.bufnr] = vim.tbl_filter(function(cap)
|
||||
return cap ~= self
|
||||
end, buf_capabilities[self.bufnr])
|
||||
|
||||
|
||||
@@ -434,6 +434,7 @@ end
|
||||
--- |lsp-handler| for the method `workspace/codeLens/refresh`
|
||||
---
|
||||
---@internal
|
||||
---@diagnostic disable-next-line: annotation-usage-error
|
||||
---@type lsp.Handler
|
||||
function M.on_refresh(err, _, ctx)
|
||||
if err then
|
||||
|
||||
@@ -86,9 +86,17 @@ local function query_workspace_symbols(pattern)
|
||||
return results
|
||||
end
|
||||
|
||||
---@param pattern string
|
||||
---@param flags string
|
||||
---@return table[]|vim.NIL
|
||||
--- Provides an interface between the built-in client and 'tagfunc'.
|
||||
---
|
||||
--- When used with normal mode commands (e.g. |CTRL-]|) this will invoke
|
||||
--- the "textDocument/definition" LSP method to find the tag under the cursor.
|
||||
--- Otherwise, uses "workspace/symbol". If no results are returned from
|
||||
--- any LSP servers, falls back to using built-in tags.
|
||||
---
|
||||
---@param pattern string Pattern used to find a workspace symbol
|
||||
---@param flags string See |tag-function|
|
||||
---
|
||||
---@return table[]|vim.NIL tags A list of matching tags, or `vim.NIL` to use the built-in tags.
|
||||
local function tagfunc(pattern, flags)
|
||||
-- avoid definition/symbol queries for insert completion
|
||||
if string.match(flags, 'i') then
|
||||
@@ -890,7 +890,7 @@ local function install_list(plug_list, confirm)
|
||||
if not confirm or confirm_install(plug_list) then
|
||||
trigger_events(plug_list, 'PackChangedPre', 'install')
|
||||
run_list(plug_list, do_install, 'Installing plugins')
|
||||
local installed = vim.tbl_filter(function(p) --- @param p vim.pack.Plug
|
||||
local installed = vim.tbl_filter(function(p)
|
||||
return p.info.installed == true
|
||||
end, plug_list)
|
||||
trigger_events(installed, 'PackChanged', 'install')
|
||||
@@ -945,7 +945,7 @@ local function infer_update_details(p)
|
||||
local any_version = vim.version.range('*') --[[@as vim.VersionRange]]
|
||||
local last_version = get_last_semver_tag(past_tags, any_version)
|
||||
|
||||
local newer_semver_tags = vim.tbl_filter(function(x) --- @param x string
|
||||
local newer_semver_tags = vim.tbl_filter(function(x)
|
||||
return vim.version.gt(x, last_version)
|
||||
end, all_semver_tags)
|
||||
|
||||
@@ -1400,7 +1400,7 @@ local function update_list(plug_list)
|
||||
end
|
||||
run_list(plug_list, do_update, 'Applying updates')
|
||||
|
||||
local updated = vim.tbl_filter(function(p) --- @param p vim.pack.Plug
|
||||
local updated = vim.tbl_filter(function(p)
|
||||
return p.info.updated == true
|
||||
end, plug_list)
|
||||
trigger_events(updated, 'PackChanged', 'update')
|
||||
@@ -1503,7 +1503,7 @@ function M.update(names, opts)
|
||||
|
||||
-- Update and show report
|
||||
if opts.force then
|
||||
local plugs_to_update = vim.tbl_filter(function(p) --- @param p vim.pack.Plug
|
||||
local plugs_to_update = vim.tbl_filter(function(p)
|
||||
return p.info.sha_head ~= p.info.sha_target
|
||||
end, plug_list)
|
||||
update_list(plugs_to_update)
|
||||
|
||||
@@ -12,7 +12,6 @@ local M = {}
|
||||
---@field named vim.treesitter.dev.Node[]
|
||||
local TSTreeView = {}
|
||||
|
||||
---@private
|
||||
---@class (private) vim.treesitter.dev.TSTreeViewOpts
|
||||
---@field anon boolean If true, display anonymous nodes.
|
||||
---@field lang boolean If true, display the language alongside each node.
|
||||
|
||||
+19
-23
@@ -347,30 +347,26 @@ do
|
||||
--- Initialize Progress handlers.
|
||||
local function progress_init()
|
||||
progress_group = vim.api.nvim_create_augroup('nvim.ui.progress_status', { clear = true })
|
||||
progress_autocmd = require('vim._core.util').nvim_on(
|
||||
'Progress',
|
||||
progress_group,
|
||||
{
|
||||
desc = 'Tracks progress messages for vim.ui.progress_status()',
|
||||
}, ---@param ev {data: vim.event.progress.data}
|
||||
function(ev)
|
||||
if not ev.data or not ev.data.id then
|
||||
return
|
||||
end
|
||||
ev.data.percent = ev.data.percent or 0
|
||||
progress[ev.data.id] = ev.data
|
||||
|
||||
-- Clear finished items
|
||||
if
|
||||
ev.data.status == 'success'
|
||||
or ev.data.percent == 100
|
||||
or ev.data.status == 'failed'
|
||||
or ev.data.status == 'cancel'
|
||||
then
|
||||
progress[ev.data.id] = nil
|
||||
end
|
||||
progress_autocmd = require('vim._core.util').nvim_on('Progress', progress_group, {
|
||||
desc = 'Tracks progress messages for vim.ui.progress_status()',
|
||||
}, function(ev)
|
||||
if not ev.data or not ev.data.id then
|
||||
return
|
||||
end
|
||||
)
|
||||
--- @cast ev.data vim.event.progress.data
|
||||
ev.data.percent = ev.data.percent or 0
|
||||
progress[ev.data.id] = ev.data
|
||||
|
||||
-- Clear finished items
|
||||
if
|
||||
ev.data.status == 'success'
|
||||
or ev.data.percent == 100
|
||||
or ev.data.status == 'failed'
|
||||
or ev.data.status == 'cancel'
|
||||
then
|
||||
progress[ev.data.id] = nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- Gets a status description summarizing currently running progress messages.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
--- end
|
||||
--- ```
|
||||
---
|
||||
--- [vim.version()]() returns the version of the current Nvim process.
|
||||
--- [vim.version()] returns the version of the current Nvim process.
|
||||
---
|
||||
--- VERSION RANGE SPEC [version-range]()
|
||||
---
|
||||
|
||||
+137
-74
@@ -38,7 +38,9 @@ local INDENTATION = 4
|
||||
--- Generated documentation target, e.g. api.txt
|
||||
--- @field filename string
|
||||
---
|
||||
--- @field section_order string[]
|
||||
--- Ordered filenames or groups of filenames to merge into one section.
|
||||
--- For a group, the first filename determines the section name and help tag.
|
||||
--- @field section_order (string|string[])[]
|
||||
---
|
||||
--- List of files/directories for doxygen to read, relative to `base_dir`.
|
||||
--- @field files string[]
|
||||
@@ -59,11 +61,6 @@ local INDENTATION = 4
|
||||
---
|
||||
--- Per-function helptag.
|
||||
--- @field fn_helptag_fmt? fun(fun: nvim.gen_vimdoc.HelptagTarget): string
|
||||
---
|
||||
--- @field append_only? string[]
|
||||
---
|
||||
--- Merge parsed files into the first section instead of rendering one section per file.
|
||||
--- @field merge_files? boolean
|
||||
|
||||
---@alias nvim.gen_vimdoc.HelptagTarget
|
||||
---| nvim.luacats.parser.fun
|
||||
@@ -179,9 +176,8 @@ local config = {
|
||||
-- Sections at the top, in a specific order:
|
||||
'builtin.lua',
|
||||
'options.lua',
|
||||
'editor.lua',
|
||||
{ 'editor.lua', 'inspect.lua', 'shared.lua' },
|
||||
'_inspector.lua',
|
||||
'shared.lua',
|
||||
|
||||
-- Sections in alphanumeric order:
|
||||
'base64.lua',
|
||||
@@ -233,6 +229,7 @@ local config = {
|
||||
'runtime/lua/vim/fs.lua',
|
||||
'runtime/lua/vim/glob.lua',
|
||||
'runtime/lua/vim/hl.lua',
|
||||
'runtime/lua/vim/inspect.lua',
|
||||
'runtime/lua/vim/iter.lua',
|
||||
'runtime/lua/vim/keymap.lua',
|
||||
'runtime/lua/vim/loader.lua',
|
||||
@@ -253,7 +250,7 @@ local config = {
|
||||
fun.module = 'vim'
|
||||
end
|
||||
|
||||
if fun.module == 'vim' and contains(fun.name, { 'cmd', 'inspect' }) then
|
||||
if fun.module == 'vim' and fun.name == 'cmd' then
|
||||
fun.table = nil
|
||||
end
|
||||
|
||||
@@ -312,15 +309,12 @@ local config = {
|
||||
|
||||
return fn_helptag_fmt_common(fun)
|
||||
end,
|
||||
append_only = {
|
||||
'shared.lua',
|
||||
},
|
||||
},
|
||||
lsp = {
|
||||
filename = 'lsp.txt',
|
||||
section_order = {
|
||||
-- Sections at the top, in a specific order:
|
||||
'lsp.lua',
|
||||
{ 'lsp.lua', 'tagfunc.lua' },
|
||||
|
||||
-- Sections in alphanumeric order:
|
||||
'buf.lua',
|
||||
@@ -338,7 +332,6 @@ local config = {
|
||||
'on_type_formatting.lua',
|
||||
'rpc.lua',
|
||||
'semantic_tokens.lua',
|
||||
'tagfunc.lua',
|
||||
|
||||
-- Sections at the end, in a specific order:
|
||||
'util.lua',
|
||||
@@ -373,9 +366,8 @@ local config = {
|
||||
async = {
|
||||
filename = 'lua-async.txt',
|
||||
section_order = {
|
||||
'async.lua',
|
||||
{ 'async.lua', '_core.lua', '_semaphore.lua' },
|
||||
},
|
||||
merge_files = true,
|
||||
files = {
|
||||
'runtime/lua/vim/async.lua',
|
||||
'runtime/lua/vim/async/_core.lua',
|
||||
@@ -388,12 +380,6 @@ local config = {
|
||||
return { 'lua-async', 'vim.async' }
|
||||
end,
|
||||
fn_xform = function(fun)
|
||||
if fun.module == 'vim.async._core' or fun.module == 'vim.async._semaphore' then
|
||||
fun.module = 'vim.async'
|
||||
end
|
||||
if fun.name == 'new_semaphore' then
|
||||
fun.name = 'semaphore'
|
||||
end
|
||||
if fun.classvar == 'M' then
|
||||
fun.classvar = nil
|
||||
end
|
||||
@@ -425,10 +411,8 @@ local config = {
|
||||
'highlighter.lua',
|
||||
'language.lua',
|
||||
'languagetree.lua',
|
||||
'query.lua',
|
||||
'tsquery.lua',
|
||||
{ 'query.lua', 'tsquery.lua' },
|
||||
},
|
||||
append_only = { 'tsquery.lua' },
|
||||
files = {
|
||||
'runtime/lua/vim/treesitter/_meta/',
|
||||
'runtime/lua/vim/treesitter.lua',
|
||||
@@ -1171,21 +1155,16 @@ local function make_section(filename, cfg, briefs, funs_txt, classes_txt)
|
||||
end
|
||||
|
||||
--- @param section nvim.gen_vimdoc.Section
|
||||
--- @param add_header? boolean
|
||||
local function render_section(section, add_header)
|
||||
local function render_section(section)
|
||||
local doc = {} --- @type string[]
|
||||
|
||||
if not section.title then
|
||||
error(('section.title is nil, check section_fmt(). section: %s'):format(vim.inspect(section)))
|
||||
end
|
||||
|
||||
if add_header ~= false then
|
||||
vim.list_extend(doc, {
|
||||
string.rep('=', TEXT_WIDTH),
|
||||
'\n',
|
||||
align_tags(TEXT_WIDTH)(section.title .. ' ' .. section.help_tag),
|
||||
})
|
||||
end
|
||||
doc[#doc + 1] = string.rep('=', TEXT_WIDTH)
|
||||
.. '\n'
|
||||
.. align_tags(TEXT_WIDTH)(section.title .. ' ' .. section.help_tag)
|
||||
|
||||
if next(section.briefs) then
|
||||
local briefs_txt = {} --- @type string[]
|
||||
@@ -1193,23 +1172,21 @@ local function render_section(section, add_header)
|
||||
briefs_txt[#briefs_txt + 1] = md_to_vimdoc(b, 0, 0, TEXT_WIDTH)
|
||||
end
|
||||
|
||||
local sdoc = '\n\n' .. table.concat(briefs_txt, '\n')
|
||||
local sdoc = table.concat(briefs_txt, '\n')
|
||||
if sdoc:find('[^%s]') then
|
||||
doc[#doc + 1] = sdoc
|
||||
end
|
||||
end
|
||||
|
||||
if section.classes_txt ~= '' then
|
||||
table.insert(doc, '\n\n')
|
||||
table.insert(doc, (section.classes_txt:gsub('\n+$', '\n')))
|
||||
end
|
||||
|
||||
if section.funs_txt ~= '' then
|
||||
table.insert(doc, '\n\n')
|
||||
table.insert(doc, section.funs_txt)
|
||||
end
|
||||
|
||||
return table.concat(doc)
|
||||
return table.concat(doc, '\n\n')
|
||||
end
|
||||
|
||||
local parsers = {
|
||||
@@ -1243,11 +1220,95 @@ local function find_module_class(classes, modvar)
|
||||
end
|
||||
end
|
||||
|
||||
--- Add callable exports and inherited module functions under their public names.
|
||||
--- E.g. `M.semaphore = require('vim.async._semaphore')` in vim.async exposes
|
||||
--- that module's returned `new_semaphore` function as `vim.async.semaphore()`.
|
||||
--- A callable table uses its module name: vim.inspect's `__call` => `vim.inspect()`.
|
||||
--- @param modules table<string,nvim.luacats.parser.module>
|
||||
local function expand_module_docs(modules)
|
||||
local exports = {} --- @type table<nvim.luacats.parser.module,string[]>
|
||||
for _, module in pairs(modules) do
|
||||
local documented = {} --- @type table<string,true>
|
||||
for _, fun in ipairs(module.funs) do
|
||||
if fun.modvar == module.modvar and (not fun.classvar or fun.classvar == module.modvar) then
|
||||
documented[fun.name] = true
|
||||
end
|
||||
end
|
||||
for name, imported in pairs(module.imports) do
|
||||
local public_name = module.name .. '.' .. name
|
||||
if not documented[name] and not ('.' .. public_name):find('%._') then
|
||||
exports[imported] = exports[imported] or {}
|
||||
table.insert(exports[imported], public_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for name, module in pairs(modules) do
|
||||
-- E.g. new_semaphore becomes vim.async.semaphore through a require() binding.
|
||||
-- Otherwise, use the public module path (vim.inspect for its __call).
|
||||
if module.callable and (exports[module] or not ('.' .. name):find('%._')) then
|
||||
for _, public_name in ipairs(exports[module] or { name }) do
|
||||
local fun = vim.deepcopy(module.callable)
|
||||
fun.module, fun.name = public_name:match('^(.*)%.([^.]+)$')
|
||||
fun.name = fun.name or public_name
|
||||
module.funs[#module.funs + 1] = fun
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- `@class vim.async: vim.async._core` makes `vim.async._core.run()` => `vim.async.run()`.
|
||||
-- Copy inherited functions under the public module name, keeping nearer declarations.
|
||||
local hidden = {} --- @type table<nvim.luacats.parser.fun,true>
|
||||
for _, module in pairs(modules) do
|
||||
if module.class and not ('.' .. module.name):find('%._') then
|
||||
local names = {} --- @type table<string,true>
|
||||
local seen = {} --- @type table<nvim.luacats.parser.module,true>
|
||||
local source = module
|
||||
while source and not seen[source] do
|
||||
seen[source] = true
|
||||
for _, fun in ipairs(source.funs) do
|
||||
if fun.class == source.class.name and fun.member_sep == '.' then
|
||||
if
|
||||
source ~= module
|
||||
and not names[fun.name]
|
||||
and not fun.nodoc
|
||||
and not fun.access
|
||||
and fun.name:sub(1, 1) ~= '_'
|
||||
then
|
||||
local inherited = vim.deepcopy(fun)
|
||||
inherited.module, inherited.class = module.name, module.class.name
|
||||
inherited.modvar, inherited.classvar = module.modvar, module.modvar
|
||||
module.funs[#module.funs + 1] = inherited
|
||||
end
|
||||
if source ~= module and ('.' .. source.name):find('%._') then
|
||||
hidden[fun] = true
|
||||
end
|
||||
-- Include functions already inherited by the source module.
|
||||
names[fun.name] = true
|
||||
end
|
||||
end
|
||||
-- A nearer declaration shadows ancestors, including non-function fields.
|
||||
for _, field in ipairs(source.class.fields) do
|
||||
names[field.name] = true
|
||||
end
|
||||
for name in pairs(source.assignments) do
|
||||
names[name] = true
|
||||
end
|
||||
source = source.parent
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Delay hiding until all modules have inherited the original documentation.
|
||||
for fun in pairs(hidden) do
|
||||
fun.nodoc = true
|
||||
end
|
||||
end
|
||||
|
||||
--- @param cfg nvim.gen_vimdoc.Config
|
||||
local function gen_target(cfg)
|
||||
cfg.fn_helptag_fmt = cfg.fn_helptag_fmt or fn_helptag_fmt_common
|
||||
print('Target:', cfg.filename)
|
||||
local sections = {} --- @type table<string,nvim.gen_vimdoc.Section>
|
||||
local sections = {} --- @type nvim.gen_vimdoc.Section[]
|
||||
|
||||
expand_files(cfg.files)
|
||||
|
||||
@@ -1257,20 +1318,28 @@ local function gen_target(cfg)
|
||||
--- @type table<string,nvim.luacats.parser.class>
|
||||
local all_classes = {}
|
||||
|
||||
--- First pass so we can collect all classes
|
||||
--- @type table<string,nvim.luacats.parser.module>
|
||||
local modules = {}
|
||||
|
||||
--- First pass so we can collect all classes and module exports.
|
||||
for _, f in vim.spairs(cfg.files) do
|
||||
local ext = f:match('%.([^.]+)$')
|
||||
local parser = parsers[ext]
|
||||
if parser then
|
||||
local classes, funs, briefs = parser(f)
|
||||
local classes, funs, briefs, _, module = parser(f)
|
||||
file_results[f] = { classes, funs, briefs }
|
||||
all_classes = vim.tbl_extend('error', all_classes, classes)
|
||||
if module then
|
||||
modules[module.name] = module
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local merged_classes = {} --- @type table<string,nvim.luacats.parser.class>
|
||||
local merged_funs = {} --- @type nvim.luacats.parser.fun[]
|
||||
local merged_briefs = {} --- @type string[]
|
||||
luacats_parser.resolve_modules(modules)
|
||||
expand_module_docs(modules)
|
||||
|
||||
--- @type table<string,[table<string,nvim.luacats.parser.class>, nvim.luacats.parser.fun[], string[]]>
|
||||
local files_by_name = {}
|
||||
|
||||
for f, r in vim.spairs(file_results) do
|
||||
local classes, funs, briefs = r[1], r[2], r[3]
|
||||
@@ -1291,43 +1360,37 @@ local function gen_target(cfg)
|
||||
|
||||
print(' Processing file:', f)
|
||||
|
||||
if cfg.merge_files then
|
||||
merged_classes = vim.tbl_extend('error', merged_classes, classes)
|
||||
vim.list_extend(merged_funs, funs)
|
||||
vim.list_extend(merged_briefs, briefs)
|
||||
else
|
||||
-- FIXME: Using f_base will confuse `_meta/protocol.lua` with `protocol.lua`
|
||||
local f_base = vim.fs.basename(f)
|
||||
sections[f_base] = make_section(
|
||||
f_base,
|
||||
cfg,
|
||||
render_briefs(briefs, cfg),
|
||||
render_funs(funs, all_classes, cfg),
|
||||
render_classes(classes, funs, cfg)
|
||||
)
|
||||
end
|
||||
-- FIXME: Using basenames will confuse `_meta/protocol.lua` with `protocol.lua`
|
||||
files_by_name[vim.fs.basename(f)] = r
|
||||
end
|
||||
|
||||
if cfg.merge_files then
|
||||
local section_file = cfg.section_order[1]
|
||||
sections[section_file] = make_section(
|
||||
section_file,
|
||||
for _, entry in ipairs(cfg.section_order) do
|
||||
local files = type(entry) == 'table' and entry or { entry }
|
||||
local classes = {} --- @type table<string,nvim.luacats.parser.class>
|
||||
local funs = {} --- @type nvim.luacats.parser.fun[]
|
||||
local briefs = {} --- @type string[]
|
||||
for _, f in ipairs(files) do
|
||||
local r = files_by_name[f]
|
||||
if r then
|
||||
classes = vim.tbl_extend('error', classes, r[1])
|
||||
vim.list_extend(funs, r[2])
|
||||
vim.list_extend(briefs, r[3])
|
||||
end
|
||||
end
|
||||
sections[#sections + 1] = make_section(
|
||||
files[1],
|
||||
cfg,
|
||||
render_briefs(merged_briefs, cfg),
|
||||
render_funs(merged_funs, all_classes, cfg),
|
||||
render_classes(merged_classes, merged_funs, cfg)
|
||||
render_briefs(briefs, cfg),
|
||||
render_funs(funs, all_classes, cfg),
|
||||
render_classes(classes, funs, cfg)
|
||||
)
|
||||
end
|
||||
|
||||
local first_section_tag = sections[cfg.section_order[1]].help_tag
|
||||
local first_section_tag = sections[1].help_tag
|
||||
local docs = {} --- @type string[]
|
||||
for _, f in ipairs(cfg.section_order) do
|
||||
local section = sections[f]
|
||||
if section then
|
||||
print(fmt(" Rendering section: '%s'", section.title))
|
||||
local add_sep_and_header = not vim.tbl_contains(cfg.append_only or {}, f)
|
||||
docs[#docs + 1] = render_section(section, add_sep_and_header)
|
||||
end
|
||||
for _, section in ipairs(sections) do
|
||||
print(fmt(" Rendering section: '%s'", section.title))
|
||||
docs[#docs + 1] = render_section(section)
|
||||
end
|
||||
|
||||
table.insert(
|
||||
|
||||
+100
-16
@@ -58,6 +58,17 @@ local luacats_grammar = require('gen.luacats_grammar') * vim.lpeg.Cp()
|
||||
--- @field last_doc_item? nvim.luacats.parser.param|nvim.luacats.parser.return|nvim.luacats.parser.note
|
||||
--- @field last_doc_item_indent? integer
|
||||
|
||||
--- @class nvim.luacats.parser.module
|
||||
--- @field name string Module name inferred from the path, used to resolve require().
|
||||
--- @field modvar? string
|
||||
--- @field class? nvim.luacats.parser.class Class of the returned module table.
|
||||
--- @field requires table<string,string> Module fields assigned directly from require(), keyed by field name.
|
||||
--- @field imports table<string,nvim.luacats.parser.module> Bindings linked by resolve_modules().
|
||||
--- @field parent? nvim.luacats.parser.module Module whose returned class is this module class's parent.
|
||||
--- @field callable? nvim.luacats.parser.fun Returned function or the returned table's __call.
|
||||
--- @field assignments table<string,true> Field assignments (`M.name = ...`), including unannotated ones.
|
||||
--- @field funs nvim.luacats.parser.fun[]
|
||||
|
||||
--- @alias nvim.luacats.parser.obj
|
||||
--- | nvim.luacats.parser.class
|
||||
--- | nvim.luacats.parser.fun
|
||||
@@ -409,20 +420,9 @@ end
|
||||
local function determine_modvar(str)
|
||||
local modvar --- @type string?
|
||||
for line in vim.gsplit(str, '\n') do
|
||||
do
|
||||
--- @type string?
|
||||
local m = line:match('^return%s+([a-zA-Z_]+)')
|
||||
if m then
|
||||
modvar = m
|
||||
end
|
||||
end
|
||||
do
|
||||
--- @type string?
|
||||
local m = line:match('^return%s+setmetatable%(([a-zA-Z_]+),')
|
||||
if m then
|
||||
modvar = m
|
||||
end
|
||||
end
|
||||
modvar = line:match('^return%s+setmetatable%s*%(%s*([%w_]+)%s*,')
|
||||
or line:match('^return%s+([%w_]+)')
|
||||
or modvar
|
||||
end
|
||||
return modvar
|
||||
end
|
||||
@@ -495,6 +495,16 @@ function M.parse_str(str, filename)
|
||||
local module = filename:match('.*/lua/([a-z_][a-z0-9_/]+)%.lua') or filename
|
||||
module = module:gsub('/', '.')
|
||||
|
||||
--- @type nvim.luacats.parser.module
|
||||
local module_info = {
|
||||
name = module,
|
||||
modvar = mod_return,
|
||||
requires = {},
|
||||
imports = {},
|
||||
assignments = {},
|
||||
funs = funs,
|
||||
}
|
||||
|
||||
local classvars = {} --- @type table<string,string>
|
||||
|
||||
local state = {} --- @type nvim.luacats.parser.State
|
||||
@@ -503,12 +513,20 @@ function M.parse_str(str, filename)
|
||||
local uncommitted = {} --- @type nvim.luacats.parser.obj[]
|
||||
|
||||
local comments = {}
|
||||
local in_module_metatable = false
|
||||
for line in vim.gsplit(str, '\n') do
|
||||
local has_indent = line:match('^%s+') ~= nil
|
||||
line = vim.trim(line)
|
||||
if vim.startswith(line, '---') then
|
||||
comments[#comments + 1] = use_type_alt(line:sub(4):gsub('^%s+@', '@'))
|
||||
else
|
||||
-- Recognize the returned module's inline metatable at file scope.
|
||||
if not has_indent and line ~= '' and not vim.startswith(line, '--') then
|
||||
local target = line:match('^setmetatable%s*%(%s*([%w_]+)%s*,%s*{')
|
||||
or line:match('^return%s+setmetatable%s*%(%s*([%w_]+)%s*,%s*{')
|
||||
in_module_metatable = target ~= nil and target == mod_return
|
||||
end
|
||||
|
||||
if #comments > 0 then
|
||||
local comment = table.concat(comments, '\n') .. '\n'
|
||||
local pos = 1
|
||||
@@ -523,12 +541,36 @@ function M.parse_str(str, filename)
|
||||
end
|
||||
add_doc_lines_to_obj(state)
|
||||
|
||||
if not has_indent then
|
||||
local parent, name, value = line:match('^([%w_]+)%.([%w_]+)%s*=%s*(.*)$')
|
||||
if parent == mod_return and name then
|
||||
module_info.assignments[name] = true
|
||||
local _, required, tail = value:match([[^require%s*%(%s*(['"])([^'"]+)%1%s*%)%s*(.*)$]])
|
||||
module_info.requires[name] = required and (tail == '' or tail:match('^%-%-')) and required
|
||||
or nil
|
||||
end
|
||||
end
|
||||
|
||||
if state.cur_obj then
|
||||
state.cur_obj.modvar = mod_return
|
||||
state.cur_obj.module = module
|
||||
end
|
||||
|
||||
process_lua_line(line, state, classes, classvars, has_indent)
|
||||
-- Keep the callable declaration separate from the table's member functions.
|
||||
local returned = line:match('^local%s+function%s+([%w_]+)%s*%(')
|
||||
local callable_name = returned
|
||||
if in_module_metatable and line:match('^__call%s*=%s*function%s*%(') then
|
||||
in_module_metatable = false
|
||||
returned = mod_return
|
||||
callable_name = '__call'
|
||||
end
|
||||
if returned and returned == mod_return and state.cur_obj then
|
||||
state.cur_obj.name = callable_name
|
||||
module_info.callable = state.cur_obj
|
||||
state.cur_obj = nil
|
||||
else
|
||||
process_lua_line(line, state, classes, classvars, has_indent)
|
||||
end
|
||||
|
||||
-- Commit the object
|
||||
local cur_obj = state.cur_obj
|
||||
@@ -543,9 +585,51 @@ function M.parse_str(str, filename)
|
||||
end
|
||||
end
|
||||
|
||||
if mod_return then
|
||||
module_info.class = classes[classvars[mod_return]]
|
||||
end
|
||||
|
||||
-- dump_uncommitted(filename, uncommitted)
|
||||
|
||||
return classes, funs, briefs, uncommitted
|
||||
return classes, funs, briefs, uncommitted, module_info
|
||||
end
|
||||
|
||||
--- Connect separately parsed modules by filling their `imports` and `parent` fields.
|
||||
--- Call after parsing all input files, passing their module records keyed by module name.
|
||||
---
|
||||
--- For example, the Lua source file pkg/child.lua contains:
|
||||
--- ```lua
|
||||
--- --- @class Child: Base
|
||||
--- local M = {}
|
||||
--- M.factory = require('pkg.factory')
|
||||
--- return M
|
||||
--- ```
|
||||
--- The caller stores the parsed record for this file in `modules['pkg.child']`.
|
||||
--- That record describes M, the table returned by the source file:
|
||||
--- - `requires.factory` contains the string 'pkg.factory'. This function fills
|
||||
--- `imports.factory` with `modules['pkg.factory']`, the parsed record for that file.
|
||||
--- - `class.parent` contains the string 'Base'. This function fills `parent` with
|
||||
--- the parsed record of the module whose returned table is annotated `@class Base`.
|
||||
---
|
||||
--- Each link points to the original parsed module; a missing target leaves it nil.
|
||||
--- The string names in `requires` and `class.parent` are retained. No declarations
|
||||
--- are copied, renamed or hidden.
|
||||
--- @param modules table<string,nvim.luacats.parser.module> Parsed modules keyed by require path.
|
||||
function M.resolve_modules(modules)
|
||||
local by_class = {} --- @type table<string,nvim.luacats.parser.module>
|
||||
for _, module in pairs(modules) do
|
||||
if module.class then
|
||||
by_class[module.class.name] = module
|
||||
end
|
||||
end
|
||||
|
||||
for _, module in pairs(modules) do
|
||||
module.imports = {}
|
||||
for name, required in pairs(module.requires) do
|
||||
module.imports[name] = modules[required]
|
||||
end
|
||||
module.parent = module.class and by_class[module.class.parent] or nil
|
||||
end
|
||||
end
|
||||
|
||||
--- @param filename string
|
||||
|
||||
@@ -143,6 +143,100 @@ describe('luacats parser', function()
|
||||
eq({ { type = 'boolean', desc = 'Whether the value is nil.' } }, funs[1].returns)
|
||||
end)
|
||||
|
||||
it('links require bindings without renaming declarations', function()
|
||||
local _, _, _, _, consumer = parser.parse_str(
|
||||
dedent([[
|
||||
local M = {}
|
||||
--- A binding with its own documentation.
|
||||
M.create = require('vim.factory')
|
||||
M.missing = require('vim.missing')
|
||||
return M
|
||||
]]),
|
||||
'runtime/lua/vim/_consumer.lua'
|
||||
)
|
||||
local _, funs, _, _, implementation = parser.parse_str(
|
||||
dedent([[
|
||||
--- Create a value.
|
||||
--- @param value string
|
||||
--- @return string
|
||||
local function new_value(value) end
|
||||
return new_value
|
||||
]]),
|
||||
'runtime/lua/vim/factory.lua'
|
||||
)
|
||||
parser.resolve_modules({ ['vim._consumer'] = consumer, ['vim.factory'] = implementation })
|
||||
|
||||
-- Check table identity: the import must reference the original parsed module.
|
||||
eq(true, implementation == consumer.imports.create)
|
||||
eq('vim.missing', consumer.requires.missing)
|
||||
eq(nil, consumer.imports.missing)
|
||||
eq({}, funs)
|
||||
eq('new_value', implementation.callable.name)
|
||||
eq('vim.factory', implementation.callable.module)
|
||||
eq('Create a value.', implementation.callable.desc)
|
||||
eq({ { name = 'value', type = 'string' } }, implementation.callable.params)
|
||||
eq({ { type = 'string' } }, implementation.callable.returns)
|
||||
end)
|
||||
|
||||
it('keeps a callable module declaration separate from its members', function()
|
||||
local _, funs, _, _, module = parser.parse_str(
|
||||
dedent([[
|
||||
local M = {}
|
||||
setmetatable(M, {
|
||||
--- Format a value.
|
||||
--- @param value any
|
||||
--- @return string
|
||||
__call = function(_, value) end,
|
||||
})
|
||||
return M
|
||||
]]),
|
||||
'runtime/lua/vim/example.lua'
|
||||
)
|
||||
eq({}, funs)
|
||||
eq('__call', module.callable.name)
|
||||
eq('vim.example', module.callable.module)
|
||||
eq('Format a value.', module.callable.desc)
|
||||
eq({ { name = 'value', type = 'any' } }, module.callable.params)
|
||||
eq({ { type = 'string' } }, module.callable.returns)
|
||||
end)
|
||||
|
||||
it('links table imports and parent modules without copying or hiding members', function()
|
||||
local _, core_funs, _, _, core = parser.parse_str(
|
||||
dedent([[
|
||||
--- @class vim._core
|
||||
local Core = {}
|
||||
|
||||
--- Shared function.
|
||||
--- @return string
|
||||
function Core.create() end
|
||||
return Core
|
||||
]]),
|
||||
'runtime/lua/vim/_core.lua'
|
||||
)
|
||||
local _, funs, _, _, public = parser.parse_str(
|
||||
dedent([[
|
||||
--- @class vim.public: vim._core
|
||||
local M = {}
|
||||
M._core = require('vim._core')
|
||||
M.create = false
|
||||
return M
|
||||
]]),
|
||||
'runtime/lua/vim/public.lua'
|
||||
)
|
||||
parser.resolve_modules({ ['vim._core'] = core, ['vim.public'] = public })
|
||||
|
||||
-- Check table identity: both links must reference the original parsed module.
|
||||
eq(true, core == public.imports._core)
|
||||
eq(true, core == public.parent)
|
||||
eq(true, public.assignments.create)
|
||||
eq({}, funs)
|
||||
eq('create', core_funs[1].name)
|
||||
eq('vim._core', core_funs[1].module)
|
||||
eq('Shared function.', core_funs[1].desc)
|
||||
eq({ { type = 'string' } }, core_funs[1].returns)
|
||||
eq(nil, core_funs[1].nodoc)
|
||||
end)
|
||||
|
||||
it('parses multiline return annotations', function()
|
||||
local _, funs = parser.parse_str(
|
||||
dedent([[
|
||||
@@ -168,7 +262,8 @@ describe('luacats parser', function()
|
||||
|
||||
it('tracks class member declaration style', function()
|
||||
local classes, funs = parser.parse_str(
|
||||
dedent([[ --- @class vim.MyClass
|
||||
dedent([[
|
||||
--- @class vim.MyClass
|
||||
local MyClass = {}
|
||||
|
||||
--- Dot member.
|
||||
|
||||
Reference in new issue
Block a user