Merge pull request #24363 from lewis6991/docs/luatypes

docs(lua): move some function docs to lua files
This commit is contained in:
Lewis Russell
2023-07-17 17:40:14 +01:00
committed by GitHub
22 changed files with 2201 additions and 1255 deletions

View File

@@ -1189,8 +1189,8 @@ format({options}) *vim.lsp.buf.format()*
server clients. server clients.
Parameters: ~ Parameters: ~
• {options} table|nil Optional table which holds the following optional • {options} (table|nil) Optional table which holds the following
fields: optional fields:
• formatting_options (table|nil): Can be used to specify • formatting_options (table|nil): Can be used to specify
FormattingOptions. Some unspecified options will be FormattingOptions. Some unspecified options will be
automatically derived from the current Nvim options. See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#formattingOptions automatically derived from the current Nvim options. See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#formattingOptions
@@ -1204,10 +1204,10 @@ format({options}) *vim.lsp.buf.format()*
Receives a client as argument and must return a boolean. Receives a client as argument and must return a boolean.
Clients matching the predicate are included. Example: • >lua Clients matching the predicate are included. Example: • >lua
-- Never request typescript-language-server for formatting -- Never request typescript-language-server for formatting
vim.lsp.buf.format { vim.lsp.buf.format {
filter = function(client) return client.name ~= "tsserver" end filter = function(client) return client.name ~= "tsserver" end
} }
< <
• async boolean|nil If true the method won't block. • async boolean|nil If true the method won't block.
Defaults to false. Editing the buffer while formatting Defaults to false. Editing the buffer while formatting

File diff suppressed because it is too large Load Diff

View File

@@ -119,11 +119,11 @@ The following new APIs or features were added.
• Added an omnifunc implementation for Lua, |vim.lua_omnifunc()| • Added an omnifunc implementation for Lua, |vim.lua_omnifunc()|
• Added a new experimental |lua-loader| that byte-compiles and caches Lua files. • Added a new experimental |vim.loader| that byte-compiles and caches Lua files.
To enable the new loader, add the following at the top of your |init.lua|: >lua To enable the new loader, add the following at the top of your |init.lua|: >lua
vim.loader.enable() vim.loader.enable()
• Added |lua-version| for parsing and comparing version strings conforming to • Added |vim.version| for parsing and comparing version strings conforming to
the semver specification. the semver specification.
• When using Nvim inside tmux 3.2 or later, the default clipboard provider • When using Nvim inside tmux 3.2 or later, the default clipboard provider
@@ -273,7 +273,7 @@ REMOVED FEATURES
The following deprecated functions or APIs were removed. The following deprecated functions or APIs were removed.
• `filetype.vim` is removed in favor of |lua-filetype| • `filetype.vim` is removed in favor of |vim.filetype|
(Note that filetype logic and tests still align with Vim, so additions or (Note that filetype logic and tests still align with Vim, so additions or
changes need to be contributed there first.) changes need to be contributed there first.)
See https://github.com/neovim/neovim/pull/20674. See https://github.com/neovim/neovim/pull/20674.

View File

@@ -793,17 +793,17 @@ get_filetypes({lang}) *vim.treesitter.language.get_filetypes()*
Get the filetypes associated with the parser named {lang}. Get the filetypes associated with the parser named {lang}.
Parameters: ~ Parameters: ~
• {lang} string Name of parser • {lang} (string) Name of parser
Return: ~ Return: ~
string[] filetypes string[] filetypes
get_lang({filetype}) *vim.treesitter.language.get_lang()* get_lang({filetype}) *vim.treesitter.language.get_lang()*
Parameters: ~ Parameters: ~
• {filetype} string • {filetype} (string)
Return: ~ Return: ~
string|nil (string|nil)
inspect({lang}) *vim.treesitter.language.inspect()* inspect({lang}) *vim.treesitter.language.inspect()*
Inspects the provided language. Inspects the provided language.
@@ -821,7 +821,7 @@ register({lang}, {filetype}) *vim.treesitter.language.register()*
Register a parser named {lang} to be used for {filetype}(s). Register a parser named {lang} to be used for {filetype}(s).
Parameters: ~ Parameters: ~
• {lang} string Name of parser • {lang} (string) Name of parser
• {filetype} string|string[] Filetype(s) to associate with lang • {filetype} string|string[] Filetype(s) to associate with lang
@@ -947,7 +947,7 @@ parse({lang}, {query}) *vim.treesitter.query.parse()*
Query Parsed query Query Parsed query
*Query:iter_captures()* *Query:iter_captures()*
Query:iter_captures({self}, {node}, {source}, {start}, {stop}) Query:iter_captures({node}, {source}, {start}, {stop})
Iterate over all captures from all matches inside {node} Iterate over all captures from all matches inside {node}
{source} is needed if the query contains predicates; then the caller must {source} is needed if the query contains predicates; then the caller must
@@ -976,14 +976,13 @@ Query:iter_captures({self}, {node}, {source}, {start}, {stop})
from from
• {start} (integer) Starting line for the search • {start} (integer) Starting line for the search
• {stop} (integer) Stopping line for the search (end-exclusive) • {stop} (integer) Stopping line for the search (end-exclusive)
• {self}
Return: ~ Return: ~
(fun(): integer, TSNode, TSMetadata): capture id, capture node, (fun(): integer, TSNode, TSMetadata): capture id, capture node,
metadata metadata
*Query:iter_matches()* *Query:iter_matches()*
Query:iter_matches({self}, {node}, {source}, {start}, {stop}, {opts}) Query:iter_matches({node}, {source}, {start}, {stop}, {opts})
Iterates the matches of self on a given range. Iterates the matches of self on a given range.
Iterate over all matches within a {node}. The arguments are the same as Iterate over all matches within a {node}. The arguments are the same as
@@ -1015,7 +1014,6 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop}, {opts})
start depth for each match. This is used to prevent start depth for each match. This is used to prevent
traversing too deep into a tree. Requires treesitter >= traversing too deep into a tree. Requires treesitter >=
0.20.9. 0.20.9.
• {self}
Return: ~ Return: ~
(fun(): integer, table<integer,TSNode>, table): pattern id, match, (fun(): integer, table<integer,TSNode>, table): pattern id, match,
@@ -1036,12 +1034,9 @@ set({lang}, {query_name}, {text}) *vim.treesitter.query.set()*
============================================================================== ==============================================================================
Lua module: vim.treesitter.highlighter *lua-treesitter-highlighter* Lua module: vim.treesitter.highlighter *lua-treesitter-highlighter*
TSHighlighter:destroy({self}) *TSHighlighter:destroy()* TSHighlighter:destroy() *TSHighlighter:destroy()*
Removes all internal references to the highlighter Removes all internal references to the highlighter
Parameters: ~
• {self}
============================================================================== ==============================================================================
Lua module: vim.treesitter.languagetree *lua-treesitter-languagetree* Lua module: vim.treesitter.languagetree *lua-treesitter-languagetree*
@@ -1056,7 +1051,9 @@ contents.
To create a LanguageTree (parser object) for a given buffer and language, use: To create a LanguageTree (parser object) for a given buffer and language, use:
>lua >lua
local parser = vim.treesitter.get_parser(bufnr, lang)
local parser = vim.treesitter.get_parser(bufnr, lang)
< <
(where `bufnr=0` means current buffer). `lang` defaults to 'filetype'. (where `bufnr=0` means current buffer). `lang` defaults to 'filetype'.
@@ -1067,7 +1064,9 @@ it wants incremental updates.
Whenever you need to access the current syntax tree, parse the buffer: Whenever you need to access the current syntax tree, parse the buffer:
>lua >lua
local tree = parser:parse()
local tree = parser:parse()
< <
This returns a table of immutable |treesitter-tree| objects representing This returns a table of immutable |treesitter-tree| objects representing
@@ -1084,97 +1083,78 @@ change callback anyway as they will be very frequent. Rather a plugin that
does any kind of analysis on a tree should use a timer to throttle too does any kind of analysis on a tree should use a timer to throttle too
frequent updates. frequent updates.
LanguageTree:children({self}) *LanguageTree:children()* LanguageTree:children() *LanguageTree:children()*
Returns a map of language to child tree. Returns a map of language to child tree.
Parameters: ~ LanguageTree:contains({range}) *LanguageTree:contains()*
• {self}
LanguageTree:contains({self}, {range}) *LanguageTree:contains()*
Determines whether {range} is contained in the |LanguageTree|. Determines whether {range} is contained in the |LanguageTree|.
Parameters: ~ Parameters: ~
• {range} (table) `{ start_line, start_col, end_line, end_col }` • {range} (table) `{ start_line, start_col, end_line, end_col }`
• {self}
Return: ~ Return: ~
(boolean) (boolean)
LanguageTree:destroy({self}) *LanguageTree:destroy()* LanguageTree:destroy() *LanguageTree:destroy()*
Destroys this |LanguageTree| and all its children. Destroys this |LanguageTree| and all its children.
Any cleanup logic should be performed here. Any cleanup logic should be performed here.
Note: This DOES NOT remove this tree from a parent. Instead, `remove_child` must be called on the parent to remove it. Note: This DOES NOT remove this tree from a parent. Instead, `remove_child` must be called on the parent to remove it.
Parameters: ~
• {self}
*LanguageTree:for_each_child()* *LanguageTree:for_each_child()*
LanguageTree:for_each_child({self}, {fn}, {include_self}) LanguageTree:for_each_child({fn}, {include_self})
Invokes the callback for each |LanguageTree| and its children recursively Invokes the callback for each |LanguageTree| and its children recursively
Parameters: ~ Parameters: ~
• {fn} fun(tree: LanguageTree, lang: string) • {fn} fun(tree: LanguageTree, lang: string)
• {include_self} (boolean|nil) Whether to include the invoking tree in • {include_self} (boolean|nil) Whether to include the invoking tree in
the results the results
• {self}
LanguageTree:for_each_tree({self}, {fn}) *LanguageTree:for_each_tree()* LanguageTree:for_each_tree({fn}) *LanguageTree:for_each_tree()*
Invokes the callback for each |LanguageTree| recursively. Invokes the callback for each |LanguageTree| recursively.
Note: This includes the invoking tree's child trees as well. Note: This includes the invoking tree's child trees as well.
Parameters: ~ Parameters: ~
• {fn} fun(tree: TSTree, ltree: LanguageTree) • {fn} fun(tree: TSTree, ltree: LanguageTree)
• {self}
LanguageTree:included_regions({self}) *LanguageTree:included_regions()* LanguageTree:included_regions() *LanguageTree:included_regions()*
Gets the set of included regions Gets the set of included regions
Parameters: ~
• {self}
Return: ~ Return: ~
integer[][] integer[][]
LanguageTree:invalidate({self}, {reload}) *LanguageTree:invalidate()* LanguageTree:invalidate({reload}) *LanguageTree:invalidate()*
Invalidates this parser and all its children Invalidates this parser and all its children
Parameters: ~ Parameters: ~
• {reload} (boolean|nil) • {reload} (boolean|nil)
• {self}
*LanguageTree:is_valid()* LanguageTree:is_valid({exclude_children}) *LanguageTree:is_valid()*
LanguageTree:is_valid({self}, {exclude_children})
Determines whether this tree is valid. If the tree is invalid, call `parse()` . This will return the updated tree. Determines whether this tree is valid. If the tree is invalid, call `parse()` . This will return the updated tree.
Parameters: ~ Parameters: ~
• {exclude_children} (boolean|nil) • {exclude_children} (boolean|nil)
• {self}
Return: ~ Return: ~
(boolean) (boolean)
LanguageTree:lang({self}) *LanguageTree:lang()* LanguageTree:lang() *LanguageTree:lang()*
Gets the language of this tree node. Gets the language of this tree node.
Parameters: ~
• {self}
*LanguageTree:language_for_range()* *LanguageTree:language_for_range()*
LanguageTree:language_for_range({self}, {range}) LanguageTree:language_for_range({range})
Gets the appropriate language that contains {range}. Gets the appropriate language that contains {range}.
Parameters: ~ Parameters: ~
• {range} (table) `{ start_line, start_col, end_line, end_col }` • {range} (table) `{ start_line, start_col, end_line, end_col }`
• {self}
Return: ~ Return: ~
|LanguageTree| Managing {range} |LanguageTree| Managing {range}
*LanguageTree:named_node_for_range()* *LanguageTree:named_node_for_range()*
LanguageTree:named_node_for_range({self}, {range}, {opts}) LanguageTree:named_node_for_range({range}, {opts})
Gets the smallest named node that contains {range}. Gets the smallest named node that contains {range}.
Parameters: ~ Parameters: ~
@@ -1182,53 +1162,46 @@ LanguageTree:named_node_for_range({self}, {range}, {opts})
• {opts} (table|nil) Optional keyword arguments: • {opts} (table|nil) Optional keyword arguments:
• ignore_injections boolean Ignore injected languages • ignore_injections boolean Ignore injected languages
(default true) (default true)
• {self}
Return: ~ Return: ~
|TSNode| | nil Found node |TSNode| | nil Found node
LanguageTree:parse({self}) *LanguageTree:parse()* LanguageTree:parse() *LanguageTree:parse()*
Parses all defined regions using a treesitter parser for the language this Parses all defined regions using a treesitter parser for the language this
tree represents. This will run the injection query for this language to tree represents. This will run the injection query for this language to
determine if any child languages should be created. determine if any child languages should be created.
Parameters: ~
• {self}
Return: ~ Return: ~
TSTree[] TSTree[]
*LanguageTree:register_cbs()* *LanguageTree:register_cbs()*
LanguageTree:register_cbs({self}, {cbs}, {recursive}) LanguageTree:register_cbs({cbs}, {recursive})
Registers callbacks for the |LanguageTree|. Registers callbacks for the |LanguageTree|.
Parameters: ~ Parameters: ~
• {cbs} (table) An |nvim_buf_attach()|-like table argument with • {cbs} (table) An |nvim_buf_attach()|-like table argument with
the following handlers: the following handlers:
• `on_bytes` : see |nvim_buf_attach()|, but this will be called after the parsers callback. • `on_bytes` : see |nvim_buf_attach()|, but this will be called after the parsers callback.
• `on_changedtree` : a callback that will be called • `on_changedtree` : a callback that will be called every
every time the tree has syntactical changes. It will time the tree has syntactical changes. It will be
be passed two arguments: a table of the ranges (as passed two arguments: a table of the ranges (as node
node ranges) that changed and the changed tree. ranges) that changed and the changed tree.
• `on_child_added` : emitted when a child is added to • `on_child_added` : emitted when a child is added to the
the tree. tree.
• `on_child_removed` : emitted when a child is removed • `on_child_removed` : emitted when a child is removed
from the tree. from the tree.
• `on_detach` : emitted when the buffer is detached, see • `on_detach` : emitted when the buffer is detached, see
|nvim_buf_detach_event|. Takes one argument, the |nvim_buf_detach_event|. Takes one argument, the number
number of the buffer. of the buffer.
• {recursive?} boolean Apply callbacks recursively for all children. • {recursive} (boolean|nil) Apply callbacks recursively for all
Any new children will also inherit the callbacks. children. Any new children will also inherit the
• {self} callbacks.
LanguageTree:source({self}) *LanguageTree:source()* LanguageTree:source() *LanguageTree:source()*
Returns the source content of the language tree (bufnr or string). Returns the source content of the language tree (bufnr or string).
Parameters: ~
• {self}
*LanguageTree:tree_for_range()* *LanguageTree:tree_for_range()*
LanguageTree:tree_for_range({self}, {range}, {opts}) LanguageTree:tree_for_range({range}, {opts})
Gets the tree that contains {range}. Gets the tree that contains {range}.
Parameters: ~ Parameters: ~
@@ -1236,16 +1209,12 @@ LanguageTree:tree_for_range({self}, {range}, {opts})
• {opts} (table|nil) Optional keyword arguments: • {opts} (table|nil) Optional keyword arguments:
• ignore_injections boolean Ignore injected languages • ignore_injections boolean Ignore injected languages
(default true) (default true)
• {self}
Return: ~ Return: ~
TSTree|nil TSTree|nil
LanguageTree:trees({self}) *LanguageTree:trees()* LanguageTree:trees() *LanguageTree:trees()*
Returns all trees this language tree contains. Does not include child Returns all trees this language tree contains. Does not include child
languages. languages.
Parameters: ~
• {self}
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl: vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@@ -186,7 +186,7 @@ backwards-compatibility cost. Some examples:
Some features are built in that otherwise required external plugins: Some features are built in that otherwise required external plugins:
- Highlighting the yanked region, see |lua-highlight|. - Highlighting the yanked region, see |vim.highlight|.
ARCHITECTURE ARCHITECTURE

View File

@@ -1094,7 +1094,7 @@ function vim._init_defaults()
vim._init_default_autocmds() vim._init_default_autocmds()
end end
require('vim._meta') require('vim._options')
-- Remove at Nvim 1.0 -- Remove at Nvim 1.0
---@deprecated ---@deprecated

View File

@@ -1,575 +0,0 @@
local api = vim.api
-- TODO(tjdevries): Improve option metadata so that this doesn't have to be hardcoded.
-- Can be done in a separate PR.
local key_value_options = {
fillchars = true,
fcs = true,
listchars = true,
lcs = true,
winhighlight = true,
winhl = true,
}
--- Convert a vimoption_T style dictionary to the correct OptionType associated with it.
---@return string
local function get_option_metatype(name, info)
if info.type == 'string' then
if info.flaglist then
return 'set'
elseif info.commalist then
if key_value_options[name] then
return 'map'
end
return 'array'
end
return 'string'
end
return info.type
end
local options_info = setmetatable({}, {
__index = function(t, k)
local info = api.nvim_get_option_info(k)
info.metatype = get_option_metatype(k, info)
rawset(t, k, info)
return rawget(t, k)
end,
})
vim.env = setmetatable({}, {
__index = function(_, k)
local v = vim.fn.getenv(k)
if v == vim.NIL then
return nil
end
return v
end,
__newindex = function(_, k, v)
vim.fn.setenv(k, v)
end,
})
local function opt_validate(option_name, target_scope)
local scope = options_info[option_name].scope
if scope ~= target_scope then
local scope_to_string = { buf = 'buffer', win = 'window' }
error(
string.format(
[['%s' is a %s option, not a %s option. See ":help %s"]],
option_name,
scope_to_string[scope] or scope,
scope_to_string[target_scope] or target_scope,
option_name
)
)
end
end
local function new_buf_opt_accessor(bufnr)
return setmetatable({}, {
__index = function(_, k)
if bufnr == nil and type(k) == 'number' then
return new_buf_opt_accessor(k)
end
opt_validate(k, 'buf')
return api.nvim_get_option_value(k, { buf = bufnr or 0 })
end,
__newindex = function(_, k, v)
opt_validate(k, 'buf')
return api.nvim_set_option_value(k, v, { buf = bufnr or 0 })
end,
})
end
vim.bo = new_buf_opt_accessor()
local function new_win_opt_accessor(winid, bufnr)
return setmetatable({}, {
__index = function(_, k)
if bufnr == nil and type(k) == 'number' then
if winid == nil then
return new_win_opt_accessor(k)
else
return new_win_opt_accessor(winid, k)
end
end
if bufnr ~= nil and bufnr ~= 0 then
error('only bufnr=0 is supported')
end
opt_validate(k, 'win')
-- TODO(lewis6991): allow passing both buf and win to nvim_get_option_value
return api.nvim_get_option_value(k, {
scope = bufnr and 'local' or nil,
win = winid or 0,
})
end,
__newindex = function(_, k, v)
opt_validate(k, 'win')
-- TODO(lewis6991): allow passing both buf and win to nvim_set_option_value
return api.nvim_set_option_value(k, v, {
scope = bufnr and 'local' or nil,
win = winid or 0,
})
end,
})
end
vim.wo = new_win_opt_accessor()
-- vim global option
-- this ONLY sets the global option. like `setglobal`
vim.go = setmetatable({}, {
__index = function(_, k)
return api.nvim_get_option_value(k, { scope = 'global' })
end,
__newindex = function(_, k, v)
return api.nvim_set_option_value(k, v, { scope = 'global' })
end,
})
-- vim `set` style options.
-- it has no additional metamethod magic.
vim.o = setmetatable({}, {
__index = function(_, k)
return api.nvim_get_option_value(k, {})
end,
__newindex = function(_, k, v)
return api.nvim_set_option_value(k, v, {})
end,
})
---@brief [[
--- vim.opt, vim.opt_local and vim.opt_global implementation
---
--- To be used as helpers for working with options within neovim.
--- For information on how to use, see :help vim.opt
---
---@brief ]]
--- Preserves the order and does not mutate the original list
local function remove_duplicate_values(t)
local result, seen = {}, {}
for _, v in ipairs(t) do
if not seen[v] then
table.insert(result, v)
end
seen[v] = true
end
return result
end
-- Check whether the OptionTypes is allowed for vim.opt
-- If it does not match, throw an error which indicates which option causes the error.
local function assert_valid_value(name, value, types)
local type_of_value = type(value)
for _, valid_type in ipairs(types) do
if valid_type == type_of_value then
return
end
end
error(
string.format(
"Invalid option type '%s' for '%s', should be %s",
type_of_value,
name,
table.concat(types, ' or ')
)
)
end
local function passthrough(_, x)
return x
end
local function tbl_merge(left, right)
return vim.tbl_extend('force', left, right)
end
local function tbl_remove(t, value)
if type(value) == 'string' then
t[value] = nil
else
for _, v in ipairs(value) do
t[v] = nil
end
end
return t
end
local valid_types = {
boolean = { 'boolean' },
number = { 'number' },
string = { 'string' },
set = { 'string', 'table' },
array = { 'string', 'table' },
map = { 'string', 'table' },
}
-- Map of functions to take a Lua style value and convert to vimoption_T style value.
-- Each function takes (info, lua_value) -> vim_value
local to_vim_value = {
boolean = passthrough,
number = passthrough,
string = passthrough,
set = function(info, value)
if type(value) == 'string' then
return value
end
if info.flaglist and info.commalist then
local keys = {}
for k, v in pairs(value) do
if v then
table.insert(keys, k)
end
end
table.sort(keys)
return table.concat(keys, ',')
else
local result = ''
for k, v in pairs(value) do
if v then
result = result .. k
end
end
return result
end
end,
array = function(info, value)
if type(value) == 'string' then
return value
end
if not info.allows_duplicates then
value = remove_duplicate_values(value)
end
return table.concat(value, ',')
end,
map = function(_, value)
if type(value) == 'string' then
return value
end
local result = {}
for opt_key, opt_value in pairs(value) do
table.insert(result, string.format('%s:%s', opt_key, opt_value))
end
table.sort(result)
return table.concat(result, ',')
end,
}
--- Convert a Lua value to a vimoption_T value
local function convert_value_to_vim(name, info, value)
if value == nil then
return vim.NIL
end
assert_valid_value(name, value, valid_types[info.metatype])
return to_vim_value[info.metatype](info, value)
end
-- Map of OptionType to functions that take vimoption_T values and convert to Lua values.
-- Each function takes (info, vim_value) -> lua_value
local to_lua_value = {
boolean = passthrough,
number = passthrough,
string = passthrough,
array = function(info, value)
if type(value) == 'table' then
if not info.allows_duplicates then
value = remove_duplicate_values(value)
end
return value
end
-- Empty strings mean that there is nothing there,
-- so empty table should be returned.
if value == '' then
return {}
end
-- Handles unescaped commas in a list.
if string.find(value, ',,,') then
local left, right = unpack(vim.split(value, ',,,'))
local result = {}
vim.list_extend(result, vim.split(left, ','))
table.insert(result, ',')
vim.list_extend(result, vim.split(right, ','))
table.sort(result)
return result
end
if string.find(value, ',^,,', 1, true) then
local left, right = unpack(vim.split(value, ',^,,', true))
local result = {}
vim.list_extend(result, vim.split(left, ','))
table.insert(result, '^,')
vim.list_extend(result, vim.split(right, ','))
table.sort(result)
return result
end
return vim.split(value, ',')
end,
set = function(info, value)
if type(value) == 'table' then
return value
end
-- Empty strings mean that there is nothing there,
-- so empty table should be returned.
if value == '' then
return {}
end
assert(info.flaglist, 'That is the only one I know how to handle')
if info.flaglist and info.commalist then
local split_value = vim.split(value, ',')
local result = {}
for _, v in ipairs(split_value) do
result[v] = true
end
return result
else
local result = {}
for i = 1, #value do
result[value:sub(i, i)] = true
end
return result
end
end,
map = function(info, raw_value)
if type(raw_value) == 'table' then
return raw_value
end
assert(info.commalist, 'Only commas are supported currently')
local result = {}
local comma_split = vim.split(raw_value, ',')
for _, key_value_str in ipairs(comma_split) do
local key, value = unpack(vim.split(key_value_str, ':'))
key = vim.trim(key)
result[key] = value
end
return result
end,
}
--- Converts a vimoption_T style value to a Lua value
local function convert_value_to_lua(info, option_value)
return to_lua_value[info.metatype](info, option_value)
end
local prepend_methods = {
number = function()
error("The '^' operator is not currently supported for")
end,
string = function(left, right)
return right .. left
end,
array = function(left, right)
for i = #right, 1, -1 do
table.insert(left, 1, right[i])
end
return left
end,
map = tbl_merge,
set = tbl_merge,
}
--- Handles the '^' operator
local function prepend_value(info, current, new)
return prepend_methods[info.metatype](
convert_value_to_lua(info, current),
convert_value_to_lua(info, new)
)
end
local add_methods = {
number = function(left, right)
return left + right
end,
string = function(left, right)
return left .. right
end,
array = function(left, right)
for _, v in ipairs(right) do
table.insert(left, v)
end
return left
end,
map = tbl_merge,
set = tbl_merge,
}
--- Handles the '+' operator
local function add_value(info, current, new)
return add_methods[info.metatype](
convert_value_to_lua(info, current),
convert_value_to_lua(info, new)
)
end
local function remove_one_item(t, val)
if vim.tbl_islist(t) then
local remove_index = nil
for i, v in ipairs(t) do
if v == val then
remove_index = i
end
end
if remove_index then
table.remove(t, remove_index)
end
else
t[val] = nil
end
end
local remove_methods = {
number = function(left, right)
return left - right
end,
string = function()
error('Subtraction not supported for strings.')
end,
array = function(left, right)
if type(right) == 'string' then
remove_one_item(left, right)
else
for _, v in ipairs(right) do
remove_one_item(left, v)
end
end
return left
end,
map = tbl_remove,
set = tbl_remove,
}
--- Handles the '-' operator
local function remove_value(info, current, new)
return remove_methods[info.metatype](convert_value_to_lua(info, current), new)
end
local function create_option_accessor(scope)
local option_mt
local function make_option(name, value)
local info = assert(options_info[name], 'Not a valid option name: ' .. name)
if type(value) == 'table' and getmetatable(value) == option_mt then
assert(name == value._name, "must be the same value, otherwise that's weird.")
value = value._value
end
return setmetatable({
_name = name,
_value = value,
_info = info,
}, option_mt)
end
option_mt = {
-- To set a value, instead use:
-- opt[my_option] = value
_set = function(self)
local value = convert_value_to_vim(self._name, self._info, self._value)
api.nvim_set_option_value(self._name, value, { scope = scope })
end,
get = function(self)
return convert_value_to_lua(self._info, self._value)
end,
append = function(self, right)
self._value = add_value(self._info, self._value, right)
self:_set()
end,
__add = function(self, right)
return make_option(self._name, add_value(self._info, self._value, right))
end,
prepend = function(self, right)
self._value = prepend_value(self._info, self._value, right)
self:_set()
end,
__pow = function(self, right)
return make_option(self._name, prepend_value(self._info, self._value, right))
end,
remove = function(self, right)
self._value = remove_value(self._info, self._value, right)
self:_set()
end,
__sub = function(self, right)
return make_option(self._name, remove_value(self._info, self._value, right))
end,
}
option_mt.__index = option_mt
return setmetatable({}, {
__index = function(_, k)
return make_option(k, api.nvim_get_option_value(k, {}))
end,
__newindex = function(_, k, v)
make_option(k, v):_set()
end,
})
end
vim.opt = create_option_accessor()
vim.opt_local = create_option_accessor('local')
vim.opt_global = create_option_accessor('global')

View File

@@ -0,0 +1,238 @@
---@meta
-- luacheck: no unused args
---@defgroup vim.builtin
---
---@brief <pre>help
---vim.api.{func}({...}) *vim.api*
--- Invokes Nvim |API| function {func} with arguments {...}.
--- Example: call the "nvim_get_current_line()" API function: >lua
--- print(tostring(vim.api.nvim_get_current_line()))
---
---vim.NIL *vim.NIL*
--- Special value representing NIL in |RPC| and |v:null| in Vimscript
--- conversion, and similar cases. Lua `nil` cannot be used as part of a Lua
--- table representing a Dictionary or Array, because it is treated as
--- missing: `{"foo", nil}` is the same as `{"foo"}`.
---
---vim.type_idx *vim.type_idx*
--- Type index for use in |lua-special-tbl|. Specifying one of the values from
--- |vim.types| allows typing the empty table (it is unclear whether empty Lua
--- table represents empty list or empty array) and forcing integral numbers
--- to be |Float|. See |lua-special-tbl| for more details.
---
---vim.val_idx *vim.val_idx*
--- Value index for tables representing |Float|s. A table representing
--- floating-point value 1.0 looks like this: >lua
--- {
--- [vim.type_idx] = vim.types.float,
--- [vim.val_idx] = 1.0,
--- }
---< See also |vim.type_idx| and |lua-special-tbl|.
---
---vim.types *vim.types*
--- Table with possible values for |vim.type_idx|. Contains two sets of
--- key-value pairs: first maps possible values for |vim.type_idx| to
--- human-readable strings, second maps human-readable type names to values
--- for |vim.type_idx|. Currently contains pairs for `float`, `array` and
--- `dictionary` types.
---
--- Note: One must expect that values corresponding to `vim.types.float`,
--- `vim.types.array` and `vim.types.dictionary` fall under only two following
--- assumptions:
--- 1. Value may serve both as a key and as a value in a table. Given the
--- properties of Lua tables this basically means “value is not `nil`”.
--- 2. For each value in `vim.types` table `vim.types[vim.types[value]]` is the
--- same as `value`.
--- No other restrictions are put on types, and it is not guaranteed that
--- values corresponding to `vim.types.float`, `vim.types.array` and
--- `vim.types.dictionary` will not change or that `vim.types` table will only
--- contain values for these three types.
---
--- *log_levels* *vim.log.levels*
---Log levels are one of the values defined in `vim.log.levels`:
---
--- vim.log.levels.DEBUG
--- vim.log.levels.ERROR
--- vim.log.levels.INFO
--- vim.log.levels.TRACE
--- vim.log.levels.WARN
--- vim.log.levels.OFF
---
---</pre>
--- Returns true if the code is executing as part of a "fast" event handler,
--- where most of the API is disabled. These are low-level events (e.g.
--- |lua-loop-callbacks|) which can be invoked whenever Nvim polls for input.
--- When this is `false` most API functions are callable (but may be subject
--- to other restrictions such as |textlock|).
function vim.in_fast_event() end
--- Creates a special empty table (marked with a metatable), which Nvim to an
--- empty dictionary when translating Lua values to Vimscript or API types.
--- Nvim by default converts an empty table `{}` without this metatable to an
--- list/array.
---
--- Note: If numeric keys are present in the table, Nvim ignores the metatable
--- marker and converts the dict to a list/array anyway.
function vim.empty_dict() end
--- Sends {event} to {channel} via |RPC| and returns immediately. If {channel}
--- is 0, the event is broadcast to all channels.
---
--- This function also works in a fast callback |lua-loop-callbacks|.
--- @param channel integer
--- @param method string
--- @param args? any[]
--- @param ...? any
function vim.rpcnotify(channel, method, args, ...) end
--- Sends a request to {channel} to invoke {method} via |RPC| and blocks until
--- a response is received.
---
--- Note: NIL values as part of the return value is represented as |vim.NIL|
--- special value
--- @param channel integer
--- @param method string
--- @param args? any[]
--- @param ...? any
function vim.rpcrequest(channel, method, args, ...) end
--- Compares strings case-insensitively.
--- @param a string
--- @param b string
--- @return 0|1|-1
--- if strings are
--- equal, {a} is greater than {b} or {a} is lesser than {b}, respectively.
function vim.stricmp(a, b) end
--- Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not
--- supplied, it defaults to false (use UTF-32). Returns the byte index.
---
--- Invalid UTF-8 and NUL is treated like by |vim.str_byteindex()|.
--- 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
function vim.str_byteindex(str, index, use_utf16) end
--- Convert byte index to UTF-32 and UTF-16 indices. If {index} is not
--- supplied, the length of the string is used. All indices are zero-based.
---
--- Embedded NUL bytes are treated as terminating the string. 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.
--- @param str string
--- @param index? number
--- @return integer UTF-32 index
--- @return integer UTF-16 index
function vim.str_utfindex(str, index) end
--- 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 encoding names are whatever the iconv() library function
--- 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.
function vim.iconv(str, from, to, opts) end
--- Schedules {callback} to be invoked soon by the main event-loop. Useful
--- to avoid |textlock| or other temporary restrictions.
--- @param callback fun()
function vim.schedule(callback) end
--- Wait for {time} in milliseconds until {callback} returns `true`.
---
--- Executes {callback} immediately and at approximately {interval}
--- milliseconds (default 200). Nvim still processes other events during
--- this time.
---
--- Examples:
--- <pre>lua
---
--- ---
--- -- Wait for 100 ms, allowing other events to process
--- vim.wait(100, function() end)
---
--- ---
--- -- Wait for 100 ms or until global variable set.
--- vim.wait(100, function() return vim.g.waiting_for_var end)
---
--- ---
--- -- Wait for 1 second or until global variable set, checking every ~500 ms
--- vim.wait(1000, function() return vim.g.waiting_for_var end, 500)
---
--- ---
--- -- Schedule a function to set a value in 100ms
--- vim.defer_fn(function() vim.g.timer_result = true end, 100)
---
--- -- Would wait ten seconds if results blocked. Actually only waits 100 ms
--- if vim.wait(10000, function() return vim.g.timer_result end) then
--- print('Only waiting a little bit of time!')
--- end
--- </pre>
---
--- @param time integer Number of milliseconds to wait
--- @param callback? fun(): boolean Optional callback. Waits until {callback} returns true
--- @param interval? integer (Approximate) number of milliseconds to wait between polls
--- @param fast_only? boolean If true, only |api-fast| events will be processed.
--- If called from while in an |api-fast| event, will
--- automatically be set to `true`.
--- @return boolean, nil|-1|-2
--- - If {callback} returns `true` during the {time}: `true, nil`
--- - If {callback} never returns `true` during the {time}: `false, -1`
--- - If {callback} is interrupted during the {time}: `false, -2`
--- - If {callback} errors, the error is raised.
function vim.wait(time, callback, interval, fast_only) end
--- Attach to ui events, similar to |nvim_ui_attach()| but receive events
--- as Lua callback. Can be used to implement screen elements like
--- popupmenu or message handling in Lua.
---
--- {options} should be a dictionary-like table, where `ext_...` options should
--- be set to true to receive events for the respective external element.
---
--- {callback} receives event name plus additional parameters. See |ui-popupmenu|
--- and the sections below for event format for respective events.
---
--- WARNING: This api is considered experimental. Usability will vary for
--- different screen elements. In particular `ext_messages` behavior is subject
--- to further changes and usability improvements. This is expected to be
--- used to handle messages when setting 'cmdheight' to zero (which is
--- likewise experimental).
---
--- Example (stub for a |ui-popupmenu| implementation):
--- <pre>lua
---
--- ns = vim.api.nvim_create_namespace('my_fancy_pum')
---
--- vim.ui_attach(ns, {ext_popupmenu=true}, function(event, ...)
--- if event == "popupmenu_show" then
--- local items, selected, row, col, grid = ...
--- print("display pum ", #items)
--- elseif event == "popupmenu_select" then
--- local selected = ...
--- print("selected", selected)
--- elseif event == "popupmenu_hide" then
--- print("FIN")
--- end
--- end)
--- </pre>
--- @param ns integer
--- @param options table<string, any>
--- @param callback fun()
function vim.ui_attach(ns, options, callback) end
--- Detach a callback previously attached with |vim.ui_attach()| for the
--- given namespace {ns}.
--- @param ns integer
function vim.ui_detach(ns) end

View File

@@ -0,0 +1,69 @@
---@meta
-- luacheck: no unused args
--- Run diff on strings {a} and {b}. Any indices returned by this function,
--- either directly or via callback arguments, are 1-based.
---
--- Examples:
--- <pre>lua
--- vim.diff('a\\n', 'b\\nc\\n')
--- -- =>
--- -- @@ -1 +1,2 @@
--- -- -a
--- -- +b
--- -- +c
---
--- vim.diff('a\\n', 'b\\nc\\n', {result_type = 'indices'})
--- -- =>
--- -- {
--- -- {1, 1, 1, 2}
--- -- }
--- </pre>
---
--- @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
--- See {opts.result_type}. `nil` if {opts.on_hunk} is given.
function vim.diff(a, b, opts) end

View File

@@ -0,0 +1,37 @@
--- @meta
-- luacheck: no unused args
--- @defgroup vim.json
---
--- This module provides encoding and decoding of Lua objects to and
--- from JSON-encoded strings. Supports |vim.NIL| and |vim.empty_dict()|.
--- Decodes (or "unpacks") the JSON-encoded {str} to a Lua object.
---
--- - Decodes JSON "null" as |vim.NIL| (controllable by {opts}, see below).
--- - Decodes empty object as |vim.empty_dict()|.
--- - Decodes empty array as `{}` (empty Lua table).
---
--- Example:
--- <pre>lua
--- :lua vim.print(vim.json.decode('{"bar":[],"foo":{},"zub":null}'))
--- --> { bar = {}, foo = vim.empty_dict(), zub = vim.NIL }
--- </pre>
--- Parameters: ~
--- • {str} Stringified JSON data.
--- • {opts} Options map keys:
--- • luanil: { object: bool, array: bool }
--- • `luanil.object=true` converts `null` in JSON objects to
--- Lua `nil` instead of `vim.NIL`.
--- • `luanil.array=true` converts `null` in JSON arrays to Lua
--- `nil` instead of `vim.NIL`.
--- @param str string
--- @param opts? table<string, any>
--- @return any
function vim.json.decode(str, opts) end
--- Encodes (or "packs") Lua object {obj} as JSON in a Lua string.
--- @param obj any
--- @return string
function vim.json.encode(obj) end

View File

@@ -0,0 +1,13 @@
---@meta
-- luacheck: no unused args
--- Invokes |vim-function| or |user-function| {func} with arguments {...}.
--- See also |vim.fn|.
--- Equivalent to:
--- <pre>lua
--- vim.fn[func]({...})
--- </pre>
--- @param func fun()
--- @param ... any
function vim.call(func, ...) end

View File

@@ -0,0 +1,15 @@
--- @meta
-- luacheck: no unused args
--- @defgroup vim.mpack
---
--- This module provides encoding and decoding of Lua objects to and
--- from msgpack-encoded strings. Supports |vim.NIL| and |vim.empty_dict()|.
--- Decodes (or "unpacks") the msgpack-encoded {str} to a Lua object.
--- @param str string
function vim.mpack.decode(str) end
--- Encodes (or "packs") Lua object {obj} as msgpack in a Lua string.
function vim.mpack.encode(obj) end

View File

@@ -0,0 +1,36 @@
--- @meta
-- luacheck: no unused args
--- @defgroup vim.regex
---
--- @brief Vim regexes can be used directly from Lua. Currently they only allow
--- matching within a single line.
--- Parse the Vim regex {re} and return a regex object. Regexes are "magic"
--- and case-sensitive by default, regardless of 'magic' and 'ignorecase'.
--- They can be controlled with flags, see |/magic| and |/ignorecase|.
--- @param re string
--- @return vim.regex
function vim.regex(re) end
--- @class vim.regex
local regex = {} -- luacheck: no unused
--- Match the string against the regex. If the string should match the regex
--- precisely, surround the regex with `^` and `$`. If the was a match, the
--- byte indices for the beginning and end of the match is returned. When
--- there is no match, `nil` is returned. As any integer is truth-y,
--- `regex:match()` can be directly used as a condition in an if-statement.
--- @param str string
function regex:match_str(str) end
--- Match line {line_idx} (zero-based) in buffer {bufnr}. If {start} and {end}
--- are supplied, match only this byte index range. Otherwise see
--- |regex:match_str()|. If {start} is used, then the returned byte indices
--- will be relative {start}.
--- @param bufnr integer
--- @param line_idx integer
--- @param start? integer
--- @param end_? integer
function regex:match_line(bufnr, line_idx, start, end_) end

View File

@@ -0,0 +1,31 @@
--- @meta
-- luacheck: no unused args
--- Check {str} for spelling errors. Similar to the Vimscript function
--- |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()|.
---
--- Example:
--- <pre>lua
--- vim.spell.check("the quik brown fox")
--- -- =>
--- -- {
--- -- {'quik', 'bad', 5}
--- -- }
--- </pre>
---
--- @param str string
--- @return {[1]: string, [2]: string, [3]: string}[]
--- 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 start with Capital
--- - The position in {str} where the word begins.
function vim.spell.check(str) end

View File

@@ -0,0 +1,928 @@
---@defgroup lua-vimscript
---
---@brief Nvim Lua provides an interface or "bridge" to Vimscript variables and
---functions, and editor commands and options.
---
---Objects passed over this bridge are COPIED (marshalled): there are no
---"references". |lua-guide-variables| For example, using \`vim.fn.remove()\` on
---a Lua list copies the list object to Vimscript and does NOT modify the Lua
---list:
---<pre>lua
--- local list = { 1, 2, 3 }
--- vim.fn.remove(list, 0)
--- vim.print(list) --> "{ 1, 2, 3 }"
---</pre>
---@addtogroup lua-vimscript
---@brief <pre>help
---vim.call({func}, {...}) *vim.call()*
--- Invokes |vim-function| or |user-function| {func} with arguments {...}.
--- See also |vim.fn|.
--- Equivalent to: >lua
--- vim.fn[func]({...})
---<
---vim.cmd({command})
--- See |vim.cmd()|.
---
---vim.fn.{func}({...}) *vim.fn*
--- Invokes |vim-function| or |user-function| {func} with arguments {...}.
--- To call autoload functions, use the syntax: >lua
--- vim.fn['some\#function']({...})
---<
--- Unlike vim.api.|nvim_call_function()| this converts directly between Vim
--- objects and Lua objects. If the Vim function returns a float, it will be
--- represented directly as a Lua number. Empty lists and dictionaries both
--- are represented by an empty table.
---
--- Note: |v:null| values as part of the return value is represented as
--- |vim.NIL| special value
---
--- Note: vim.fn keys are generated lazily, thus `pairs(vim.fn)` only
--- enumerates functions that were called at least once.
---
--- Note: The majority of functions cannot run in |api-fast| callbacks with some
--- undocumented exceptions which are allowed.
---
--- *lua-vim-variables*
---The Vim editor global dictionaries |g:| |w:| |b:| |t:| |v:| can be accessed
---from Lua conveniently and idiomatically by referencing the `vim.*` Lua tables
---described below. In this way you can easily read and modify global Vimscript
---variables from Lua.
---
---Example: >lua
---
--- vim.g.foo = 5 -- Set the g:foo Vimscript variable.
--- print(vim.g.foo) -- Get and print the g:foo Vimscript variable.
--- vim.g.foo = nil -- Delete (:unlet) the Vimscript variable.
--- vim.b[2].foo = 6 -- Set b:foo for buffer 2
---<
---
---Note that setting dictionary fields directly will not write them back into
---Nvim. This is because the index into the namespace simply returns a copy.
---Instead the whole dictionary must be written as one. This can be achieved by
---creating a short-lived temporary.
---
---Example: >lua
---
--- vim.g.my_dict.field1 = 'value' -- Does not work
---
--- local my_dict = vim.g.my_dict --
--- my_dict.field1 = 'value' -- Instead do
--- vim.g.my_dict = my_dict --
---
---vim.g *vim.g*
--- Global (|g:|) editor variables.
--- Key with no value returns `nil`.
---
---vim.b *vim.b*
--- Buffer-scoped (|b:|) variables for the current buffer.
--- Invalid or unset key returns `nil`. Can be indexed with
--- an integer to access variables for a specific buffer.
---
---vim.w *vim.w*
--- Window-scoped (|w:|) variables for the current window.
--- Invalid or unset key returns `nil`. Can be indexed with
--- an integer to access variables for a specific window.
---
---vim.t *vim.t*
--- Tabpage-scoped (|t:|) variables for the current tabpage.
--- Invalid or unset key returns `nil`. Can be indexed with
--- an integer to access variables for a specific tabpage.
---
---vim.v *vim.v*
--- |v:| variables.
--- Invalid or unset key returns `nil`.
---
---vim.env *vim.env*
--- Environment variables defined in the editor session.
--- See |expand-env| and |:let-environment| for the Vimscript behavior.
--- Invalid or unset key returns `nil`.
--- Example: >lua
--- vim.env.FOO = 'bar'
--- print(vim.env.TERM)
---<
---</pre>
local api = vim.api
-- TODO(tjdevries): Improve option metadata so that this doesn't have to be hardcoded.
-- Can be done in a separate PR.
local key_value_options = {
fillchars = true,
fcs = true,
listchars = true,
lcs = true,
winhighlight = true,
winhl = true,
}
--- Convert a vimoption_T style dictionary to the correct OptionType associated with it.
---@return string
---@private
local function get_option_metatype(name, info)
if info.type == 'string' then
if info.flaglist then
return 'set'
elseif info.commalist then
if key_value_options[name] then
return 'map'
end
return 'array'
end
return 'string'
end
return info.type
end
local options_info = setmetatable({}, {
__index = function(t, k)
local info = api.nvim_get_option_info(k)
info.metatype = get_option_metatype(k, info)
rawset(t, k, info)
return rawget(t, k)
end,
})
vim.env = setmetatable({}, {
__index = function(_, k)
local v = vim.fn.getenv(k)
if v == vim.NIL then
return nil
end
return v
end,
__newindex = function(_, k, v)
vim.fn.setenv(k, v)
end,
})
---@private
local function opt_validate(option_name, target_scope)
local scope = options_info[option_name].scope
if scope ~= target_scope then
local scope_to_string = { buf = 'buffer', win = 'window' }
error(
string.format(
[['%s' is a %s option, not a %s option. See ":help %s"]],
option_name,
scope_to_string[scope] or scope,
scope_to_string[target_scope] or target_scope,
option_name
)
)
end
end
---@private
local function new_buf_opt_accessor(bufnr)
return setmetatable({}, {
__index = function(_, k)
if bufnr == nil and type(k) == 'number' then
return new_buf_opt_accessor(k)
end
opt_validate(k, 'buf')
return api.nvim_get_option_value(k, { buf = bufnr or 0 })
end,
__newindex = function(_, k, v)
opt_validate(k, 'buf')
return api.nvim_set_option_value(k, v, { buf = bufnr or 0 })
end,
})
end
---@private
local function new_win_opt_accessor(winid, bufnr)
return setmetatable({}, {
__index = function(_, k)
if bufnr == nil and type(k) == 'number' then
if winid == nil then
return new_win_opt_accessor(k)
else
return new_win_opt_accessor(winid, k)
end
end
if bufnr ~= nil and bufnr ~= 0 then
error('only bufnr=0 is supported')
end
opt_validate(k, 'win')
-- TODO(lewis6991): allow passing both buf and win to nvim_get_option_value
return api.nvim_get_option_value(k, {
scope = bufnr and 'local' or nil,
win = winid or 0,
})
end,
__newindex = function(_, k, v)
opt_validate(k, 'win')
-- TODO(lewis6991): allow passing both buf and win to nvim_set_option_value
return api.nvim_set_option_value(k, v, {
scope = bufnr and 'local' or nil,
win = winid or 0,
})
end,
})
end
---@addtogroup lua-vimscript
---@brief <pre>help
---` ` *lua-options*
--- *lua-vim-options*
--- *lua-vim-set*
--- *lua-vim-setlocal*
---
---Vim options can be accessed through |vim.o|, which behaves like Vimscript
---|:set|.
---
--- Examples: ~
---
--- To set a boolean toggle:
--- Vimscript: `set number`
--- Lua: `vim.o.number = true`
---
--- To set a string value:
--- Vimscript: `set wildignore=*.o,*.a,__pycache__`
--- Lua: `vim.o.wildignore = '*.o,*.a,__pycache__'`
---
---Similarly, there is |vim.bo| and |vim.wo| for setting buffer-scoped and
---window-scoped options. Note that this must NOT be confused with
---|local-options| and |:setlocal|. There is also |vim.go| that only accesses the
---global value of a |global-local| option, see |:setglobal|.
---</pre>
---@addtogroup lua-vimscript
---@brief <pre>help
---vim.o *vim.o*
--- Get or set |options|. Like `:set`. Invalid key is an error.
---
--- Note: this works on both buffer-scoped and window-scoped options using the
--- current buffer and window.
---
--- Example: >lua
--- vim.o.cmdheight = 4
--- print(vim.o.columns)
--- print(vim.o.foo) -- error: invalid key
---<
---</pre>
vim.o = setmetatable({}, {
__index = function(_, k)
return api.nvim_get_option_value(k, {})
end,
__newindex = function(_, k, v)
return api.nvim_set_option_value(k, v, {})
end,
})
---@addtogroup lua-vimscript
---@brief <pre>help
---vim.go *vim.go*
--- Get or set global |options|. Like `:setglobal`. Invalid key is
--- an error.
---
--- Note: this is different from |vim.o| because this accesses the global
--- option value and thus is mostly useful for use with |global-local|
--- options.
---
--- Example: >lua
--- vim.go.cmdheight = 4
--- print(vim.go.columns)
--- print(vim.go.bar) -- error: invalid key
---<
---</pre>
vim.go = setmetatable({}, {
__index = function(_, k)
return api.nvim_get_option_value(k, { scope = 'global' })
end,
__newindex = function(_, k, v)
return api.nvim_set_option_value(k, v, { scope = 'global' })
end,
})
---@addtogroup lua-vimscript
---@brief <pre>help
---vim.bo[{bufnr}] *vim.bo*
--- Get or set buffer-scoped |options| for the buffer with number {bufnr}.
--- Like `:set` and `:setlocal`. If [{bufnr}] is omitted then the current
--- buffer is used. Invalid {bufnr} or key is an error.
---
--- Note: this is equivalent to both `:set` and `:setlocal`.
---
--- Example: >lua
--- local bufnr = vim.api.nvim_get_current_buf()
--- vim.bo[bufnr].buflisted = true -- same as vim.bo.buflisted = true
--- print(vim.bo.comments)
--- print(vim.bo.baz) -- error: invalid key
---</pre>
vim.bo = new_buf_opt_accessor()
---@addtogroup lua-vimscript
---@brief <pre>help
---vim.wo[{winid}][{bufnr}] *vim.wo*
--- Get or set window-scoped |options| for the window with handle {winid} and
--- buffer with number {bufnr}. Like `:setlocal` if {bufnr} is provided, like
--- `:set` otherwise. If [{winid}] is omitted then the current window is
--- used. Invalid {winid}, {bufnr} or key is an error.
---
--- Note: only {bufnr} with value `0` (the current buffer in the window) is
--- supported.
---
--- Example: >lua
--- local winid = vim.api.nvim_get_current_win()
--- vim.wo[winid].number = true -- same as vim.wo.number = true
--- print(vim.wo.foldmarker)
--- print(vim.wo.quux) -- error: invalid key
--- vim.wo[winid][0].spell = false -- like ':setlocal nospell'
---<
---</pre>
vim.wo = new_win_opt_accessor()
---@brief [[
--- vim.opt, vim.opt_local and vim.opt_global implementation
---
--- To be used as helpers for working with options within neovim.
--- For information on how to use, see :help vim.opt
---
---@brief ]]
--- Preserves the order and does not mutate the original list
--- @private
local function remove_duplicate_values(t)
local result, seen = {}, {}
for _, v in ipairs(t) do
if not seen[v] then
table.insert(result, v)
end
seen[v] = true
end
return result
end
-- Check whether the OptionTypes is allowed for vim.opt
-- If it does not match, throw an error which indicates which option causes the error.
--- @private
local function assert_valid_value(name, value, types)
local type_of_value = type(value)
for _, valid_type in ipairs(types) do
if valid_type == type_of_value then
return
end
end
error(
string.format(
"Invalid option type '%s' for '%s', should be %s",
type_of_value,
name,
table.concat(types, ' or ')
)
)
end
--- @private
local function passthrough(_, x)
return x
end
--- @private
local function tbl_merge(left, right)
return vim.tbl_extend('force', left, right)
end
--- @private
local function tbl_remove(t, value)
if type(value) == 'string' then
t[value] = nil
else
for _, v in ipairs(value) do
t[v] = nil
end
end
return t
end
local valid_types = {
boolean = { 'boolean' },
number = { 'number' },
string = { 'string' },
set = { 'string', 'table' },
array = { 'string', 'table' },
map = { 'string', 'table' },
}
-- Map of functions to take a Lua style value and convert to vimoption_T style value.
-- Each function takes (info, lua_value) -> vim_value
local to_vim_value = {
boolean = passthrough,
number = passthrough,
string = passthrough,
set = function(info, value)
if type(value) == 'string' then
return value
end
if info.flaglist and info.commalist then
local keys = {}
for k, v in pairs(value) do
if v then
table.insert(keys, k)
end
end
table.sort(keys)
return table.concat(keys, ',')
else
local result = ''
for k, v in pairs(value) do
if v then
result = result .. k
end
end
return result
end
end,
array = function(info, value)
if type(value) == 'string' then
return value
end
if not info.allows_duplicates then
value = remove_duplicate_values(value)
end
return table.concat(value, ',')
end,
map = function(_, value)
if type(value) == 'string' then
return value
end
local result = {}
for opt_key, opt_value in pairs(value) do
table.insert(result, string.format('%s:%s', opt_key, opt_value))
end
table.sort(result)
return table.concat(result, ',')
end,
}
--- Convert a Lua value to a vimoption_T value
--- @private
local function convert_value_to_vim(name, info, value)
if value == nil then
return vim.NIL
end
assert_valid_value(name, value, valid_types[info.metatype])
return to_vim_value[info.metatype](info, value)
end
-- Map of OptionType to functions that take vimoption_T values and convert to Lua values.
-- Each function takes (info, vim_value) -> lua_value
local to_lua_value = {
boolean = passthrough,
number = passthrough,
string = passthrough,
array = function(info, value)
if type(value) == 'table' then
if not info.allows_duplicates then
value = remove_duplicate_values(value)
end
return value
end
-- Empty strings mean that there is nothing there,
-- so empty table should be returned.
if value == '' then
return {}
end
-- Handles unescaped commas in a list.
if string.find(value, ',,,') then
local left, right = unpack(vim.split(value, ',,,'))
local result = {}
vim.list_extend(result, vim.split(left, ','))
table.insert(result, ',')
vim.list_extend(result, vim.split(right, ','))
table.sort(result)
return result
end
if string.find(value, ',^,,', 1, true) then
local left, right = unpack(vim.split(value, ',^,,', true))
local result = {}
vim.list_extend(result, vim.split(left, ','))
table.insert(result, '^,')
vim.list_extend(result, vim.split(right, ','))
table.sort(result)
return result
end
return vim.split(value, ',')
end,
set = function(info, value)
if type(value) == 'table' then
return value
end
-- Empty strings mean that there is nothing there,
-- so empty table should be returned.
if value == '' then
return {}
end
assert(info.flaglist, 'That is the only one I know how to handle')
if info.flaglist and info.commalist then
local split_value = vim.split(value, ',')
local result = {}
for _, v in ipairs(split_value) do
result[v] = true
end
return result
else
local result = {}
for i = 1, #value do
result[value:sub(i, i)] = true
end
return result
end
end,
map = function(info, raw_value)
if type(raw_value) == 'table' then
return raw_value
end
assert(info.commalist, 'Only commas are supported currently')
local result = {}
local comma_split = vim.split(raw_value, ',')
for _, key_value_str in ipairs(comma_split) do
local key, value = unpack(vim.split(key_value_str, ':'))
key = vim.trim(key)
result[key] = value
end
return result
end,
}
--- Converts a vimoption_T style value to a Lua value
--- @private
local function convert_value_to_lua(info, option_value)
return to_lua_value[info.metatype](info, option_value)
end
local prepend_methods = {
number = function()
error("The '^' operator is not currently supported for")
end,
string = function(left, right)
return right .. left
end,
array = function(left, right)
for i = #right, 1, -1 do
table.insert(left, 1, right[i])
end
return left
end,
map = tbl_merge,
set = tbl_merge,
}
--- Handles the '^' operator
--- @private
local function prepend_value(info, current, new)
return prepend_methods[info.metatype](
convert_value_to_lua(info, current),
convert_value_to_lua(info, new)
)
end
local add_methods = {
number = function(left, right)
return left + right
end,
string = function(left, right)
return left .. right
end,
array = function(left, right)
for _, v in ipairs(right) do
table.insert(left, v)
end
return left
end,
map = tbl_merge,
set = tbl_merge,
}
--- Handles the '+' operator
--- @private
local function add_value(info, current, new)
return add_methods[info.metatype](
convert_value_to_lua(info, current),
convert_value_to_lua(info, new)
)
end
--- @private
local function remove_one_item(t, val)
if vim.tbl_islist(t) then
local remove_index = nil
for i, v in ipairs(t) do
if v == val then
remove_index = i
end
end
if remove_index then
table.remove(t, remove_index)
end
else
t[val] = nil
end
end
local remove_methods = {
number = function(left, right)
return left - right
end,
string = function()
error('Subtraction not supported for strings.')
end,
array = function(left, right)
if type(right) == 'string' then
remove_one_item(left, right)
else
for _, v in ipairs(right) do
remove_one_item(left, v)
end
end
return left
end,
map = tbl_remove,
set = tbl_remove,
}
--- Handles the '-' operator
--- @private
local function remove_value(info, current, new)
return remove_methods[info.metatype](convert_value_to_lua(info, current), new)
end
--- @private
local function create_option_accessor(scope)
local option_mt
--- @private
local function make_option(name, value)
local info = assert(options_info[name], 'Not a valid option name: ' .. name)
if type(value) == 'table' and getmetatable(value) == option_mt then
assert(name == value._name, "must be the same value, otherwise that's weird.")
value = value._value
end
return setmetatable({
_name = name,
_value = value,
_info = info,
}, option_mt)
end
option_mt = {
-- To set a value, instead use:
-- opt[my_option] = value
_set = function(self)
local value = convert_value_to_vim(self._name, self._info, self._value)
api.nvim_set_option_value(self._name, value, { scope = scope })
end,
get = function(self)
return convert_value_to_lua(self._info, self._value)
end,
append = function(self, right)
self._value = add_value(self._info, self._value, right)
self:_set()
end,
__add = function(self, right)
return make_option(self._name, add_value(self._info, self._value, right))
end,
prepend = function(self, right)
self._value = prepend_value(self._info, self._value, right)
self:_set()
end,
__pow = function(self, right)
return make_option(self._name, prepend_value(self._info, self._value, right))
end,
remove = function(self, right)
self._value = remove_value(self._info, self._value, right)
self:_set()
end,
__sub = function(self, right)
return make_option(self._name, remove_value(self._info, self._value, right))
end,
}
option_mt.__index = option_mt
return setmetatable({}, {
__index = function(_, k)
return make_option(k, api.nvim_get_option_value(k, {}))
end,
__newindex = function(_, k, v)
make_option(k, v):_set()
end,
})
end
---@addtogroup lua-vimscript
---@brief <pre>help
---` ` *vim.opt_local*
--- *vim.opt_global*
--- *vim.opt*
---
---
---A special interface |vim.opt| exists for conveniently interacting with list-
---and map-style option from Lua: It allows accessing them as Lua tables and
---offers object-oriented method for adding and removing entries.
---
--- Examples: ~
---
--- The following methods of setting a list-style option are equivalent:
--- In Vimscript: >vim
--- set wildignore=*.o,*.a,__pycache__
---<
--- In Lua using `vim.o`: >lua
--- vim.o.wildignore = '*.o,*.a,__pycache__'
---<
--- In Lua using `vim.opt`: >lua
--- vim.opt.wildignore = { '*.o', '*.a', '__pycache__' }
---<
--- To replicate the behavior of |:set+=|, use: >lua
---
--- vim.opt.wildignore:append { "*.pyc", "node_modules" }
---<
--- To replicate the behavior of |:set^=|, use: >lua
---
--- vim.opt.wildignore:prepend { "new_first_value" }
---<
--- To replicate the behavior of |:set-=|, use: >lua
---
--- vim.opt.wildignore:remove { "node_modules" }
---<
--- The following methods of setting a map-style option are equivalent:
--- In Vimscript: >vim
--- set listchars=space:_,tab:>~
---<
--- In Lua using `vim.o`: >lua
--- vim.o.listchars = 'space:_,tab:>~'
---<
--- In Lua using `vim.opt`: >lua
--- vim.opt.listchars = { space = '_', tab = '>~' }
---<
---
---Note that |vim.opt| returns an `Option` object, not the value of the option,
---which is accessed through |vim.opt:get()|:
---
--- Examples: ~
---
--- The following methods of getting a list-style option are equivalent:
--- In Vimscript: >vim
--- echo wildignore
---<
--- In Lua using `vim.o`: >lua
--- print(vim.o.wildignore)
---<
--- In Lua using `vim.opt`: >lua
--- vim.print(vim.opt.wildignore:get())
---<
---
---In any of the above examples, to replicate the behavior |:setlocal|, use
---`vim.opt_local`. Additionally, to replicate the behavior of |:setglobal|, use
---`vim.opt_global`.
---</pre>
--- @diagnostic disable-next-line:unused-local used for gen_vimdoc
local Option = {} -- luacheck: no unused
---Returns a Lua-representation of the option. Boolean, number and string
---values will be returned in exactly the same fashion.
---
---For values that are comma-separated lists, an array will be returned with
---the values as entries in the array: <pre>lua
--- vim.cmd [[set wildignore=*.pyc,*.o]]
---
--- vim.print(vim.opt.wildignore:get())
--- -- { "*.pyc", "*.o", }
---
--- for _, ignore_pattern in ipairs(vim.opt.wildignore:get()) do
--- print("Will ignore:", ignore_pattern)
--- end
--- -- Will ignore: *.pyc
--- -- Will ignore: *.o
---</pre>
---
---For values that are comma-separated maps, a table will be returned with
---the names as keys and the values as entries: <pre>lua
--- vim.cmd [[set listchars=space:_,tab:>~]]
---
--- vim.print(vim.opt.listchars:get())
--- -- { space = "_", tab = ">~", }
---
--- for char, representation in pairs(vim.opt.listchars:get()) do
--- print(char, "=>", representation)
--- end
---</pre>
---
---For values that are lists of flags, a set will be returned with the flags
---as keys and `true` as entries. <pre>lua
--- vim.cmd [[set formatoptions=njtcroql]]
---
--- vim.print(vim.opt.formatoptions:get())
--- -- { n = true, j = true, c = true, ... }
---
--- local format_opts = vim.opt.formatoptions:get()
--- if format_opts.j then
--- print("J is enabled!")
--- end
---</pre>
---@return string|integer|boolean|nil value of option
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
function Option:get() end
---Append a value to string-style options. See |:set+=|
---
---These are equivalent: <pre>lua
--- vim.opt.formatoptions:append('j')
--- vim.opt.formatoptions = vim.opt.formatoptions + 'j'
---</pre>
---@param value string Value to append
--- @diagnostic disable-next-line:unused-local used for gen_vimdoc
function Option:append(value) end -- luacheck: no unused
---Prepend a value to string-style options. See |:set^=|
---
---These are equivalent: <pre>lua
--- vim.opt.wildignore:prepend('*.o')
--- vim.opt.wildignore = vim.opt.wildignore ^ '*.o'
---</pre>
---@param value string Value to prepend
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
function Option:prepend(value) end -- luacheck: no unused
---Remove a value from string-style options. See |:set-=|
---
---These are equivalent: <pre>lua
--- vim.opt.wildignore:remove('*.pyc')
--- vim.opt.wildignore = vim.opt.wildignore - '*.pyc'
---</pre>
---@param value string Value to remove
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
function Option:remove(value) end -- luacheck: no unused
vim.opt = create_option_accessor()
vim.opt_local = create_option_accessor('local')
vim.opt_global = create_option_accessor('global')

View File

@@ -1,3 +1,36 @@
---@defgroup vim.highlight
---
---@brief
---Nvim includes a function for highlighting a selection on yank.
---
---To enable it, add the following to your `init.vim`:
---<pre>vim
--- au TextYankPost * silent! lua vim.highlight.on_yank()
---</pre>
---
---You can customize the highlight group and the duration of
---the highlight via:
---<pre>vim
--- au TextYankPost * silent! lua vim.highlight.on_yank {higroup="IncSearch", timeout=150}
---</pre>
---
---If you want to exclude visual selections from highlighting on yank, use:
---<pre>vim
--- au TextYankPost * silent! lua vim.highlight.on_yank {on_visual=false}
---</pre>
---
--- <pre>help
---vim.highlight.priorities *vim.highlight.priorities*
---
--- Table with default priorities used for highlighting:
--- • `syntax`: `50`, used for standard syntax highlighting
--- • `treesitter`: `100`, used for tree-sitter-based highlighting
--- • `semantic_tokens`: `125`, used for LSP semantic token highlighting
--- • `diagnostics`: `150`, used for code analysis such as diagnostics
--- • `user`: `200`, used for user-triggered highlights such as LSP document
--- symbols or `on_yank` autocommands
---</pre>
local api = vim.api local api = vim.api
local M = {} local M = {}
@@ -10,7 +43,7 @@ M.priorities = {
user = 200, user = 200,
} }
--- Highlight range between two positions --- Apply highlight group to range of text.
--- ---
---@param bufnr integer Buffer number to apply highlighting to ---@param bufnr integer Buffer number to apply highlighting to
---@param ns integer Namespace to add highlight to ---@param ns integer Namespace to add highlight to
@@ -18,9 +51,9 @@ M.priorities = {
---@param start integer[]|string Start of region as a (line, column) tuple or string accepted by |getpos()| ---@param start integer[]|string Start of region as a (line, column) tuple or string accepted by |getpos()|
---@param finish integer[]|string End of region as a (line, column) tuple or string accepted by |getpos()| ---@param finish integer[]|string End of region as a (line, column) tuple or string accepted by |getpos()|
---@param opts table|nil Optional parameters ---@param opts table|nil Optional parameters
-- - regtype type of range (see |setreg()|, default charwise) --- - regtype type of range (see |setreg()|, default charwise)
-- - inclusive boolean indicating whether the range is end-inclusive (default false) --- - inclusive boolean indicating whether the range is end-inclusive (default false)
-- - priority number indicating priority of highlight (default priorities.user) --- - priority number indicating priority of highlight (default priorities.user)
function M.range(bufnr, ns, higroup, start, finish, opts) function M.range(bufnr, ns, higroup, start, finish, opts)
opts = opts or {} opts = opts or {}
local regtype = opts.regtype or 'v' local regtype = opts.regtype or 'v'
@@ -46,22 +79,16 @@ end
local yank_ns = api.nvim_create_namespace('hlyank') local yank_ns = api.nvim_create_namespace('hlyank')
local yank_timer local yank_timer
--- Highlight the yanked region
--- Highlight the yanked text
--- ---
--- use from init.vim via --- @param opts table|nil Optional parameters
--- au TextYankPost * lua vim.highlight.on_yank() --- - higroup highlight group for yanked region (default "IncSearch")
--- customize highlight group and timeout via --- - timeout time in ms before highlight is cleared (default 150)
--- au TextYankPost * lua vim.highlight.on_yank {higroup="IncSearch", timeout=150} --- - on_macro highlight when executing macro (default false)
--- customize conditions (here: do not highlight a visual selection) via --- - on_visual highlight when yanking visual selection (default true)
--- au TextYankPost * lua vim.highlight.on_yank {on_visual=false} --- - event event structure (default vim.v.event)
--- --- - priority integer priority (default |vim.highlight.priorities|`.user`)
-- @param opts table|nil Optional parameters
-- - higroup highlight group for yanked region (default "IncSearch")
-- - timeout time in ms before highlight is cleared (default 150)
-- - on_macro highlight when executing macro (default false)
-- - on_visual highlight when yanking visual selection (default true)
-- - event event structure (default vim.v.event)
-- - priority integer priority (default |vim.highlight.priorities|`.user`)
function M.on_yank(opts) function M.on_yank(opts)
vim.validate({ vim.validate({
opts = { opts = {

View File

@@ -1,6 +1,6 @@
---@defgroup lua-iter ---@defgroup vim.iter
--- ---
--- @brief The \*vim.iter\* module provides a generic interface for working with --- This module provides a generic interface for working with
--- iterables: tables, lists, iterator functions, pair()/ipair()-like iterators, --- iterables: tables, lists, iterator functions, pair()/ipair()-like iterators,
--- and \`vim.iter()\` objects. --- and \`vim.iter()\` objects.
--- ---

View File

@@ -1,4 +1,4 @@
--- @defgroup lua-version --- @defgroup vim.version
--- ---
--- @brief The \`vim.version\` module provides functions for comparing versions and ranges --- @brief The \`vim.version\` module provides functions for comparing versions and ranges
--- conforming to the https://semver.org spec. Plugins, and plugin managers, can use this to check --- conforming to the https://semver.org spec. Plugins, and plugin managers, can use this to check

View File

@@ -45,6 +45,8 @@ import logging
from pathlib import Path from pathlib import Path
from xml.dom import minidom from xml.dom import minidom
Element = minidom.Element
Document = minidom.Document
MIN_PYTHON_VERSION = (3, 6) MIN_PYTHON_VERSION = (3, 6)
MIN_DOXYGEN_VERSION = (1, 9, 0) MIN_DOXYGEN_VERSION = (1, 9, 0)
@@ -143,6 +145,14 @@ CONFIG = {
'mode': 'lua', 'mode': 'lua',
'filename': 'lua.txt', 'filename': 'lua.txt',
'section_order': [ 'section_order': [
'highlight.lua',
'regex.lua',
'diff.lua',
'mpack.lua',
'json.lua',
'spell.lua',
'builtin.lua',
'_options.lua',
'_editor.lua', '_editor.lua',
'_inspector.lua', '_inspector.lua',
'shared.lua', 'shared.lua',
@@ -159,6 +169,7 @@ CONFIG = {
'files': [ 'files': [
'runtime/lua/vim/iter.lua', 'runtime/lua/vim/iter.lua',
'runtime/lua/vim/_editor.lua', 'runtime/lua/vim/_editor.lua',
'runtime/lua/vim/_options.lua',
'runtime/lua/vim/shared.lua', 'runtime/lua/vim/shared.lua',
'runtime/lua/vim/loader.lua', 'runtime/lua/vim/loader.lua',
'runtime/lua/vim/uri.lua', 'runtime/lua/vim/uri.lua',
@@ -166,30 +177,48 @@ CONFIG = {
'runtime/lua/vim/filetype.lua', 'runtime/lua/vim/filetype.lua',
'runtime/lua/vim/keymap.lua', 'runtime/lua/vim/keymap.lua',
'runtime/lua/vim/fs.lua', 'runtime/lua/vim/fs.lua',
'runtime/lua/vim/highlight.lua',
'runtime/lua/vim/secure.lua', 'runtime/lua/vim/secure.lua',
'runtime/lua/vim/version.lua', 'runtime/lua/vim/version.lua',
'runtime/lua/vim/_inspector.lua', 'runtime/lua/vim/_inspector.lua',
'runtime/lua/vim/_meta/builtin.lua',
'runtime/lua/vim/_meta/diff.lua',
'runtime/lua/vim/_meta/mpack.lua',
'runtime/lua/vim/_meta/json.lua',
'runtime/lua/vim/_meta/regex.lua',
'runtime/lua/vim/_meta/spell.lua',
], ],
'file_patterns': '*.lua', 'file_patterns': '*.lua',
'fn_name_prefix': '', 'fn_name_prefix': '',
'fn_name_fmt': lambda fstem, name: (
name if fstem in [ 'vim.iter' ] else
f'vim.{name}' if fstem in [ '_editor', 'vim.regex'] else
f'{fstem}.{name}' if fstem.startswith('vim') else
name
),
'section_name': { 'section_name': {
'lsp.lua': 'core', 'lsp.lua': 'core',
'_inspector.lua': 'inspector', '_inspector.lua': 'inspector',
}, },
'section_fmt': lambda name: ( 'section_fmt': lambda name: (
'Lua module: vim' 'Lua module: vim' if name.lower() == '_editor' else
if name.lower() == '_editor' 'LUA-VIMSCRIPT BRIDGE' if name.lower() == '_options' else
else f'Lua module: {name.lower()}'), f'VIM.{name.upper()}' if name.lower() in [ 'highlight', 'mpack', 'json', 'diff', 'spell', 'regex' ] else
'VIM' if name.lower() == 'builtin' else
f'Lua module: vim.{name.lower()}'),
'helptag_fmt': lambda name: ( 'helptag_fmt': lambda name: (
'*lua-vim*' '*lua-vim*' if name.lower() == '_editor' else
if name.lower() == '_editor' '*lua-vimscript*' if name.lower() == '_options' else
else f'*lua-{name.lower()}*'), f'*vim.{name.lower()}*'),
'fn_helptag_fmt': lambda fstem, name: ( 'fn_helptag_fmt': lambda fstem, name: (
f'*vim.{name}()*' f'*vim.opt:{name.split(":")[-1]}()*' if ':' in name and name.startswith('Option') else
if fstem.lower() == '_editor' # Exclude fstem for methods
else f'*{name}()*' f'*{name}()*' if ':' in name else
if name[0].isupper() f'*vim.{name}()*' if fstem.lower() == '_editor' else
else f'*{fstem}.{name}()*'), # Prevents vim.regex.regex
f'*{fstem}()*' if fstem.endswith('.' + name) else
f'*{fstem}.{name}()*'
),
'module_override': { 'module_override': {
# `shared` functions are exposed on the `vim` module. # `shared` functions are exposed on the `vim` module.
'shared': 'vim', 'shared': 'vim',
@@ -200,9 +229,16 @@ CONFIG = {
'filetype': 'vim.filetype', 'filetype': 'vim.filetype',
'keymap': 'vim.keymap', 'keymap': 'vim.keymap',
'fs': 'vim.fs', 'fs': 'vim.fs',
'highlight': 'vim.highlight',
'secure': 'vim.secure', 'secure': 'vim.secure',
'version': 'vim.version', 'version': 'vim.version',
'iter': 'vim.iter', 'iter': 'vim.iter',
'diff': 'vim',
'builtin': 'vim',
'mpack': 'vim.mpack',
'json': 'vim.json',
'regex': 'vim.regex',
'spell': 'vim.spell',
}, },
'append_only': [ 'append_only': [
'shared.lua', 'shared.lua',
@@ -541,6 +577,8 @@ def render_node(n, text, prefix='', indent='', width=text_width - indentation,
text += '>lua{}{}\n<'.format(ensure_nl, o[3:-1]) text += '>lua{}{}\n<'.format(ensure_nl, o[3:-1])
elif o[0:4] == 'vim\n': elif o[0:4] == 'vim\n':
text += '>vim{}{}\n<'.format(ensure_nl, o[3:-1]) text += '>vim{}{}\n<'.format(ensure_nl, o[3:-1])
elif o[0:5] == 'help\n':
text += o[4:-1]
else: else:
text += '>{}{}\n<'.format(ensure_nl, o) text += '>{}{}\n<'.format(ensure_nl, o)
@@ -720,8 +758,7 @@ def para_as_map(parent, indent='', width=text_width - indentation, fmt_vimhelp=F
return chunks, xrefs return chunks, xrefs
def fmt_node_as_vimhelp(parent: Element, width=text_width - indentation, indent='',
def fmt_node_as_vimhelp(parent, width=text_width - indentation, indent='',
fmt_vimhelp=False): fmt_vimhelp=False):
"""Renders (nested) Doxygen <para> nodes as Vim :help text. """Renders (nested) Doxygen <para> nodes as Vim :help text.
@@ -734,6 +771,8 @@ def fmt_node_as_vimhelp(parent, width=text_width - indentation, indent='',
max_name_len = max_name(m.keys()) + 4 max_name_len = max_name(m.keys()) + 4
out = '' out = ''
for name, desc in m.items(): for name, desc in m.items():
if name == 'self':
continue
name = '{}'.format('{{{}}}'.format(name).ljust(max_name_len)) name = '{}'.format('{{{}}}'.format(name).ljust(max_name_len))
out += '{}{}\n'.format(name, desc) out += '{}{}\n'.format(name, desc)
return out.rstrip() return out.rstrip()
@@ -851,6 +890,7 @@ def extract_from_xml(filename, target, width, fmt_vimhelp):
and any(x[1] == 'self' for x in params): and any(x[1] == 'self' for x in params):
split_return = return_type.split(' ') split_return = return_type.split(' ')
name = f'{split_return[1]}:{name}' name = f'{split_return[1]}:{name}'
params = [x for x in params if x[1] != 'self']
c_args = [] c_args = []
for param_type, param_name in params: for param_type, param_name in params:
@@ -866,6 +906,9 @@ def extract_from_xml(filename, target, width, fmt_vimhelp):
fstem = CONFIG[target]['module_override'].get(fstem, fstem) fstem = CONFIG[target]['module_override'].get(fstem, fstem)
vimtag = CONFIG[target]['fn_helptag_fmt'](fstem, name) vimtag = CONFIG[target]['fn_helptag_fmt'](fstem, name)
if 'fn_name_fmt' in CONFIG[target]:
name = CONFIG[target]['fn_name_fmt'](fstem, name)
prefix = '%s(' % name prefix = '%s(' % name
suffix = '%s)' % ', '.join('{%s}' % a[1] for a in params suffix = '%s)' % ', '.join('{%s}' % a[1] for a in params
if a[0] not in ('void', 'Error', 'Arena', if a[0] not in ('void', 'Error', 'Arena',
@@ -1047,6 +1090,42 @@ def delete_lines_below(filename, tokenstr):
fp.writelines(lines[0:i]) fp.writelines(lines[0:i])
def extract_defgroups(base: str, dom: Document):
'''Generate module-level (section) docs (@defgroup).'''
section_docs = {}
for compound in dom.getElementsByTagName('compound'):
if compound.getAttribute('kind') != 'group':
continue
# Doxygen "@defgroup" directive.
groupname = get_text(find_first(compound, 'name'))
groupxml = os.path.join(base, '%s.xml' %
compound.getAttribute('refid'))
group_parsed = minidom.parse(groupxml)
doc_list = []
brief_desc = find_first(group_parsed, 'briefdescription')
if brief_desc:
for child in brief_desc.childNodes:
doc_list.append(fmt_node_as_vimhelp(child))
desc = find_first(group_parsed, 'detaileddescription')
if desc:
doc = fmt_node_as_vimhelp(desc)
if doc:
doc_list.append(doc)
# Can't use '.' in @defgroup, so convert to '--'
# "vim.json" => "vim-dot-json"
groupname = groupname.replace('-dot-', '.')
section_docs[groupname] = "\n".join(doc_list)
return section_docs
def main(doxygen_config, args): def main(doxygen_config, args):
"""Generates: """Generates:
@@ -1088,37 +1167,12 @@ def main(doxygen_config, args):
fn_map_full = {} # Collects all functions as each module is processed. fn_map_full = {} # Collects all functions as each module is processed.
sections = {} sections = {}
section_docs = {}
sep = '=' * text_width sep = '=' * text_width
base = os.path.join(output_dir, 'xml') base = os.path.join(output_dir, 'xml')
dom = minidom.parse(os.path.join(base, 'index.xml')) dom = minidom.parse(os.path.join(base, 'index.xml'))
# Generate module-level (section) docs (@defgroup). section_docs = extract_defgroups(base, dom)
for compound in dom.getElementsByTagName('compound'):
if compound.getAttribute('kind') != 'group':
continue
# Doxygen "@defgroup" directive.
groupname = get_text(find_first(compound, 'name'))
groupxml = os.path.join(base, '%s.xml' %
compound.getAttribute('refid'))
group_parsed = minidom.parse(groupxml)
doc_list = []
brief_desc = find_first(group_parsed, 'briefdescription')
if brief_desc:
for child in brief_desc.childNodes:
doc_list.append(fmt_node_as_vimhelp(child))
desc = find_first(group_parsed, 'detaileddescription')
if desc:
doc = fmt_node_as_vimhelp(desc)
if doc:
doc_list.append(doc)
section_docs[groupname] = "\n".join(doc_list)
# Generate docs for all functions in the current module. # Generate docs for all functions in the current module.
for compound in dom.getElementsByTagName('compound'): for compound in dom.getElementsByTagName('compound'):

View File

@@ -328,6 +328,7 @@ function TLua2DoX_filter.filter(this, AppStamp, Filename)
line = string_trim(inStream:getLine()) line = string_trim(inStream:getLine())
l = l + 1 l = l + 1
if string.sub(line, 1, 2) == '--' then -- it's a comment if string.sub(line, 1, 2) == '--' then -- it's a comment
line = line:gsub('^---%s+@', '---@')
-- Allow people to write style similar to EmmyLua (since they are basically the same) -- Allow people to write style similar to EmmyLua (since they are basically the same)
-- instead of silently skipping things that start with --- -- instead of silently skipping things that start with ---
if string.sub(line, 3, 3) == '@' then -- it's a magic comment if string.sub(line, 3, 3) == '@' then -- it's a magic comment
@@ -341,6 +342,7 @@ function TLua2DoX_filter.filter(this, AppStamp, Filename)
if vim.startswith(line, '---@cast') if vim.startswith(line, '---@cast')
or vim.startswith(line, '---@diagnostic') or vim.startswith(line, '---@diagnostic')
or vim.startswith(line, '---@overload') or vim.startswith(line, '---@overload')
or vim.startswith(line, '---@meta')
or vim.startswith(line, '---@type') then or vim.startswith(line, '---@type') then
-- Ignore LSP directives -- Ignore LSP directives
outStream:writeln('// gg:"' .. line .. '"') outStream:writeln('// gg:"' .. line .. '"')
@@ -361,6 +363,8 @@ function TLua2DoX_filter.filter(this, AppStamp, Filename)
magic = magic:gsub('^return%s+.*%((' .. type .. ')%)', 'return %1') magic = magic:gsub('^return%s+.*%((' .. type .. ')%)', 'return %1')
magic = magic:gsub('^return%s+.*%((' .. type .. '|nil)%)', 'return %1') magic = magic:gsub('^return%s+.*%((' .. type .. '|nil)%)', 'return %1')
end end
-- handle the return of vim.spell.check
magic = magic:gsub('({.*}%[%])', '`%1`')
magic_split = string_split(magic, ' ') magic_split = string_split(magic, ' ')
end end
@@ -414,6 +418,11 @@ function TLua2DoX_filter.filter(this, AppStamp, Filename)
magic = table.concat(magic_split, ' ') magic = table.concat(magic_split, ' ')
if magic_split[1] == 'defgroup' or magic_split[1] == 'addtogroup' then
-- Can't use '.' in defgroup, so convert to '--'
magic = magic:gsub('%.', '-dot-')
end
outStream:writeln('/// @' .. magic) outStream:writeln('/// @' .. magic)
fn_magic = checkComment4fn(fn_magic, magic) fn_magic = checkComment4fn(fn_magic, magic)
end end

View File

@@ -287,7 +287,7 @@ set(LUA_LOADER_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/loader.lua)
set(LUA_INSPECT_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/inspect.lua) set(LUA_INSPECT_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/inspect.lua)
set(LUA_FS_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/fs.lua) set(LUA_FS_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/fs.lua)
set(LUA_F_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/F.lua) set(LUA_F_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/F.lua)
set(LUA_META_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/_meta.lua) set(LUA_OPTIONS_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/_options.lua)
set(LUA_FILETYPE_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/filetype.lua) set(LUA_FILETYPE_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/filetype.lua)
set(LUA_INIT_PACKAGES_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/_init_packages.lua) set(LUA_INIT_PACKAGES_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/_init_packages.lua)
set(LUA_KEYMAP_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/keymap.lua) set(LUA_KEYMAP_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/keymap.lua)
@@ -538,7 +538,7 @@ add_custom_command(
${LUA_INSPECT_MODULE_SOURCE} "vim.inspect" ${LUA_INSPECT_MODULE_SOURCE} "vim.inspect"
${LUA_KEYMAP_MODULE_SOURCE} "vim.keymap" ${LUA_KEYMAP_MODULE_SOURCE} "vim.keymap"
${LUA_LOADER_MODULE_SOURCE} "vim.loader" ${LUA_LOADER_MODULE_SOURCE} "vim.loader"
${LUA_META_MODULE_SOURCE} "vim._meta" ${LUA_OPTIONS_MODULE_SOURCE} "vim._options"
${LUA_SHARED_MODULE_SOURCE} "vim.shared" ${LUA_SHARED_MODULE_SOURCE} "vim.shared"
DEPENDS DEPENDS
${CHAR_BLOB_GENERATOR} ${CHAR_BLOB_GENERATOR}
@@ -550,7 +550,7 @@ add_custom_command(
${LUA_INSPECT_MODULE_SOURCE} ${LUA_INSPECT_MODULE_SOURCE}
${LUA_KEYMAP_MODULE_SOURCE} ${LUA_KEYMAP_MODULE_SOURCE}
${LUA_LOADER_MODULE_SOURCE} ${LUA_LOADER_MODULE_SOURCE}
${LUA_META_MODULE_SOURCE} ${LUA_OPTIONS_MODULE_SOURCE}
${LUA_SHARED_MODULE_SOURCE} ${LUA_SHARED_MODULE_SOURCE}
VERBATIM VERBATIM
) )

View File

@@ -2036,9 +2036,9 @@ void nlua_set_sctx(sctx_T *current)
lua_Debug *info = (lua_Debug *)xmalloc(sizeof(lua_Debug)); lua_Debug *info = (lua_Debug *)xmalloc(sizeof(lua_Debug));
// Files where internal wrappers are defined so we can ignore them // Files where internal wrappers are defined so we can ignore them
// like vim.o/opt etc are defined in _meta.lua // like vim.o/opt etc are defined in _options.lua
char *ignorelist[] = { char *ignorelist[] = {
"vim/_meta.lua", "vim/_options.lua",
"vim/keymap.lua", "vim/keymap.lua",
}; };
int ignorelist_size = sizeof(ignorelist) / sizeof(ignorelist[0]); int ignorelist_size = sizeof(ignorelist) / sizeof(ignorelist[0]);