feat(docs): replace lua2dox.lua

Problem:

The documentation flow (`gen_vimdoc.py`) has several issues:
- it's not very versatile
- depends on doxygen
- doesn't work well with Lua code as it requires an awkward filter script to convert it into pseudo-C.
- The intermediate XML files and filters makes it too much like a rube goldberg machine.

Solution:

Re-implement the flow using Lua, LPEG and treesitter.

- `gen_vimdoc.py` is now replaced with `gen_vimdoc.lua` and replicates a portion of the logic.
- `lua2dox.lua` is gone!
- No more XML files.
- Doxygen is now longer used and instead we now use:
  - LPEG for comment parsing (see `scripts/luacats_grammar.lua` and `scripts/cdoc_grammar.lua`).
  - LPEG for C parsing (see `scripts/cdoc_parser.lua`)
  - Lua patterns for Lua parsing (see `scripts/luacats_parser.lua`).
  - Treesitter for Markdown parsing (see `scripts/text_utils.lua`).
- The generated `runtime/doc/*.mpack` files have been removed.
   - `scripts/gen_eval_files.lua` now instead uses `scripts/cdoc_parser.lua` directly.
- Text wrapping is implemented in `scripts/text_utils.lua` and appears to produce more consistent results (the main contributer to the diff of this change).
This commit is contained in:
Lewis Russell 2024-02-15 17:16:04 +00:00 committed by Lewis Russell
parent 7ad2e3c645
commit 9beb40a4db
71 changed files with 3701 additions and 3849 deletions

View File

@ -20,10 +20,6 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- name: Install dependencies
run: |
sudo apt-get install -y doxygen python3-msgpack
- name: Generate docs
run: |
make doc

View File

@ -272,11 +272,16 @@ make lintdoc
```
If you need to modify or debug the documentation flow, these are the main files:
- `./scripts/gen_vimdoc.py`:
Main doc generator. Drives doxygen to generate xml files, and scrapes those
xml files to render vimdoc files.
- `./scripts/lua2dox.lua`:
Used by `gen_vimdoc.py` to transform Lua files into a format compatible with doxygen.
- `./scripts/gen_vimdoc.lua`:
Main doc generator. Parses C and Lua files to render vimdoc files.
- `./scripts/luacats_parser.lua`:
Documentation parser for Lua files.
- `./scripts/cdoc_parser.lua`:
Documentation parser for C files.
- `./scripts/luacats_grammar.lua`:
Lpeg grammar for LuaCATS
- `./scripts/cdoc_grammar.lua`:
Lpeg grammar for C doc comments
- `./scripts/gen_eval_files.lua`:
Generates documentation and Lua type files from metadata files:
```

View File

@ -140,7 +140,6 @@
include-what-you-use # for scripts/check-includes.py
jq # jq for scripts/vim-patch.sh -r
shellcheck # for `make shlint`
doxygen # for script/gen_vimdoc.py
];
nativeBuildInputs = with pkgs;

View File

@ -55,9 +55,3 @@
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED=OFF
# .DEFAULT_GOAL := nvim
#
# Run doxygen over the source code.
# Output will be in build/doxygen
#
# doxygen:
# doxygen src/Doxyfile

View File

@ -579,7 +579,7 @@ created for extmark changes.
==============================================================================
Global Functions *api-global*
nvim__get_runtime({pat}, {all}, {*opts}) *nvim__get_runtime()*
nvim__get_runtime({pat}, {all}, {opts}) *nvim__get_runtime()*
Find files in runtime directories
Attributes: ~
@ -700,7 +700,7 @@ nvim_chan_send({chan}, {data}) *nvim_chan_send()*
• {chan} id of the channel
• {data} data to write. 8-bit clean: can contain NUL bytes.
nvim_complete_set({index}, {*opts}) *nvim_complete_set()*
nvim_complete_set({index}, {opts}) *nvim_complete_set()*
Set info for the completion candidate index. if the info was shown in a
window, then the window and buffer ids are returned for further
customization. If the text was not shown, an empty dict is returned.
@ -766,7 +766,7 @@ nvim_del_var({name}) *nvim_del_var()*
Parameters: ~
• {name} Variable name
nvim_echo({chunks}, {history}, {*opts}) *nvim_echo()*
nvim_echo({chunks}, {history}, {opts}) *nvim_echo()*
Echo a message.
Parameters: ~
@ -797,7 +797,7 @@ nvim_err_writeln({str}) *nvim_err_writeln()*
See also: ~
• nvim_err_write()
nvim_eval_statusline({str}, {*opts}) *nvim_eval_statusline()*
nvim_eval_statusline({str}, {opts}) *nvim_eval_statusline()*
Evaluates statusline string.
Attributes: ~
@ -878,13 +878,13 @@ nvim_get_api_info() *nvim_get_api_info()*
Returns a 2-tuple (Array), where item 0 is the current channel id and item
1 is the |api-metadata| map (Dictionary).
Return: ~
2-tuple [{channel-id}, {api-metadata}]
Attributes: ~
|api-fast|
|RPC| only
Return: ~
2-tuple [{channel-id}, {api-metadata}]
nvim_get_chan_info({chan}) *nvim_get_chan_info()*
Gets information about a channel.
@ -900,12 +900,10 @@ nvim_get_chan_info({chan}) *nvim_get_chan_info()*
• "stderr" stderr of this Nvim instance
• "socket" TCP/IP socket or named pipe
• "job" Job with communication over its stdio.
• "mode" How data received on the channel is interpreted.
• "bytes" Send and receive raw bytes.
• "terminal" |terminal| instance interprets ASCII sequences.
• "rpc" |RPC| communication on the channel is active.
• "pty" (optional) Name of pseudoterminal. On a POSIX system this is a
device path like "/dev/pts/1". If the name is unknown, the key will
still be present if a pty is used (e.g. for conpty on Windows).
@ -937,7 +935,7 @@ nvim_get_color_map() *nvim_get_color_map()*
Return: ~
Map of color names and RGB values.
nvim_get_context({*opts}) *nvim_get_context()*
nvim_get_context({opts}) *nvim_get_context()*
Gets a map of the current editor state.
Parameters: ~
@ -972,7 +970,7 @@ nvim_get_current_win() *nvim_get_current_win()*
Return: ~
Window handle
nvim_get_hl({ns_id}, {*opts}) *nvim_get_hl()*
nvim_get_hl({ns_id}, {opts}) *nvim_get_hl()*
Gets all or specific highlight groups in a namespace.
Note: ~
@ -1001,7 +999,7 @@ nvim_get_hl_id_by_name({name}) *nvim_get_hl_id_by_name()*
similar to |hlID()|, but allocates a new ID if not present.
nvim_get_hl_ns({*opts}) *nvim_get_hl_ns()*
nvim_get_hl_ns({opts}) *nvim_get_hl_ns()*
Gets the active highlight namespace.
Parameters: ~
@ -1024,7 +1022,7 @@ nvim_get_keymap({mode}) *nvim_get_keymap()*
Array of |maparg()|-like dictionaries describing mappings. The
"buffer" key is always zero.
nvim_get_mark({name}, {*opts}) *nvim_get_mark()*
nvim_get_mark({name}, {opts}) *nvim_get_mark()*
Returns a `(row, col, buffer, buffername)` tuple representing the position
of the uppercase/file named mark. "End of line" column position is
returned as |v:maxcol| (big number). See |mark-motions|.
@ -1050,12 +1048,12 @@ nvim_get_mode() *nvim_get_mode()*
Gets the current mode. |mode()| "blocking" is true if Nvim is waiting for
input.
Return: ~
Dictionary { "mode": String, "blocking": Boolean }
Attributes: ~
|api-fast|
Return: ~
Dictionary { "mode": String, "blocking": Boolean }
nvim_get_proc({pid}) *nvim_get_proc()*
Gets info describing process `pid`.
@ -1222,7 +1220,7 @@ nvim_notify({msg}, {log_level}, {opts}) *nvim_notify()*
• {log_level} The log level
• {opts} Reserved for future use.
nvim_open_term({buffer}, {*opts}) *nvim_open_term()*
nvim_open_term({buffer}, {opts}) *nvim_open_term()*
Open a terminal instance in a buffer
By default (and currently the only option) the terminal will not be
@ -1280,14 +1278,13 @@ nvim_paste({data}, {crlf}, {phase}) *nvim_paste()*
• {data} Multiline input. May be binary (containing NUL bytes).
• {crlf} Also break lines at CR and CRLF.
• {phase} -1: paste in a single call (i.e. without streaming). To
"stream" a paste, call `nvim_paste` sequentially
with these `phase` values:
"stream" a paste, call `nvim_paste` sequentially with these
`phase` values:
• 1: starts the paste (exactly once)
• 2: continues the paste (zero or more times)
• 3: ends the paste (exactly once)
Return: ~
• true: Client may continue pasting.
• false: Client must cancel the paste.
@ -1326,7 +1323,7 @@ nvim_replace_termcodes({str}, {from_part}, {do_lt}, {special})
• cpoptions
*nvim_select_popupmenu_item()*
nvim_select_popupmenu_item({item}, {insert}, {finish}, {*opts})
nvim_select_popupmenu_item({item}, {insert}, {finish}, {opts})
Selects an item in the completion popup menu.
If neither |ins-completion| nor |cmdline-completion| popup menu is active
@ -1450,20 +1447,20 @@ nvim_set_current_win({window}) *nvim_set_current_win()*
Parameters: ~
• {window} Window handle
nvim_set_hl({ns_id}, {name}, {*val}) *nvim_set_hl()*
nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()*
Sets a highlight group.
Note: ~
• Unlike the `:highlight` command which can update a highlight group, this
function completely replaces the definition. For example:
• Unlike the `:highlight` command which can update a highlight group,
this function completely replaces the definition. For example:
`nvim_set_hl(0, 'Visual', {})` will clear the highlight group
'Visual'.
• The fg and bg keys also accept the string values `"fg"` or `"bg"` which
act as aliases to the corresponding foreground and background values
of the Normal group. If the Normal group has not been defined, using
these values results in an error.
• If `link` is used in combination with other attributes; only the `link`
will take effect (see |:hi-link|).
• The fg and bg keys also accept the string values `"fg"` or `"bg"`
which act as aliases to the corresponding foreground and background
values of the Normal group. If the Normal group has not been defined,
using these values results in an error.
• If `link` is used in combination with other attributes; only the
`link` will take effect (see |:hi-link|).
Parameters: ~
• {ns_id} Namespace id for this highlight |nvim_create_namespace()|.
@ -1520,7 +1517,7 @@ nvim_set_hl_ns_fast({ns_id}) *nvim_set_hl_ns_fast()*
Parameters: ~
• {ns_id} the namespace to activate
nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()*
nvim_set_keymap({mode}, {lhs}, {rhs}, {opts}) *nvim_set_keymap()*
Sets a global |mapping| for the given mode.
To set a buffer-local mapping, use |nvim_buf_set_keymap()|.
@ -1537,8 +1534,8 @@ nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()*
<
Parameters: ~
• {mode} Mode short-name (map command prefix: "n", "i", "v", "x", …) or
"!" for |:map!|, or empty string for |:map|. "ia", "ca" or
• {mode} Mode short-name (map command prefix: "n", "i", "v", "x", …)
or "!" for |:map!|, or empty string for |:map|. "ia", "ca" or
"!a" for abbreviation in Insert mode, Cmdline mode, or both,
respectively
• {lhs} Left-hand-side |{lhs}| of the mapping.
@ -1651,7 +1648,7 @@ nvim_eval({expr}) *nvim_eval()*
Return: ~
Evaluation result or expanded object
nvim_exec2({src}, {*opts}) *nvim_exec2()*
nvim_exec2({src}, {opts}) *nvim_exec2()*
Executes Vimscript (multiline block of Ex commands), like anonymous
|:source|.
@ -1704,18 +1701,16 @@ nvim_parse_expression({expr}, {flags}, {highlight})
region [start_col, end_col)).
Return: ~
• AST: top-level dictionary with these keys:
• "error": Dictionary with error, present only if parser saw some
error. Contains the following keys:
• "message": String, error message in printf format, translated.
Must contain exactly one "%.*s".
• "arg": String, error message argument.
• "len": Amount of bytes successfully parsed. With flags equal to ""
that should be equal to the length of expr string. (Successfully
parsed” here means “participated in AST creation”, not “till the
first error.)
that should be equal to the length of expr string. ("Successfully
parsed" here means "participated in AST creation", not "till the
first error".)
• "ast": AST, either nil or a dictionary with these keys:
• "type": node type, one of the value names from ExprASTNodeType
stringified without "kExprNode" prefix.
@ -1730,7 +1725,6 @@ nvim_parse_expression({expr}, {flags}, {highlight})
is zero, one or two children, key will not be present if node
has no children. Maximum number of children may be found in
node_maxchildren array.
• Local values (present only for certain nodes):
• "scope": a single Integer, specifies scope for "Option" and
"PlainIdentifier" nodes. For "Option" it is one of ExprOptScope
@ -1760,11 +1754,11 @@ nvim_parse_expression({expr}, {flags}, {highlight})
Command Functions *api-command*
*nvim_buf_create_user_command()*
nvim_buf_create_user_command({buffer}, {name}, {command}, {*opts})
nvim_buf_create_user_command({buffer}, {name}, {command}, {opts})
Creates a buffer-local command |user-commands|.
Parameters: ~
• {buffer} Buffer handle, or 0 for current buffer.
• {buffer} Buffer handle, or 0 for current buffer.
See also: ~
• nvim_create_user_command
@ -1780,7 +1774,7 @@ nvim_buf_del_user_command({buffer}, {name})
• {buffer} Buffer handle, or 0 for current buffer.
• {name} Name of the command to delete.
nvim_buf_get_commands({buffer}, {*opts}) *nvim_buf_get_commands()*
nvim_buf_get_commands({buffer}, {opts}) *nvim_buf_get_commands()*
Gets a map of buffer-local |user-commands|.
Parameters: ~
@ -1790,7 +1784,7 @@ nvim_buf_get_commands({buffer}, {*opts}) *nvim_buf_get_commands()*
Return: ~
Map of maps describing commands.
nvim_cmd({*cmd}, {*opts}) *nvim_cmd()*
nvim_cmd({cmd}, {opts}) *nvim_cmd()*
Executes an Ex command.
Unlike |nvim_command()| this command takes a structured Dictionary instead
@ -1825,7 +1819,7 @@ nvim_cmd({*cmd}, {*opts}) *nvim_cmd()*
• |nvim_command()|
*nvim_create_user_command()*
nvim_create_user_command({name}, {command}, {*opts})
nvim_create_user_command({name}, {command}, {opts})
Creates a global |user-commands| command.
For Lua usage see |lua-guide-commands-create|.
@ -1885,7 +1879,7 @@ nvim_del_user_command({name}) *nvim_del_user_command()*
Parameters: ~
• {name} Name of the command to delete.
nvim_get_commands({*opts}) *nvim_get_commands()*
nvim_get_commands({opts}) *nvim_get_commands()*
Gets a map of global (non-buffer-local) Ex commands.
Currently only |user-commands| are supported, not builtin Ex commands.
@ -1899,7 +1893,7 @@ nvim_get_commands({*opts}) *nvim_get_commands()*
See also: ~
• |nvim_get_all_options_info()|
nvim_parse_cmd({str}, {*opts}) *nvim_parse_cmd()*
nvim_parse_cmd({str}, {opts}) *nvim_parse_cmd()*
Parse command line.
Doesn't check the validity of command arguments.
@ -1937,13 +1931,11 @@ nvim_parse_cmd({str}, {*opts}) *nvim_parse_cmd()*
• bar: (boolean) The "|" character is treated as a command separator
and the double quote character (") is treated as the start of a
comment.
• mods: (dictionary) |:command-modifiers|.
• filter: (dictionary) |:filter|.
• pattern: (string) Filter pattern. Empty string if there is no
filter.
• force: (boolean) Whether filter is inverted or not.
• silent: (boolean) |:silent|.
• emsg_silent: (boolean) |:silent!|.
• unsilent: (boolean) |:unsilent|.
@ -1986,7 +1978,7 @@ nvim_get_all_options_info() *nvim_get_all_options_info()*
See also: ~
• |nvim_get_commands()|
nvim_get_option_info2({name}, {*opts}) *nvim_get_option_info2()*
nvim_get_option_info2({name}, {opts}) *nvim_get_option_info2()*
Gets the option information for one option from arbitrary buffer or window
Resulting dictionary has keys:
@ -2020,7 +2012,7 @@ nvim_get_option_info2({name}, {*opts}) *nvim_get_option_info2()*
Return: ~
Option Information
nvim_get_option_value({name}, {*opts}) *nvim_get_option_value()*
nvim_get_option_value({name}, {opts}) *nvim_get_option_value()*
Gets the value of an option. The behavior of this function matches that of
|:set|: the local value of an option is returned if it exists; otherwise,
the global value is returned. Local values always correspond to the
@ -2043,7 +2035,7 @@ nvim_get_option_value({name}, {*opts}) *nvim_get_option_value()*
Option value
*nvim_set_option_value()*
nvim_set_option_value({name}, {value}, {*opts})
nvim_set_option_value({name}, {value}, {opts})
Sets the value of an option. The behavior of this function matches that of
|:set|: for global-local options, both the global and local value are set
unless otherwise specified with {scope}.
@ -2069,16 +2061,16 @@ For more information on buffers, see |buffers|.
Unloaded Buffers: ~
Buffers may be unloaded by the |:bunload| command or the buffer's
|'bufhidden'| option. When a buffer is unloaded its file contents are
freed from memory and vim cannot operate on the buffer lines until it is
reloaded (usually by opening the buffer again in a new window). API
methods such as |nvim_buf_get_lines()| and |nvim_buf_line_count()| will be
affected.
|'bufhidden'| option. When a buffer is unloaded its file contents are freed
from memory and vim cannot operate on the buffer lines until it is reloaded
(usually by opening the buffer again in a new window). API methods such as
|nvim_buf_get_lines()| and |nvim_buf_line_count()| will be affected.
You can use |nvim_buf_is_loaded()| or |nvim_buf_line_count()| to check
whether a buffer is loaded.
nvim_buf_attach({buffer}, {send_buffer}, {*opts}) *nvim_buf_attach()*
nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
Activates buffer-update events on a channel, or as Lua callbacks.
Example (Lua): capture buffer updates in a global `events` variable (use
@ -2100,8 +2092,7 @@ nvim_buf_attach({buffer}, {send_buffer}, {*opts}) *nvim_buf_attach()*
callbacks.
• {opts} Optional parameters.
• on_lines: Lua callback invoked on change. Return a
truthy value (not `false` or `nil`)
to detach. Args:
truthy value (not `false` or `nil`) to detach. Args:
• the string "lines"
• buffer handle
• b:changedtick
@ -2111,12 +2102,10 @@ nvim_buf_attach({buffer}, {send_buffer}, {*opts}) *nvim_buf_attach()*
• byte count of previous contents
• deleted_codepoints (if `utf_sizes` is true)
• deleted_codeunits (if `utf_sizes` is true)
• on_bytes: Lua callback invoked on change. This
callback receives more granular information about the
change compared to on_lines. Return a truthy value
(not `false` or `nil`) to
detach. Args:
(not `false` or `nil`) to detach. Args:
• the string "bytes"
• buffer handle
• b:changedtick
@ -2134,22 +2123,18 @@ nvim_buf_attach({buffer}, {send_buffer}, {*opts}) *nvim_buf_attach()*
• new end column of the changed text (if new end row
= 0, offset from start column)
• new end byte length of the changed text
• on_changedtick: Lua callback invoked on changedtick
increment without text change. Args:
• the string "changedtick"
• buffer handle
• b:changedtick
• on_detach: Lua callback invoked on detach. Args:
• the string "detach"
• buffer handle
• on_reload: Lua callback invoked on reload. The entire
buffer content should be considered changed. Args:
• the string "reload"
• buffer handle
• utf_sizes: include UTF-32 and UTF-16 size of the
replaced region, as args to `on_lines`.
• preview: also attach to command preview (i.e.
@ -2221,7 +2206,7 @@ nvim_buf_del_var({buffer}, {name}) *nvim_buf_del_var()*
• {buffer} Buffer handle, or 0 for current buffer
• {name} Variable name
nvim_buf_delete({buffer}, {*opts}) *nvim_buf_delete()*
nvim_buf_delete({buffer}, {opts}) *nvim_buf_delete()*
Deletes the buffer. See |:bwipeout|
Attributes: ~
@ -2263,8 +2248,8 @@ nvim_buf_get_keymap({buffer}, {mode}) *nvim_buf_get_keymap()*
Gets a list of buffer-local |mapping| definitions.
Parameters: ~
• {mode} Mode short-name ("n", "i", "v", ...)
• {buffer} Buffer handle, or 0 for current buffer
• {mode} Mode short-name ("n", "i", "v", ...)
Return: ~
Array of |maparg()|-like dictionaries describing mappings. The
@ -2338,7 +2323,7 @@ nvim_buf_get_offset({buffer}, {index}) *nvim_buf_get_offset()*
*nvim_buf_get_text()*
nvim_buf_get_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col},
{*opts})
{opts})
Gets a range from the buffer.
This differs from |nvim_buf_get_lines()| in that it allows retrieving only
@ -2403,7 +2388,7 @@ nvim_buf_line_count({buffer}) *nvim_buf_line_count()*
Line count, or 0 for unloaded buffer. |api-buffer|
*nvim_buf_set_keymap()*
nvim_buf_set_keymap({buffer}, {mode}, {lhs}, {rhs}, {*opts})
nvim_buf_set_keymap({buffer}, {mode}, {lhs}, {rhs}, {opts})
Sets a buffer-local |mapping| for the given mode.
Parameters: ~
@ -2440,7 +2425,7 @@ nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing}, {replacement})
• |nvim_buf_set_text()|
*nvim_buf_set_mark()*
nvim_buf_set_mark({buffer}, {name}, {line}, {col}, {*opts})
nvim_buf_set_mark({buffer}, {name}, {line}, {col}, {opts})
Sets a named mark in the given buffer, all marks are allowed
file/uppercase, visual, last change, etc. See |mark-motions|.
@ -2581,7 +2566,7 @@ nvim_buf_del_extmark({buffer}, {ns_id}, {id}) *nvim_buf_del_extmark()*
true if the extmark was found, else false
*nvim_buf_get_extmark_by_id()*
nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {*opts})
nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {opts})
Gets the position (0-indexed) of an |extmark|.
Parameters: ~
@ -2597,7 +2582,7 @@ nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {*opts})
0-indexed (row, col) tuple or empty list () if extmark id was absent
*nvim_buf_get_extmarks()*
nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {*opts})
nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
Gets |extmarks| in "traversal order" from a |charwise| region defined by
buffer positions (inclusive, 0-indexed |api-indexing|).
@ -2657,7 +2642,7 @@ nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {*opts})
List of [extmark_id, row, col] tuples in "traversal order".
*nvim_buf_set_extmark()*
nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts})
nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
Creates or updates an |extmark|.
By default a new extmark is created when no id is passed in, but it is
@ -2703,7 +2688,6 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts})
• "right_align": display right aligned in the window.
• "inline": display at the specified column, and shift the
buffer text to the right as needed.
• virt_text_win_col : position the virtual text at a fixed
window column (starting from the first text column of the
screen line) instead of "virt_text_pos".
@ -2715,14 +2699,12 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts})
wrapped lines.
• hl_mode : control how highlights are combined with the
highlights of the text. Currently only affects virt_text
highlights, but might affect `hl_group` in
later versions.
highlights, but might affect `hl_group` in later versions.
• "replace": only show the virt_text color. This is the
default.
• "combine": combine with background text color.
• "blend": blend with background text color. Not supported
for "inline" virt_text.
• virt_lines : virtual lines to add next to this mark This
should be an array over lines, where each line in turn is
an array over [text, highlight] tuples. In general, buffer
@ -2815,7 +2797,7 @@ nvim_get_namespaces() *nvim_get_namespaces()*
dict that maps from names to namespace ids.
*nvim_set_decoration_provider()*
nvim_set_decoration_provider({ns_id}, {*opts})
nvim_set_decoration_provider({ns_id}, {opts})
Set or change decoration provider for a |namespace|
This is a very general purpose interface for having Lua callbacks being
@ -3066,7 +3048,7 @@ nvim_win_set_hl_ns({window}, {ns_id}) *nvim_win_set_hl_ns()*
This takes precedence over the 'winhighlight' option.
Parameters: ~
• {ns_id} the namespace to use
• {ns_id} the namespace to use
nvim_win_set_var({window}, {name}, {value}) *nvim_win_set_var()*
Sets a window-scoped (w:) variable
@ -3084,7 +3066,7 @@ nvim_win_set_width({window}, {width}) *nvim_win_set_width()*
• {window} Window handle, or 0 for current window
• {width} Width as a count of columns
nvim_win_text_height({window}, {*opts}) *nvim_win_text_height()*
nvim_win_text_height({window}, {opts}) *nvim_win_text_height()*
Computes the number of screen lines occupied by a range of text in a given
window. Works for off-screen text and takes folds into account.
@ -3120,9 +3102,9 @@ nvim_win_text_height({window}, {*opts}) *nvim_win_text_height()*
==============================================================================
Win_Config Functions *api-win_config*
Win_config Functions *api-win_config*
nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
Opens a new split window, or a floating window if `relative` is specified,
or an external window (managed by the UI) if `external` is specified.
@ -3188,7 +3170,6 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
window.
• "cursor" Cursor position in current window.
• "mouse" Mouse position
• win: |window-ID| window to split, or relative window when
creating a float (relative="win").
• anchor: Decides which corner of the float to place at
@ -3197,17 +3178,15 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
• "NE" northeast
• "SW" southwest
• "SE" southeast
• width: Window width (in character cells). Minimum of 1.
• height: Window height (in character cells). Minimum of 1.
• bufpos: Places float relative to buffer text (only when
relative="win"). Takes a tuple of zero-indexed [line,
column]. `row` and `col` if given are
applied relative to this position, else they default to:
column]. `row` and `col` if given are applied relative to
this position, else they default to:
• `row=1` and `col=0` if `anchor` is "NW" or "NE"
• `row=0` and `col=0` if `anchor` is "SW" or "SE" (thus
like a tooltip near the buffer text).
• row: Row position in units of "screen cell height", may be
fractional.
• col: Column position in units of "screen cell width", may
@ -3228,7 +3207,6 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
wildoptions+=pum) The default value for floats are 50.
In general, values below 100 are recommended, unless
there is a good reason to overshadow builtin elements.
• style: (optional) Configure the appearance of the window.
Currently only supports one value:
• "minimal" Nvim will display the window with many UI
@ -3241,14 +3219,13 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
empty. The end-of-buffer region is hidden by setting
`eob` flag of 'fillchars' to a space char, and clearing
the |hl-EndOfBuffer| region in 'winhighlight'.
• border: Style of (optional) window border. This can either
be a string or an array. The string values are
• "none": No border (default).
• "single": A single line box.
• "double": A double line box.
• "rounded": Like "single", but with rounded corners ("╭"
etc.).
• "rounded": Like "single", but with rounded corners
("╭" etc.).
• "solid": Adds padding by a single whitespace cell.
• "shadow": A drop shadow effect by blending with the
background.
@ -3256,19 +3233,26 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
any divisor of eight. The array will specify the eight
chars building up the border in a clockwise fashion
starting with the top-left corner. As an example, the
double box style could be specified as [ "╔", "═" ,"╗",
"║", "╝", "═", "╚", "║" ]. If the number of chars are
less than eight, they will be repeated. Thus an ASCII
border could be specified as [ "/", "-", "\\", "|" ], or
all chars the same as [ "x" ]. An empty string can be
used to turn off a specific border, for instance, [ "",
"", "", ">", "", "", "", "<" ] will only make vertical
borders but not horizontal ones. By default,
`FloatBorder` highlight is used, which links to
`WinSeparator` when not defined. It could also be
specified by character: [ ["+", "MyCorner"], ["x",
"MyBorder"] ].
double box style could be specified as: >
[ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
<
If the number of chars are less than eight, they will be
repeated. Thus an ASCII border could be specified as >
[ "/", "-", \"\\\\\", "|" ],
<
or all chars the same as >
[ "x" ].
<
An empty string can be used to turn off a specific border,
for instance, >
[ "", "", "", ">", "", "", "", "<" ]
<
will only make vertical borders but not horizontal ones.
By default, `FloatBorder` highlight is used, which links
to `WinSeparator` when not defined. It could also be
specified by character: >
[ ["+", "MyCorner"], ["x", "MyBorder"] ].
<
• title: Title (optional) in window border, string or list.
List should consist of `[text, highlight]` tuples. If
string, the default highlight group is `FloatTitle`.
@ -3306,7 +3290,7 @@ nvim_win_get_config({window}) *nvim_win_get_config()*
Return: ~
Map defining the window configuration, see |nvim_open_win()|
nvim_win_set_config({window}, {*config}) *nvim_win_set_config()*
nvim_win_set_config({window}, {config}) *nvim_win_set_config()*
Configures window layout. Currently only for floating and external windows
(including changing a split window to those layouts).
@ -3397,7 +3381,7 @@ nvim_tabpage_set_win({tabpage}, {win}) *nvim_tabpage_set_win()*
==============================================================================
Autocmd Functions *api-autocmd*
nvim_clear_autocmds({*opts}) *nvim_clear_autocmds()*
nvim_clear_autocmds({opts}) *nvim_clear_autocmds()*
Clears all autocommands selected by {opts}. To delete autocmds see
|nvim_del_autocmd()|.
@ -3407,25 +3391,21 @@ nvim_clear_autocmds({*opts}) *nvim_clear_autocmds()*
• event: "pat1"
• event: { "pat1" }
• event: { "pat1", "pat2", "pat3" }
• pattern: (string|table)
• pattern or patterns to match exactly.
• For example, if you have `*.py` as that pattern for the
autocmd, you must pass `*.py` exactly to clear it.
`test.py` will not match the pattern.
• defaults to clearing all patterns.
• NOTE: Cannot be used with {buffer}
• buffer: (bufnr)
• clear only |autocmd-buflocal| autocommands.
• NOTE: Cannot be used with {pattern}
• group: (string|int) The augroup name or id.
• NOTE: If not passed, will only delete autocmds not in any
group.
nvim_create_augroup({name}, {*opts}) *nvim_create_augroup()*
nvim_create_augroup({name}, {opts}) *nvim_create_augroup()*
Create or get an autocommand group |autocmd-groups|.
To get an existing group id, do: >lua
@ -3446,9 +3426,10 @@ nvim_create_augroup({name}, {*opts}) *nvim_create_augroup()*
See also: ~
• |autocmd-groups|
nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()*
Creates an |autocommand| event handler, defined by `callback` (Lua function
or Vimscript function name string) or `command` (Ex command string).
nvim_create_autocmd({event}, {opts}) *nvim_create_autocmd()*
Creates an |autocommand| event handler, defined by `callback` (Lua
function or Vimscript function name string) or `command` (Ex command
string).
Example using Lua callback: >lua
vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
@ -3487,8 +3468,8 @@ nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()*
• callback (function|string) optional: Lua function (or
Vimscript function name, if string) called when the
event(s) is triggered. Lua callback can return a truthy
value (not `false` or `nil`) to delete the
autocommand. Receives a table argument with these keys:
value (not `false` or `nil`) to delete the autocommand.
Receives a table argument with these keys:
• id: (number) autocommand id
• event: (string) name of the triggered event
|autocmd-events|
@ -3498,7 +3479,6 @@ nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()*
• file: (string) expanded value of |<afile>|
• data: (any) arbitrary data passed from
|nvim_exec_autocmds()|
• command (string) optional: Vim command to execute on event.
Cannot be used with {callback}
• once (boolean) optional: defaults to false. Run the
@ -3548,7 +3528,7 @@ nvim_del_autocmd({id}) *nvim_del_autocmd()*
Parameters: ~
• {id} Integer Autocommand id returned by |nvim_create_autocmd()|
nvim_exec_autocmds({event}, {*opts}) *nvim_exec_autocmds()*
nvim_exec_autocmds({event}, {opts}) *nvim_exec_autocmds()*
Execute all autocommands for {event} that match the corresponding {opts}
|autocmd-execute|.
@ -3569,7 +3549,7 @@ nvim_exec_autocmds({event}, {*opts}) *nvim_exec_autocmds()*
See also: ~
• |:doautocmd|
nvim_get_autocmds({*opts}) *nvim_get_autocmds()*
nvim_get_autocmds({opts}) *nvim_get_autocmds()*
Get all autocommands that match the corresponding {opts}.
These examples will get autocommands matching ALL the given criteria: >lua
@ -3683,13 +3663,12 @@ nvim_ui_pum_set_height({height}) *nvim_ui_pum_set_height()*
• {height} Popupmenu height, must be greater than zero.
nvim_ui_set_focus({gained}) *nvim_ui_set_focus()*
Tells the nvim server if focus was gained or lost by the GUI.
Tells the nvim server if focus was gained or lost by the GUI
Attributes: ~
|RPC| only
nvim_ui_set_option({name}, {value}) *nvim_ui_set_option()*
TODO: Documentation
Attributes: ~
|RPC| only
@ -3698,7 +3677,6 @@ nvim_ui_term_event({event}, {value}) *nvim_ui_term_event()*
Tells Nvim when a terminal event has occurred
The following terminal events are supported:
• "termresponse": The terminal sent an OSC or DCS response sequence to
Nvim. The payload is the received response. Sets |v:termresponse| and
fires |TermResponse|.
@ -3707,11 +3685,10 @@ nvim_ui_term_event({event}, {value}) *nvim_ui_term_event()*
|RPC| only
Parameters: ~
• {event} Event name
• {payload} Event payload
• {event} Event name
• {value} Event payload
nvim_ui_try_resize({width}, {height}) *nvim_ui_try_resize()*
TODO: Documentation
Attributes: ~
|RPC| only
@ -3731,4 +3708,5 @@ nvim_ui_try_resize_grid({grid}, {width}, {height})
• {width} The new requested width.
• {height} The new requested height.
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@ -397,7 +397,6 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
diagnostics. Options:
• severity: Only underline diagnostics matching the
given severity |diagnostic-severity|
• virtual_text: (default true) Use virtual text for
diagnostics. If multiple diagnostics are set for a
namespace, one prefix per diagnostic + the last
@ -430,7 +429,6 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
• format: (function) A function that takes a diagnostic
as input and returns a string. The return value is
the text used to display the diagnostic. Example: >lua
function(diagnostic)
if diagnostic.severity == vim.diagnostic.severity.ERROR then
return string.format("E: %s", diagnostic.message)
@ -438,7 +436,6 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
return diagnostic.message
end
<
• signs: (default true) Use signs for diagnostics
|diagnostic-signs|. Options:
• severity: Only show signs for diagnostics matching
@ -452,7 +449,6 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
default is to use "E", "W", "I", and "H" for errors,
warnings, information, and hints, respectively.
Example: >lua
vim.diagnostic.config({
signs = { text = { [vim.diagnostic.severity.ERROR] = 'E', ... } }
})
@ -463,7 +459,6 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
• linehl: (table) A table mapping |diagnostic-severity|
to the highlight group used for the whole line the
sign is placed in.
• float: Options for floating windows. See
|vim.diagnostic.open_float()|.
• update_in_insert: (default false) Update diagnostics in
@ -542,8 +537,8 @@ get({bufnr}, {opts}) *vim.diagnostic.get()*
Return: ~
(`vim.Diagnostic[]`) table A list of diagnostic items
|diagnostic-structure|. Keys `bufnr` , `end_lnum` , `end_col` , and `severity` are
guaranteed to be present.
|diagnostic-structure|. Keys `bufnr`, `end_lnum`, `end_col`, and
`severity` are guaranteed to be present.
get_namespace({namespace}) *vim.diagnostic.get_namespace()*
Get namespace metadata.
@ -685,7 +680,7 @@ match({str}, {pat}, {groups}, {severity_map}, {defaults})
(`vim.Diagnostic?`) |diagnostic-structure| or `nil` if {pat} fails to
match {str}.
open_float({opts}, {...}) *vim.diagnostic.open_float()*
open_float({opts}) *vim.diagnostic.open_float()*
Show diagnostics in a floating window.
Parameters: ~
@ -738,8 +733,9 @@ open_float({opts}, {...}) *vim.diagnostic.open_float()*
diagnostic instead of prepending it. Overrides the setting
from |vim.diagnostic.config()|.
Return: ~
(`integer?, integer?`) ({float_bufnr}, {win_id})
Return (multiple): ~
(`integer?`) float_bufnr
(`integer?`) win_id
reset({namespace}, {bufnr}) *vim.diagnostic.reset()*
Remove all diagnostics from the given namespace.
@ -823,4 +819,5 @@ toqflist({diagnostics}) *vim.diagnostic.toqflist()*
Return: ~
(`table[]`) of quickfix list items |setqflist-what|
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@ -712,10 +712,9 @@ buf_request_sync({bufnr}, {method}, {params}, {timeout_ms})
(`string?`) err On timeout, cancel, or error, `err` is a string
describing the failure reason, and `result` is nil.
client() *vim.lsp.client*
client *vim.lsp.client*
LSP client object. You can get an active client object via
|vim.lsp.get_client_by_id()| or |vim.lsp.get_clients()|.
• Methods:
• request(method, params, [handler], bufnr) Sends a request to the
server. This is a thin wrapper around {client.rpc.request} with some
@ -750,7 +749,6 @@ client() *vim.lsp.client*
given method. Always returns true for unknown off-spec methods. [opts]
is a optional `{bufnr?: integer}` table. Some language server
capabilities can be file specific.
• Members
• {id} (number): The id allocated to the client.
• {name} (string): If a name is specified on creation, that will be
@ -916,7 +914,6 @@ start({config}, {opts}) *vim.lsp.start()*
See |vim.lsp.start_client()| for all available options. The most important
are:
• `name` arbitrary name for the LSP client. Should be unique per language
server.
• `cmd` command string[] or function, described at
@ -975,8 +972,7 @@ start_client({config}) *vim.lsp.start_client()*
• cmd_env: (table) Environment flags to pass to the LSP on
spawn. Must be specified using a table. Non-string values
are coerced to string. Example: >
{ PORT = 8080; HOST = "0.0.0.0"; }
{ PORT = 8080; HOST = "0.0.0.0"; }
<
• detached: (boolean, default true) Daemonize the server
process so that it runs in a separate process group from
@ -994,7 +990,6 @@ start_client({config}) *vim.lsp.start_client()*
make_client_capabilities() and modify its result.
• Note: To send an empty dictionary use
|vim.empty_dict()|, else it will be encoded as an array.
• handlers: Map of language server method names to
|lsp-handler|
• settings: Map with language server specific settings.
@ -1041,7 +1036,6 @@ start_client({config}) *vim.lsp.start_client()*
• signal: number describing the signal used to terminate
(if any)
• client_id: client handle
• on_attach: Callback (client, bufnr) invoked when client
attaches to a buffer.
• trace: ("off" | "messages" | "verbose" | nil) passed
@ -1059,7 +1053,6 @@ start_client({config}) *vim.lsp.start_client()*
sending the "shutdown" request before sending kill -15.
If set to false, nvim exits immediately after sending
the "shutdown" request to the server.
• root_dir: (string) Directory where the LSP server will
base its workspaceFolders, rootUri, and rootPath on
initialization.
@ -1124,6 +1117,9 @@ add_workspace_folder({workspace_folder})
Add the folder at path to the workspace folders. If {path} is not
provided, the user will be prompted for a path using |input()|.
Parameters: ~
• {workspace_folder} (`string?`)
clear_references() *vim.lsp.buf.clear_references()*
Removes document highlights from current buffer.
@ -1133,8 +1129,8 @@ code_action({options}) *vim.lsp.buf.code_action()*
Parameters: ~
• {options} (`table?`) Optional table which holds the following
optional fields:
• context: (table|nil) Corresponds to `CodeActionContext` of
the LSP specification:
• context: (table|nil) Corresponds to `CodeActionContext`
of the LSP specification:
• diagnostics (table|nil): LSP `Diagnostic[]`. Inferred
from the current position if not provided.
• only (table|nil): List of LSP `CodeActionKind`s used to
@ -1142,7 +1138,6 @@ code_action({options}) *vim.lsp.buf.code_action()*
values like `refactor` or `quickfix`.
• triggerKind (number|nil): The reason why code actions
were requested.
• filter: (function|nil) Predicate taking an `CodeAction`
and returning a boolean.
• apply: (boolean|nil) When set to `true`, and there is
@ -1235,7 +1230,8 @@ format({options}) *vim.lsp.buf.format()*
optional fields:
• formatting_options (table|nil): Can be used to specify
FormattingOptions. Some unspecified options will be
automatically derived from the current Nvim options. See https://microsoft.github.io/language-server-protocol/specification/#formattingOptions
automatically derived from the current Nvim options. See
https://microsoft.github.io/language-server-protocol/specification/#formattingOptions
• timeout_ms (integer|nil, default 1000): Time in
milliseconds to block for formatting requests. No effect
if async=true
@ -1245,7 +1241,6 @@ format({options}) *vim.lsp.buf.format()*
• filter (function|nil): Predicate used to filter clients.
Receives a client as argument and must return a boolean.
Clients matching the predicate are included. Example: >lua
-- Never request typescript-language-server for formatting
vim.lsp.buf.format {
filter = function(client) return client.name ~= "tsserver" end
@ -1308,6 +1303,9 @@ remove_workspace_folder({workspace_folder})
Remove the folder at path from the workspace folders. If {path} is not
provided, the user will be prompted for a path using |input()|.
Parameters: ~
• {workspace_folder} (`string?`)
rename({new_name}, {options}) *vim.lsp.buf.rename()*
Renames all references to the symbol under the cursor.
@ -1454,12 +1452,13 @@ get({bufnr}) *vim.lsp.codelens.get()*
Return: ~
(`lsp.CodeLens[]`)
*vim.lsp.codelens.on_codelens()*
on_codelens({err}, {result}, {ctx}, {_})
on_codelens({err}, {result}, {ctx}) *vim.lsp.codelens.on_codelens()*
|lsp-handler| for the method `textDocument/codeLens`
Parameters: ~
• {ctx} (`lsp.HandlerContext`)
• {err} (`lsp.ResponseError?`)
• {result} (`lsp.CodeLens[]`)
• {ctx} (`lsp.HandlerContext`)
refresh({opts}) *vim.lsp.codelens.refresh()*
Refresh the lenses.
@ -1499,7 +1498,7 @@ enable({bufnr}, {enable}) *vim.lsp.inlay_hint.enable()*
<
Note: ~
This API is pre-release (unstable).
This API is pre-release (unstable).
Parameters: ~
• {bufnr} (`integer?`) Buffer handle, or 0 or nil for current
@ -1523,7 +1522,7 @@ get({filter}) *vim.lsp.inlay_hint.get()*
<
Note: ~
This API is pre-release (unstable).
This API is pre-release (unstable).
Parameters: ~
• {filter} (`vim.lsp.inlay_hint.get.filter?`) Optional filters
@ -1539,8 +1538,9 @@ get({filter}) *vim.lsp.inlay_hint.get()*
• inlay_hint (lsp.InlayHint)
is_enabled({bufnr}) *vim.lsp.inlay_hint.is_enabled()*
Note: ~
This API is pre-release (unstable).
This API is pre-release (unstable).
Parameters: ~
• {bufnr} (`integer?`) Buffer handle, or 0 or nil for current
@ -1653,6 +1653,7 @@ hover({_}, {result}, {ctx}, {config}) *vim.lsp.handlers.hover()*
<
Parameters: ~
• {result} (`lsp.Hover`)
• {ctx} (`lsp.HandlerContext`)
• {config} (`table`) Configuration table.
• border: (default=nil)
@ -1674,7 +1675,7 @@ signature_help({_}, {result}, {ctx}, {config})
<
Parameters: ~
• {result} (`table`) Response from the language server
• {result} (`lsp.SignatureHelp`) Response from the language server
• {ctx} (`lsp.HandlerContext`) Client context
• {config} (`table`) Configuration table.
• border: (default=nil)
@ -1695,6 +1696,7 @@ apply_text_document_edit({text_document_edit}, {index}, {offset_encoding})
• {text_document_edit} (`table`) a `TextDocumentEdit` object
• {index} (`integer`) Optional index of the edit, if from
a list of edits (or nil, if not from a list)
• {offset_encoding} (`string?`)
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
@ -1719,6 +1721,9 @@ apply_workspace_edit({workspace_edit}, {offset_encoding})
• {workspace_edit} (`table`) `WorkspaceEdit`
• {offset_encoding} (`string`) utf-8|utf-16|utf-32 (required)
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()*
Removes document highlights from a buffer.
@ -1994,6 +1999,7 @@ preview_location({location}, {opts}) *vim.lsp.util.preview_location()*
Parameters: ~
• {location} (`table`) a single `Location` or `LocationLink`
• {opts} (`table`)
Return (multiple): ~
(`integer?`) buffer id of float window
@ -2038,6 +2044,7 @@ stylize_markdown({bufnr}, {contents}, {opts})
`open_floating_preview` instead
Parameters: ~
• {bufnr} (`integer`)
• {contents} (`table`) of lines to show in window
• {opts} (`table`) with optional fields
• height of floating window
@ -2055,6 +2062,7 @@ symbols_to_items({symbols}, {bufnr}) *vim.lsp.util.symbols_to_items()*
Parameters: ~
• {symbols} (`table`) DocumentSymbol[] or SymbolInformation[]
• {bufnr} (`integer`)
==============================================================================
@ -2092,7 +2100,7 @@ should_log({level}) *vim.lsp.log.should_log()*
• {level} (`integer`) log level
Return: ~
(bool) true if would log, false if not
(`bool`) true if would log, false if not
==============================================================================
@ -2110,7 +2118,8 @@ connect({host}, {port}) *vim.lsp.rpc.connect()*
• {port} (`integer`) port to connect to
Return: ~
(`fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
(`fun(dispatchers: vim.lsp.rpc.Dispatchers):
vim.lsp.rpc.PublicClient`)
*vim.lsp.rpc.domain_socket_connect()*
domain_socket_connect({pipe_path})
@ -2126,7 +2135,8 @@ domain_socket_connect({pipe_path})
of the named pipe (Windows) to connect to
Return: ~
(`fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
(`fun(dispatchers: vim.lsp.rpc.Dispatchers):
vim.lsp.rpc.PublicClient`)
format_rpc_error({err}) *vim.lsp.rpc.format_rpc_error()*
Constructs an error message from an LSP error object.
@ -2241,4 +2251,5 @@ resolve_capabilities({server_capabilities})
Return: ~
(`lsp.ServerCapabilities?`) Normalized table of capabilities
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@ -582,25 +582,21 @@ A subset of the `vim.*` API is available in threads. This includes:
==============================================================================
VIM.HIGHLIGHT *vim.highlight*
Nvim includes a function for highlighting a selection on yank.
To enable it, add the following to your `init.vim`: >vim
au TextYankPost * silent! lua vim.highlight.on_yank()
<
You can customize the highlight group and the duration of the highlight
via: >vim
You can customize the highlight group and the duration of the highlight via: >vim
au TextYankPost * silent! lua vim.highlight.on_yank {higroup="IncSearch", timeout=150}
<
If you want to exclude visual selections from highlighting on yank, use: >vim
au TextYankPost * silent! lua vim.highlight.on_yank {on_visual=false}
<
vim.highlight.on_yank({opts}) *vim.highlight.on_yank()*
Highlight the yanked text
@ -678,12 +674,10 @@ vim.diff({a}, {b}, {opts}) *vim.diff()*
• `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
@ -694,7 +688,6 @@ vim.diff({a}, {b}, {opts}) *vim.diff()*
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
@ -716,30 +709,38 @@ vim.diff({a}, {b}, {opts}) *vim.diff()*
==============================================================================
VIM.MPACK *vim.mpack*
This module provides encoding and decoding of Lua objects to and from
msgpack-encoded strings. Supports |vim.NIL| and |vim.empty_dict()|.
vim.mpack.decode({str}) *vim.mpack.decode()*
Decodes (or "unpacks") the msgpack-encoded {str} to a Lua object.
Parameters: ~
• {str} (`string`)
Return: ~
(`any`)
vim.mpack.encode({obj}) *vim.mpack.encode()*
Encodes (or "packs") Lua object {obj} as msgpack in a Lua string.
Parameters: ~
• {obj} (`any`)
Return: ~
(`string`)
==============================================================================
VIM.JSON *vim.json*
This module provides encoding and decoding of Lua objects to and from
JSON-encoded strings. Supports |vim.NIL| and |vim.empty_dict()|.
vim.json.decode({str}, {opts}) *vim.json.decode()*
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).
@ -829,24 +830,24 @@ vim.spell.check({str}) *vim.spell.check()*
VIM *vim.builtin*
vim.api.{func}({...}) *vim.api*
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*
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*
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*
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
{
@ -855,7 +856,7 @@ vim.val_idx *vim.val_id
}
< See also |vim.type_idx| and |lua-special-tbl|.
vim.types *vim.types*
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
@ -884,6 +885,8 @@ Log levels are one of the values defined in `vim.log.levels`:
vim.log.levels.WARN
vim.log.levels.OFF
vim.empty_dict() *vim.empty_dict()*
Creates a special empty table (marked with a metatable), which Nvim
converts to an empty dictionary when translating Lua values to Vimscript
@ -1137,8 +1140,9 @@ vim.wait({time}, {callback}, {interval}, {fast_only}) *vim.wait()*
• {fast_only} (`boolean?`) If true, only |api-fast| events will be
processed.
Return: ~
(`boolean, -1|-2?`)
Return (multiple): ~
(`boolean`)
(`-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`
@ -1148,18 +1152,15 @@ vim.wait({time}, {callback}, {interval}, {fast_only}) *vim.wait()*
==============================================================================
LUA-VIMSCRIPT BRIDGE *lua-vimscript*
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: >lua
"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: >lua
local list = { 1, 2, 3 }
vim.fn.remove(list, 0)
vim.print(list) --> "{ 1, 2, 3 }"
<
vim.call({func}, {...}) *vim.call()*
@ -1240,7 +1241,7 @@ vim.v *vim.v*
|v:| variables.
Invalid or unset key returns `nil`.
` ` *lua-options*
*lua-options*
*lua-vim-options*
*lua-vim-set*
*lua-vim-setlocal*
@ -1263,9 +1264,10 @@ 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|.
` ` *vim.opt_local*
*vim.opt_global*
*vim.opt*
*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
@ -1326,6 +1328,7 @@ 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`.
Option:append({value}) *vim.opt:append()*
Append a value to string-style options. See |:set+=|
@ -1478,7 +1481,7 @@ vim.wo *vim.wo*
==============================================================================
Lua module: vim *lua-vim*
vim.cmd *vim.cmd()*
vim.cmd({command}) *vim.cmd()*
Executes Vim script commands.
Note that `vim.cmd` can be indexed with a command name to return a
@ -1552,7 +1555,7 @@ vim.deprecate({name}, {alternative}, {version}, {plugin}, {backtrace})
Return: ~
(`string?`) Deprecated message, or nil if no message was shown.
vim.inspect *vim.inspect()*
vim.inspect() *vim.inspect()*
Gets a human-readable representation of the given object.
Return: ~
@ -1580,12 +1583,15 @@ vim.keycode({str}) *vim.keycode()*
See also: ~
• |nvim_replace_termcodes()|
vim.lua_omnifunc({find_start}, {_}) *vim.lua_omnifunc()*
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 `set omnifunc=v:lua.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.
@ -1655,8 +1661,8 @@ vim.paste({lines}, {phase}) *vim.paste()*
• {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:
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)
@ -1674,6 +1680,9 @@ vim.print({...}) *vim.print()*
local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' }))
<
Parameters: ~
• {...} (`any`)
Return: ~
(`any`) given arguments.
@ -1799,7 +1808,6 @@ vim.system({cmd}, {opts}, {on_exit}) *vim.system()*
• signal: (integer)
• stdout: (string), nil if stdout argument is passed
• stderr: (string), nil if stderr argument is passed
• kill (fun(signal: integer|string))
• write (fun(data: string|nil)) Requires `stdin=true`. Pass `nil` to
close the stream.
@ -1858,11 +1866,32 @@ vim.show_pos({bufnr}, {row}, {col}, {filter}) *vim.show_pos()*
Ringbuf:clear() *Ringbuf:clear()*
Clear all items
Ringbuf:peek() *Ringbuf:peek()*
Returns the first unread item without removing it
Return: ~
(`any?`)
Ringbuf:pop() *Ringbuf:pop()*
Removes and returns the first unread item
Return: ~
(`any?`)
Ringbuf:push({item}) *Ringbuf:push()*
Adds an item, overriding the oldest item if the buffer is full.
Parameters: ~
• {item} (`any`)
vim.deep_equal({a}, {b}) *vim.deep_equal()*
Deep compare values for equality
Tables are compared recursively unless they both provide the `eq` metamethod.
All other types are compared using the equality `==` operator.
Tables are compared recursively unless they both provide the `eq`
metamethod. All other types are compared using the equality `==` operator.
Parameters: ~
• {a} (`any`) First value
@ -1999,12 +2028,12 @@ vim.list_slice({list}, {start}, {finish}) *vim.list_slice()*
(inclusive)
Parameters: ~
• {list} (`list`) Table
• {list} (`any[]`) Table
• {start} (`integer?`) Start range of slice
• {finish} (`integer?`) End range of slice
Return: ~
(`list`) Copy of table sliced from start to finish (inclusive)
(`any[]`) Copy of table sliced from start to finish (inclusive)
vim.pesc({s}) *vim.pesc()*
Escapes magic chars in |lua-patterns|.
@ -2037,7 +2066,6 @@ vim.ringbuf({size}) *vim.ringbuf()*
<
Returns a Ringbuf instance with the following methods:
• |Ringbuf:push()|
• |Ringbuf:pop()|
• |Ringbuf:peek()|
@ -2049,27 +2077,6 @@ vim.ringbuf({size}) *vim.ringbuf()*
Return: ~
(`table`)
vim.Ringbuf:clear() *Ringbuf:clear()*
Clear all items.
vim.Ringbuf:peek() *Ringbuf:peek()*
Returns the first unread item without removing it
Return: ~
(`any?`)
vim.Ringbuf:pop() *Ringbuf:pop()*
Removes and returns the first unread item
Return: ~
(`any?`)
vim.Ringbuf:push({item}) *Ringbuf:push()*
Adds an item, overriding the oldest item if the buffer is full.
Parameters: ~
• {item} (`any`)
vim.spairs({t}) *vim.spairs()*
Enumerates key-value pairs of a table, ordered by key.
@ -2080,7 +2087,8 @@ vim.spairs({t}) *vim.spairs()*
(`function`) |for-in| iterator over sorted keys and their values
See also: ~
• Based on https://github.com/premake/premake-core/blob/master/src/base/table.lua
• Based on
https://github.com/premake/premake-core/blob/master/src/base/table.lua
vim.split({s}, {sep}, {opts}) *vim.split()*
Splits a string at each instance of a separator and returns the result as
@ -2171,8 +2179,8 @@ vim.tbl_deep_extend({behavior}, {...}) *vim.tbl_deep_extend()*
Merges recursively two or more tables.
Parameters: ~
• {behavior} (`string`) Decides what to do if a key is found in more
than one map:
• {behavior} (`"error"|"keep"|"force"`) (string) Decides what to do if
a key is found in more than one map:
• "error": raise an error
• "keep": use value from the leftmost map
• "force": use value from the rightmost map
@ -2209,7 +2217,7 @@ vim.tbl_filter({func}, {t}) *vim.tbl_filter()*
• {t} (`table`) Table
Return: ~
(`table`) Table of filtered values
(`any[]`) Table of filtered values
vim.tbl_flatten({t}) *vim.tbl_flatten()*
Creates a copy of a list-like table such that any nested tables are
@ -2222,7 +2230,8 @@ vim.tbl_flatten({t}) *vim.tbl_flatten()*
(`table`) Flattened copy of the given list-like table
See also: ~
• From https://github.com/premake/premake-core/blob/master/src/base/table.lua
• From
https://github.com/premake/premake-core/blob/master/src/base/table.lua
vim.tbl_get({o}, {...}) *vim.tbl_get()*
Index into a table (first argument) via string keys passed as subsequent
@ -2298,10 +2307,11 @@ vim.tbl_keys({t}) *vim.tbl_keys()*
• {t} (`table`) Table
Return: ~
(`list`) List of keys
(`any[]`) List of keys
See also: ~
• From https://github.com/premake/premake-core/blob/master/src/base/table.lua
• From
https://github.com/premake/premake-core/blob/master/src/base/table.lua
vim.tbl_map({func}, {t}) *vim.tbl_map()*
Apply a function to all values of a table.
@ -2321,7 +2331,7 @@ vim.tbl_values({t}) *vim.tbl_values()*
• {t} (`table`) Table
Return: ~
(`list`) List of values
(`any[]`) List of values
vim.trim({s}) *vim.trim()*
Trim whitespace (Lua pattern "%s") from both sides of a string.
@ -2378,7 +2388,6 @@ vim.validate({opt}) *vim.validate()*
"string", "s", "number", "n", "boolean", "b", "function",
"f", "nil", "thread", "userdata") or list of them.
• optional: (optional) boolean, if true, `nil` is valid
2. (arg_value, fn, msg)
• arg_value: argument value
• fn: any function accepting one argument, returns true if
@ -2422,7 +2431,7 @@ vim.loader.find({modname}, {opts}) *vim.loader.find()*
first one (defaults to `false`)
Return: ~
(`list`) A list of results with the following properties:
(`table`) A list of results with the following properties:
• modpath: (string) the path to the module
• modname: (string) the name of the module
• stat: (table|nil) the fs_stat of the module path. Won't be returned
@ -2632,9 +2641,9 @@ vim.filetype.add({filetypes}) *vim.filetype.add()*
['/etc/foo/config'] = 'toml',
},
pattern = {
['.*&zwj;/etc/foo/.*'] = 'fooscript',
['.*/etc/foo/.*'] = 'fooscript',
-- Using an optional priority
['.*&zwj;/etc/foo/.*%.conf'] = { 'dosini', { priority = 10 } },
['.*/etc/foo/.*%.conf'] = { 'dosini', { priority = 10 } },
-- A pattern containing an environment variable
['${XDG_CONFIG_HOME}/foo/git'] = 'git',
['README.(%a+)$'] = function(path, bufnr, ext)
@ -2756,9 +2765,11 @@ vim.keymap.del({modes}, {lhs}, {opts}) *vim.keymap.del()*
<
Parameters: ~
• {opts} (`table?`) A table of optional arguments:
• "buffer": (integer|boolean) Remove a mapping from the given
buffer. When `0` or `true`, use the current buffer.
• {modes} (`string|string[]`)
• {lhs} (`string`)
• {opts} (`table?`) A table of optional arguments:
• "buffer": (integer|boolean) Remove a mapping from the given
buffer. When `0` or `true`, use the current buffer.
See also: ~
• |vim.keymap.set()|
@ -2789,7 +2800,6 @@ vim.keymap.set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()*
• Same as |nvim_set_keymap()| {opts}, except:
• "replace_keycodes" defaults to `true` if "expr" is `true`.
• "noremap": inverse of "remap" (see below).
• Also accepts:
• "buffer": (integer|boolean) Creates buffer-local mapping,
`0` or `true` for current buffer.
@ -2971,7 +2981,8 @@ Lua module: vim.glob *vim.glob*
vim.glob.to_lpeg({pattern}) *vim.glob.to_lpeg()*
Parses a raw glob into an |lua-lpeg| pattern.
This uses glob semantics from LSP 3.17.0: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#pattern
This uses glob semantics from LSP 3.17.0:
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#pattern
Glob patterns can have the following syntax:
• `*` to match one or more characters in a path segment
@ -3008,6 +3019,35 @@ The LPeg library for parsing expression grammars is included as `vim.lpeg`
In addition, its regex-like interface is available as |vim.re|
(https://www.inf.puc-rio.br/~roberto/lpeg/re.html).
Pattern:match({subject}, {init}) *Pattern:match()*
Matches the given `pattern` against the `subject` string. If the match
succeeds, returns the index in the subject of the first character after
the match, or the captured values (if the pattern captured any value). An
optional numeric argument `init` makes the match start at that position in
the subject string. As usual in Lua libraries, a negative value counts
from the end. Unlike typical pattern-matching functions, `match` works
only in anchored mode; that is, it tries to match the pattern with a
prefix of the given subject string (at position `init`), not with an
arbitrary substring of the subject. So, if we want to find a pattern
anywhere in a string, we must either write a loop in Lua or write a
pattern that matches anywhere.
Example: >lua
local pattern = lpeg.R("az") ^ 1 * -1
assert(pattern:match("hello") == 6)
assert(lpeg.match(pattern, "hello") == 6)
assert(pattern:match("1 hello") == nil)
<
Parameters: ~
• {subject} (`string`)
• {init} (`integer?`)
Return: ~
(`integer|vim.lpeg.Capture?`)
vim.lpeg.B({pattern}) *vim.lpeg.B()*
Returns a pattern that matches only if the input string at the current
position is preceded by `patt`. Pattern `patt` must match only strings
@ -3047,7 +3087,8 @@ vim.lpeg.C({patt}) *vim.lpeg.C()*
vim.lpeg.Carg({n}) *vim.lpeg.Carg()*
Creates an argument capture. This pattern matches the empty string and
produces the value given as the nth extra argument given in the call to `lpeg.match` .
produces the value given as the nth extra argument given in the call to
`lpeg.match`.
Parameters: ~
• {n} (`integer`)
@ -3192,11 +3233,40 @@ vim.lpeg.Ct({patt}) *vim.lpeg.Ct()*
the group name as its key. The captured value is only the table.
Parameters: ~
• {patt} (vim.lpeg.Pattern |' `) @return (` vim.lpeg.Capture`)
• {patt} (`vim.lpeg.Pattern|''`)
vim.lpeg.lpeg *vim.lpeg()*
LPeg is a new pattern-matching library for Lua, based on Parsing Expression
Grammars (PEGs).
Return: ~
(`vim.lpeg.Capture`)
vim.lpeg.locale({tab}) *vim.lpeg.locale()*
Returns a table with patterns for matching some character classes
according to the current locale. The table has fields named `alnum`,
`alpha`, `cntrl`, `digit`, `graph`, `lower`, `print`, `punct`, `space`,
`upper`, and `xdigit`, each one containing a correspondent pattern. Each
pattern matches any single character that belongs to its class. If called
with an argument `table`, then it creates those fields inside the given
table and returns that table.
Example: >lua
lpeg.locale(lpeg)
local space = lpeg.space^0
local name = lpeg.C(lpeg.alpha^1) * space
local sep = lpeg.S(",;") * space
local pair = lpeg.Cg(name * "=" * space * name) * sep^-1
local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset)
local t = list:match("a=b, c = hi; next = pi")
assert(t.a == 'b')
assert(t.c == 'hi')
assert(t.next == 'pi')
local locale = lpeg.locale()
assert(type(locale.digit) == 'userdata')
<
Parameters: ~
• {tab} (`table?`)
Return: ~
(`vim.lpeg.Locale`)
vim.lpeg.match({pattern}, {subject}, {init}) *vim.lpeg.match()*
Matches the given `pattern` against the `subject` string. If the match
@ -3252,33 +3322,6 @@ vim.lpeg.P({value}) *vim.lpeg.P()*
Return: ~
(`vim.lpeg.Pattern`)
vim.lpeg.Pattern:match({subject}, {init}) *Pattern:match()*
Matches the given `pattern` against the `subject` string. If the match
succeeds, returns the index in the subject of the first character after
the match, or the captured values (if the pattern captured any value). An
optional numeric argument `init` makes the match start at that position in
the subject string. As usual in Lua libraries, a negative value counts
from the end. Unlike typical pattern-matching functions, `match` works
only in anchored mode; that is, it tries to match the pattern with a
prefix of the given subject string (at position `init`), not with an
arbitrary substring of the subject. So, if we want to find a pattern
anywhere in a string, we must either write a loop in Lua or write a
pattern that matches anywhere.
Example: >lua
local pattern = lpeg.R("az") ^ 1 * -1
assert(pattern:match("hello") == 6)
assert(lpeg.match(pattern, "hello") == 6)
assert(pattern:match("1 hello") == nil)
<
Parameters: ~
• {subject} (`string`)
• {init} (`integer?`)
Return: ~
(`integer|vim.lpeg.Capture?`)
vim.lpeg.R({...}) *vim.lpeg.R()*
Returns a pattern that matches any single character belonging to one of
the given ranges. Each `range` is a string `xy` of length 2, representing
@ -3300,10 +3343,10 @@ vim.lpeg.R({...}) *vim.lpeg.R()*
vim.lpeg.S({string}) *vim.lpeg.S()*
Returns a pattern that matches any single character that appears in the
given string (the `S` stands for Set). As an example, the pattern
`lpeg.S("+-*&zwj;/")` matches any arithmetic operator. Note that, if `s`
is a character (that is, a string of length 1), then `lpeg.P(s)` is
equivalent to `lpeg.S(s)` which is equivalent to `lpeg.R(s..s)`. Note also
that both `lpeg.S("")` and `lpeg.R()` are patterns that always fail.
`lpeg.S("+-*/")` matches any arithmetic operator. Note that, if `s` is a
character (that is, a string of length 1), then `lpeg.P(s)` is equivalent
to `lpeg.S(s)` which is equivalent to `lpeg.R(s..s)`. Note also that both
`lpeg.S("")` and `lpeg.R()` are patterns that always fail.
Parameters: ~
• {string} (`string`)
@ -3327,6 +3370,9 @@ vim.lpeg.type({value}) *vim.lpeg.type()*
Returns the string `"pattern"` if the given value is a pattern, otherwise
`nil`.
Parameters: ~
• {value} (`vim.lpeg.Pattern|string|integer|boolean|table|function`)
Return: ~
(`"pattern"?`)
@ -3357,13 +3403,13 @@ vim.lpeg.version() *vim.lpeg.version()*
==============================================================================
VIM.RE *vim.re*
The `vim.re` module provides a conventional regex-like syntax for pattern usage
within LPeg |vim.lpeg|.
The `vim.re` module provides a conventional regex-like syntax for pattern
usage within LPeg |vim.lpeg|.
See https://www.inf.puc-rio.br/~roberto/lpeg/re.html for the original
documentation including regex syntax and more concrete examples.
vim.re.compile({string}, {defs}) *vim.re.compile()*
Compiles the given {string} and returns an equivalent LPeg pattern. The
given string may define either an expression or a grammar. The optional
@ -3421,28 +3467,19 @@ vim.re.match({subject}, {pattern}, {init}) *vim.re.match()*
See also: ~
• vim.lpeg.match()
vim.re.updatelocale() *vim.re.updatelocale()*
Updates the pre-defined character classes to the current locale.
==============================================================================
VIM.REGEX *vim.regex*
Vim regexes can be used directly from Lua. Currently they only allow matching
within a single line.
Vim regexes can be used directly from Lua. Currently they only allow
matching within a single line.
vim.regex({re}) *vim.regex()*
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|.
Parameters: ~
• {re} (`string`)
Return: ~
(`vim.regex`)
*regex:match_line()*
vim.regex:match_line({bufnr}, {line_idx}, {start}, {end_})
regex:match_line({bufnr}, {line_idx}, {start}, {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
@ -3454,16 +3491,28 @@ vim.regex:match_line({bufnr}, {line_idx}, {start}, {end_})
• {start} (`integer?`)
• {end_} (`integer?`)
vim.regex:match_str({str}) *regex:match_str()*
regex:match_str({str}) *regex:match_str()*
Match the string against the regex. If the string should match the regex
precisely, surround the regex with `^` and `$` . If there was a match, the
precisely, surround the regex with `^` and `$`. If there was a match, the
byte indices for the beginning and end of the match are returned. When
there is no match, `nil` is returned. Because any integer is "truthy", `regex:match_str()` can
be directly used as a condition in an if-statement.
there is no match, `nil` is returned. Because any integer is "truthy",
`regex:match_str()` can be directly used as a condition in an
if-statement.
Parameters: ~
• {str} (`string`)
vim.regex({re}) *vim.regex()*
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|.
Parameters: ~
• {re} (`string`)
Return: ~
(`vim.regex`)
==============================================================================
Lua module: vim.secure *vim.secure*
@ -3508,29 +3557,23 @@ vim.secure.trust({opts}) *vim.secure.trust()*
==============================================================================
Lua module: vim.version *vim.version*
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 available tools
and dependencies on the current system.
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 available tools and dependencies on the current system.
Example: >lua
local v = vim.version.parse(vim.fn.system({'tmux', '-V'}), {strict=false})
if vim.version.gt(v, {3, 2, 0}) then
-- ...
end
<
*vim.version()* returns the version of the current Nvim process.
VERSION RANGE SPEC *version-range*
VERSION RANGE SPEC *version-range*
A version "range spec" defines a semantic version range which can be
tested against a version, using |vim.version.range()|.
A version "range spec" defines a semantic version range which can be tested
against a version, using |vim.version.range()|.
Supported range specs are shown in the following table. Note: suffixed
versions (1.2.3-rc1) are not matched. >
@ -3561,9 +3604,9 @@ versions (1.2.3-rc1) are not matched. >
Partial left: missing pieces treated as 0 (1.2 => 1.2.0).
1.2 - 2.3.0 is 1.2.0 - 2.3.0
<
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}`
@ -3586,14 +3629,14 @@ vim.version.cmp({v1}, {v2}) *vim.version.cmp()*
Parameters: ~
• {v1} (`Version|number[]|string`) Version object.
• {v2} (`Version|number[]|string`) Version to compare with `v1` .
• {v2} (`Version|number[]|string`) Version to compare with `v1`.
Return: ~
(`integer`) -1 if `v1 < v2`, 0 if `v1 == v2`, 1 if `v1 > v2`.
vim.version.eq({v1}, {v2}) *vim.version.eq()*
Returns `true` if the given versions are equal. See |vim.version.cmp()| for
usage.
Returns `true` if the given versions are equal. See |vim.version.cmp()|
for usage.
Parameters: ~
• {v1} (`Version|number[]|string`)
@ -3603,7 +3646,7 @@ vim.version.eq({v1}, {v2}) *vim.version.eq()*
(`boolean`)
vim.version.ge({v1}, {v2}) *vim.version.ge()*
Returns `true` if `v1 >= v2` . See |vim.version.cmp()| for usage.
Returns `true` if `v1 >= v2`. See |vim.version.cmp()| for usage.
Parameters: ~
• {v1} (`Version|number[]|string`)
@ -3613,7 +3656,7 @@ vim.version.ge({v1}, {v2}) *vim.version.ge()*
(`boolean`)
vim.version.gt({v1}, {v2}) *vim.version.gt()*
Returns `true` if `v1 > v2` . See |vim.version.cmp()| for usage.
Returns `true` if `v1 > v2`. See |vim.version.cmp()| for usage.
Parameters: ~
• {v1} (`Version|number[]|string`)
@ -3632,7 +3675,7 @@ vim.version.last({versions}) *vim.version.last()*
(`Version?`)
vim.version.le({v1}, {v2}) *vim.version.le()*
Returns `true` if `v1 <= v2` . See |vim.version.cmp()| for usage.
Returns `true` if `v1 <= v2`. See |vim.version.cmp()| for usage.
Parameters: ~
• {v1} (`Version|number[]|string`)
@ -3642,7 +3685,7 @@ vim.version.le({v1}, {v2}) *vim.version.le()*
(`boolean`)
vim.version.lt({v1}, {v2}) *vim.version.lt()*
Returns `true` if `v1 < v2` . See |vim.version.cmp()| for usage.
Returns `true` if `v1 < v2`. See |vim.version.cmp()| for usage.
Parameters: ~
• {v1} (`Version|number[]|string`)
@ -3671,7 +3714,7 @@ vim.version.parse({version}, {opts}) *vim.version.parse()*
invalid.
See also: ~
# https://semver.org/spec/v2.0.0.html
• https://semver.org/spec/v2.0.0.html
vim.version.range({spec}) *vim.version.range()*
Parses a semver |version-range| "spec" and returns a range object: >
@ -3702,35 +3745,30 @@ vim.version.range({spec}) *vim.version.range()*
• {spec} (`string`) Version range "spec"
See also: ~
# https://github.com/npm/node-semver#ranges
• https://github.com/npm/node-semver#ranges
==============================================================================
Lua module: vim.iter *vim.iter*
*vim.iter()* is an interface for |iterable|s: it wraps a table or function
argument into an *Iter* object with methods (such as |Iter:filter()| and
|Iter:map()|) that transform the underlying source data. These methods can
be chained to create iterator "pipelines": the output of each pipeline
stage is input to the next stage. The first stage depends on the type
passed to `vim.iter()`:
|Iter:map()|) that transform the underlying source data. These methods can be
chained to create iterator "pipelines": the output of each pipeline stage is
input to the next stage. The first stage depends on the type passed to
`vim.iter()`:
• List tables (arrays, |lua-list|) yield only the value of each element.
• Use |Iter:enumerate()| to also pass the index to the next stage.
• Or initialize with ipairs(): `vim.iter(ipairs(…))`.
• Non-list tables (|lua-dict|) yield both the key and value of each
element.
• Function |iterator|s yield all values returned by the underlying
function.
• Non-list tables (|lua-dict|) yield both the key and value of each element.
• Function |iterator|s yield all values returned by the underlying function.
• Tables with a |__call()| metamethod are treated as function iterators.
The iterator pipeline terminates when the underlying |iterable| is
exhausted (for function iterators this means it returned nil).
The iterator pipeline terminates when the underlying |iterable| is exhausted
(for function iterators this means it returned nil).
Note: `vim.iter()` scans table input to decide if it is a list or a dict;
to avoid this cost you can wrap the table with an iterator e.g.
Note: `vim.iter()` scans table input to decide if it is a list or a dict; to
avoid this cost you can wrap the table with an iterator e.g.
`vim.iter(ipairs({…}))`, but that precludes the use of |list-iterator|
operations such as |Iter:rev()|).
@ -3771,13 +3809,13 @@ Examples: >lua
rb:push("b")
vim.iter(rb):totable()
-- { "a", "b" }
<
In addition to the |vim.iter()| function, the |vim.iter| module provides
convenience functions like |vim.iter.filter()| and |vim.iter.totable()|.
filter({f}, {src}, {...}) *vim.iter.filter()*
filter({f}, {src}) *vim.iter.filter()*
Filters a table or other |iterable|. >lua
-- Equivalent to:
vim.iter(src):filter(f):totable()
@ -3839,11 +3877,11 @@ Iter:enumerate() *Iter:enumerate()*
Example: >lua
local it = vim.iter(vim.gsplit('abc', '')):enumerate()
it:next()
-- 1 'a'
-- 1 'a'
it:next()
-- 2 'b'
-- 2 'b'
it:next()
-- 3 'c'
-- 3 'c'
<
Return: ~
@ -3884,6 +3922,9 @@ Iter:find({f}) *Iter:find()*
-- 12
<
Parameters: ~
• {f} (`any`)
Return: ~
(`any`)
@ -3926,7 +3967,7 @@ Iter:fold({init}, {f}) *Iter:fold()*
Parameters: ~
• {init} (`any`) Initial value of the accumulator.
• {f} (`fun(acc:any, ...):any`) Accumulation function.
• {f} (`fun(acc:A, ...):A`) Accumulation function.
Return: ~
(`any`)
@ -4105,11 +4146,14 @@ Iter:rfind({f}) *Iter:rfind()*
Examples: >lua
local it = vim.iter({ 1, 2, 3, 2, 1 }):enumerate()
it:rfind(1)
-- 5 1
-- 5 1
it:rfind(1)
-- 1 1
-- 1 1
<
Parameters: ~
• {f} (`any`)
Return: ~
(`any`)
@ -4205,7 +4249,7 @@ Iter:totable() *Iter:totable()*
Return: ~
(`table`)
map({f}, {src}, {...}) *vim.iter.map()*
map({f}, {src}) *vim.iter.map()*
Maps a table or other |iterable|. >lua
-- Equivalent to:
vim.iter(src):map(f):totable()
@ -4223,7 +4267,7 @@ map({f}, {src}, {...}) *vim.iter.map()*
See also: ~
• |Iter:map()|
totable({f}, {...}) *vim.iter.totable()*
totable({f}) *vim.iter.totable()*
Collects an |iterable| into a table. >lua
-- Equivalent to:
vim.iter(f):totable()
@ -4249,8 +4293,9 @@ vim.snippet.exit() *vim.snippet.exit()*
Exits the current snippet.
vim.snippet.expand({input}) *vim.snippet.expand()*
Expands the given snippet text. Refer to https://microsoft.github.io/language-server-protocol/specification/#snippet_syntax for
the specification of valid input.
Expands the given snippet text. Refer to
https://microsoft.github.io/language-server-protocol/specification/#snippet_syntax
for the specification of valid input.
Tabstops are highlighted with hl-SnippetTabstop.
@ -4317,4 +4362,5 @@ vim.text.hexencode({str}) *vim.text.hexencode()*
Return: ~
(`string`) Hex encoded string
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@ -933,6 +933,7 @@ get_filetypes({lang}) *vim.treesitter.language.get_filetypes()*
(`string[]`) filetypes
get_lang({filetype}) *vim.treesitter.language.get_lang()*
Parameters: ~
• {filetype} (`string`)
@ -1056,14 +1057,13 @@ lint({buf}, {opts}) *vim.treesitter.query.lint()*
Use |treesitter-parsers| in runtimepath to check the query file in {buf}
for errors:
• verify that used nodes are valid identifiers in the grammar.
• verify that predicates and directives are valid.
• verify that top-level s-expressions are valid.
The found diagnostics are reported using |diagnostic-api|. By default, the
parser used for verification is determined by the containing folder of the
query file, e.g., if the path ends in `/lua/highlights.scm` , the parser
query file, e.g., if the path ends in `/lua/highlights.scm`, the parser
for the `lua` language will be used.
Parameters: ~
@ -1093,6 +1093,10 @@ omnifunc({findstart}, {base}) *vim.treesitter.query.omnifunc()*
vim.bo.omnifunc = 'v:lua.vim.treesitter.query.omnifunc'
<
Parameters: ~
• {findstart} (`0|1`)
• {base} (`string`)
parse({lang}, {query}) *vim.treesitter.query.parse()*
Parse {query} as a string. (If the query is in a file, the caller should
read the contents into a string before calling).
@ -1218,42 +1222,36 @@ set({lang}, {query_name}, {text}) *vim.treesitter.query.set()*
==============================================================================
Lua module: vim.treesitter.languagetree *lua-treesitter-languagetree*
A *LanguageTree* contains a tree of parsers: the root treesitter parser for
{lang} and any "injected" language parsers, which themselves may inject other
languages, recursively. For example a Lua buffer containing some Vimscript
commands needs multiple parsers to fully understand its contents.
A *LanguageTree* contains a tree of parsers: the root treesitter parser
for {lang} and any "injected" language parsers, which themselves may
inject other languages, recursively. For example a Lua buffer containing
some Vimscript commands needs multiple parsers to fully understand its
contents.
To create a LanguageTree (parser object) for a given buffer and language,
use: >lua
To create a LanguageTree (parser object) for a given buffer and language, use: >lua
local parser = vim.treesitter.get_parser(bufnr, lang)
<
(where `bufnr=0` means current buffer). `lang` defaults to 'filetype'.
Note: currently the parser is retained for the lifetime of a buffer but
this may change; a plugin should keep a reference to the parser object if
it wants incremental updates.
(where `bufnr=0` means current buffer). `lang` defaults to 'filetype'. Note:
currently the parser is retained for the lifetime of a buffer but this may
change; a plugin should keep a reference to the parser object if it wants
incremental updates.
Whenever you need to access the current syntax tree, parse the buffer: >lua
local tree = parser:parse({ start_row, end_row })
<
This returns a table of immutable |treesitter-tree| objects representing
the current state of the buffer. When the plugin wants to access the state
after a (possible) edit it must call `parse()` again. If the buffer wasn't
edited, the same tree will be returned again without extra work. If the
buffer was parsed before, incremental parsing will be done of the changed
parts.
This returns a table of immutable |treesitter-tree| objects representing the
current state of the buffer. When the plugin wants to access the state after a
(possible) edit it must call `parse()` again. If the buffer wasn't edited, the
same tree will be returned again without extra work. If the buffer was parsed
before, incremental parsing will be done of the changed parts.
Note: To use the parser directly inside a |nvim_buf_attach()| Lua callback,
you must call |vim.treesitter.get_parser()| before you register your callback.
But preferably parsing shouldn't be done directly in the 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 frequent updates.
Note: To use the parser directly inside a |nvim_buf_attach()| Lua
callback, you must call |vim.treesitter.get_parser()| before you register
your callback. But preferably parsing shouldn't be done directly in the
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
frequent updates.
LanguageTree:children() *LanguageTree:children()*
Returns a map of language to child tree.
@ -1284,7 +1282,7 @@ LanguageTree:for_each_tree({fn}) *LanguageTree:for_each_tree()*
• {fn} (`fun(tree: TSTree, ltree: LanguageTree)`)
LanguageTree:included_regions() *LanguageTree:included_regions()*
Gets the set of included regions managed by this LanguageTree . This can be
Gets the set of included regions managed by this LanguageTree. This can be
different from the regions set by injection query, because a partial
|LanguageTree:parse()| drops the regions outside the requested range.
@ -1405,4 +1403,5 @@ LanguageTree:trees() *LanguageTree:trees()*
Return: ~
(`table<integer, TSTree>`)
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@ -127,10 +127,10 @@ vim.log = {
--- timeout the process is sent the KILL signal (9) and the exit code is set to 124. Cannot
--- be called in |api-fast|.
--- - SystemCompleted is an object with the fields:
--- - code: (integer)
--- - signal: (integer)
--- - stdout: (string), nil if stdout argument is passed
--- - stderr: (string), nil if stderr argument is passed
--- - code: (integer)
--- - signal: (integer)
--- - stdout: (string), nil if stdout argument is passed
--- - stderr: (string), nil if stderr argument is passed
--- - kill (fun(signal: integer|string))
--- - write (fun(data: string|nil)) Requires `stdin=true`. Pass `nil` to close the stream.
--- - is_closing (fun(): boolean)
@ -706,8 +706,8 @@ end
--- Generates a list of possible completions for the string.
--- String has the pattern.
---
--- 1. Can we get it to just return things in the global namespace with that name prefix
--- 2. Can we get it to return things from global namespace even with `print(` in front.
--- 1. Can we get it to just return things in the global namespace with that name prefix
--- 2. Can we get it to return things from global namespace even with `print(` in front.
---
--- @param pat string
function vim._expand_pat(pat, env)
@ -885,6 +885,7 @@ do
--- similar to the builtin completion for the `:lua` command.
---
--- Activate using `set omnifunc=v:lua.vim.lua_omnifunc` in a Lua buffer.
--- @param find_start 1|0
function vim.lua_omnifunc(find_start, _)
if find_start == 1 then
local line = vim.api.nvim_get_current_line()
@ -914,6 +915,7 @@ end
---
--- @see |vim.inspect()|
--- @see |:=|
--- @param ... any
--- @return any # given arguments.
function vim.print(...)
if vim.in_fast_event() then

View File

@ -17,7 +17,7 @@ local defaults = {
---@param bufnr? integer defaults to the current buffer
---@param row? integer row to inspect, 0-based. Defaults to the row of the current cursor
---@param col? integer col to inspect, 0-based. Defaults to the col of the current cursor
---@param filter? InspectorFilter (table|nil) a table with key-value pairs to filter the items
---@param filter? InspectorFilter (table) a table with key-value pairs to filter the items
--- - syntax (boolean): include syntax based highlight groups (defaults to true)
--- - treesitter (boolean): include treesitter based highlight groups (defaults to true)
--- - extmarks (boolean|"all"): include extmarks. When `all`, then extmarks without a `hl_group` will also be included (defaults to true)
@ -139,7 +139,7 @@ end
---@param bufnr? integer defaults to the current buffer
---@param row? integer row to inspect, 0-based. Defaults to the row of the current cursor
---@param col? integer col to inspect, 0-based. Defaults to the col of the current cursor
---@param filter? InspectorFilter (table|nil) see |vim.inspect_pos()|
---@param filter? InspectorFilter (table) see |vim.inspect_pos()|
function vim.show_pos(bufnr, row, col, filter)
local items = vim.inspect_pos(bufnr, row, col, filter)

File diff suppressed because it is too large Load Diff

View File

@ -3,65 +3,63 @@
error('Cannot require a meta file')
---@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()))
---
---@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.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.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.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.
---
---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.
---
--- 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`:
---
--- *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
---
--- 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>
--- </pre>
---@class vim.NIL

View File

@ -5,7 +5,7 @@ vim.json = {}
-- luacheck: no unused args
---@defgroup vim.json
---@brief
---
--- This module provides encoding and decoding of Lua objects to and
--- from JSON-encoded strings. Supports |vim.NIL| and |vim.empty_dict()|.

View File

@ -5,22 +5,20 @@ error('Cannot require a meta file')
-- (based on revision 4aded588f9531d89555566bb1de27490354b91c7)
-- with types being renamed to include the vim namespace and with some descriptions made less verbose.
---@defgroup vim.lpeg
---<pre>help
---LPeg is a pattern-matching library for Lua, based on
---Parsing Expression Grammars (https://bford.info/packrat/) (PEGs).
--- @brief <pre>help
--- LPeg is a pattern-matching library for Lua, based on
--- Parsing Expression Grammars (https://bford.info/packrat/) (PEGs).
---
--- *lua-lpeg*
--- *vim.lpeg.Pattern*
---The LPeg library for parsing expression grammars is included as `vim.lpeg`
---(https://www.inf.puc-rio.br/~roberto/lpeg/).
--- *lua-lpeg*
--- *vim.lpeg.Pattern*
--- The LPeg library for parsing expression grammars is included as `vim.lpeg`
--- (https://www.inf.puc-rio.br/~roberto/lpeg/).
---
---In addition, its regex-like interface is available as |vim.re|
---(https://www.inf.puc-rio.br/~roberto/lpeg/re.html).
--- In addition, its regex-like interface is available as |vim.re|
--- (https://www.inf.puc-rio.br/~roberto/lpeg/re.html).
---
---</pre>
--- </pre>
--- *LPeg* is a new pattern-matching library for Lua, based on [Parsing Expression Grammars](https://bford.info/packrat/) (PEGs).
vim.lpeg = {}
--- @class vim.lpeg.Pattern
@ -88,6 +86,7 @@ function Pattern:match(subject, init) end
--- Returns the string `"pattern"` if the given value is a pattern, otherwise `nil`.
---
--- @param value vim.lpeg.Pattern|string|integer|boolean|table|function
--- @return "pattern"|nil
function vim.lpeg.type(value) end

View File

@ -2,14 +2,17 @@
-- luacheck: no unused args
--- @defgroup vim.mpack
--- @brief
---
--- 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
--- @return any
function vim.mpack.decode(str) end
--- Encodes (or "packs") Lua object {obj} as msgpack in a Lua string.
--- @param obj any
--- @return string
function vim.mpack.encode(obj) end

View File

@ -7,15 +7,12 @@ error('Cannot require a meta file')
-- Copyright © 2007-2023 Lua.org, PUC-Rio.
-- See 'lpeg.html' for license
--- @defgroup vim.re
---<pre>help
---The `vim.re` module provides a conventional regex-like syntax for pattern usage
---within LPeg |vim.lpeg|.
--- @brief
--- The `vim.re` module provides a conventional regex-like syntax for pattern usage
--- within LPeg |vim.lpeg|.
---
---See https://www.inf.puc-rio.br/~roberto/lpeg/re.html for the original
---documentation including regex syntax and more concrete examples.
---
---</pre>
--- See https://www.inf.puc-rio.br/~roberto/lpeg/re.html for the original
--- documentation including regex syntax and more concrete examples.
--- Compiles the given {string} and returns an equivalent LPeg pattern. The given string may define
--- either an expression or a grammar. The optional {defs} table provides extra Lua values to be used

View File

@ -2,8 +2,6 @@
-- 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.

View File

@ -1,12 +1,10 @@
---@defgroup lua-vimscript
--- @brief Nvim Lua provides an interface or "bridge" to Vimscript variables and
--- functions, and editor commands and options.
---
---@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:
--- 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:
---
--- ```lua
--- local list = { 1, 2, 3 }
@ -14,86 +12,85 @@
--- vim.print(list) --> "{ 1, 2, 3 }"
--- ```
---@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()|.
--- @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.
--- 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: |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: 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.
--- 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.
--- *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
--- 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
---<
--- 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.
--- 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
--- Example: >lua
---
--- vim.g.my_dict.field1 = 'value' -- Does not work
--- 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 --
--- 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.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.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.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.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`.
---</pre>
--- vim.v *vim.v*
--- |v:| variables.
--- Invalid or unset key returns `nil`.
--- </pre>
local api = vim.api
@ -142,7 +139,6 @@ end
--- vim.env.FOO = 'bar'
--- print(vim.env.TERM)
--- ```
---
---@param var string
vim.env = setmetatable({}, {
__index = function(_, k)
@ -205,31 +201,30 @@ local function new_win_opt_accessor(winid, bufnr)
})
end
---@addtogroup lua-vimscript
---@brief <pre>help
---` ` *lua-options*
--- *lua-vim-options*
--- *lua-vim-set*
--- *lua-vim-setlocal*
--- @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|.
--- Vim options can be accessed through |vim.o|, which behaves like Vimscript
--- |:set|.
---
--- Examples: ~
--- Examples: ~
---
--- To set a boolean toggle:
--- Vimscript: `set number`
--- Lua: `vim.o.number = true`
--- 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__'`
--- 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>
--- 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>
--- Get or set |options|. Like `:set`. Invalid key is an error.
---
@ -310,13 +305,10 @@ vim.bo = new_buf_opt_accessor()
--- ```
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
local function remove_duplicate_values(t)
@ -739,74 +731,73 @@ local function create_option_accessor(scope)
})
end
---@addtogroup lua-vimscript
---@brief <pre>help
---` ` *vim.opt_local*
--- *vim.opt_global*
--- *vim.opt*
--- @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.
--- 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: ~
--- 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
--- 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: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: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 = '>~' }
---<
--- 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()|:
--- Note that |vim.opt| returns an `Option` object, not the value of the option,
--- which is accessed through |vim.opt:get()|:
---
--- Examples: ~
--- 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())
---<
--- 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>
--- 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
--- @class vim.Option
local Option = {} -- luacheck: no unused
--- Returns a Lua-representation of the option. Boolean, number and string
@ -856,9 +847,7 @@ local Option = {} -- luacheck: no unused
--- print("J is enabled!")
--- end
--- ```
---
---@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+=|
@ -869,7 +858,6 @@ function Option:get() end
--- vim.opt.formatoptions:append('j')
--- vim.opt.formatoptions = vim.opt.formatoptions + 'j'
--- ```
---
---@param value string Value to append
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
function Option:append(value) end -- luacheck: no unused
@ -882,7 +870,6 @@ function Option:append(value) end -- luacheck: no unused
--- vim.opt.wildignore:prepend('*.o')
--- vim.opt.wildignore = vim.opt.wildignore ^ '*.o'
--- ```
---
---@param value string Value to prepend
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
function Option:prepend(value) end -- luacheck: no unused
@ -895,7 +882,6 @@ function Option:prepend(value) end -- luacheck: no unused
--- vim.opt.wildignore:remove('*.pyc')
--- vim.opt.wildignore = vim.opt.wildignore - '*.pyc'
--- ```
---
---@param value string Value to remove
---@diagnostic disable-next-line:unused-local used for gen_vimdoc
function Option:remove(value) end -- luacheck: no unused

View File

@ -70,6 +70,7 @@ local M = {}
--- @field linehl? table<vim.diagnostic.Severity,string>
--- @field texthl? table<vim.diagnostic.Severity,string>
--- @nodoc
--- @enum vim.diagnostic.Severity
M.severity = {
ERROR = 1,
@ -107,6 +108,7 @@ local global_diagnostic_options = {
--- @field show? fun(namespace: integer, bufnr: integer, diagnostics: vim.Diagnostic[], opts?: vim.diagnostic.OptsResolved)
--- @field hide? fun(namespace:integer, bufnr:integer)
--- @nodoc
--- @type table<string,vim.diagnostic.Handler>
M.handlers = setmetatable({}, {
__newindex = function(t, name, handler)
@ -731,71 +733,71 @@ end
--- - `function`: Function with signature (namespace, bufnr) that returns any of the above.
---
---@param opts vim.diagnostic.Opts? (table?) When omitted or "nil", retrieve the current
--- configuration. Otherwise, a configuration table with the following keys:
--- configuration. Otherwise, a configuration table with the following keys:
--- - underline: (default true) Use underline for diagnostics. Options:
--- * severity: Only underline diagnostics matching the given
--- severity |diagnostic-severity|
--- * severity: Only underline diagnostics matching the given
--- severity |diagnostic-severity|
--- - virtual_text: (default true) Use virtual text for diagnostics. If multiple diagnostics
--- are set for a namespace, one prefix per diagnostic + the last diagnostic
--- message are shown. In addition to the options listed below, the
--- "virt_text" options of |nvim_buf_set_extmark()| may also be used here
--- (e.g. "virt_text_pos" and "hl_mode").
--- Options:
--- * severity: Only show virtual text for diagnostics matching the given
--- severity |diagnostic-severity|
--- * source: (boolean or string) Include the diagnostic source in virtual
--- text. Use "if_many" to only show sources if there is more than
--- one diagnostic source in the buffer. Otherwise, any truthy value
--- means to always show the diagnostic source.
--- * spacing: (number) Amount of empty spaces inserted at the beginning
--- of the virtual text.
--- * prefix: (string or function) prepend diagnostic message with prefix.
--- If a function, it must have the signature (diagnostic, i, total)
--- -> string, where {diagnostic} is of type |diagnostic-structure|,
--- {i} is the index of the diagnostic being evaluated, and {total}
--- is the total number of diagnostics for the line. This can be
--- used to render diagnostic symbols or error codes.
--- * suffix: (string or function) Append diagnostic message with suffix.
--- If a function, it must have the signature (diagnostic) ->
--- string, where {diagnostic} is of type |diagnostic-structure|.
--- This can be used to render an LSP diagnostic error code.
--- * format: (function) A function that takes a diagnostic as input and
--- returns a string. The return value is the text used to display
--- the diagnostic. Example:
--- <pre>lua
--- function(diagnostic)
--- if diagnostic.severity == vim.diagnostic.severity.ERROR then
--- return string.format("E: %s", diagnostic.message)
--- end
--- return diagnostic.message
--- end
--- </pre>
--- are set for a namespace, one prefix per diagnostic + the last diagnostic
--- message are shown. In addition to the options listed below, the
--- "virt_text" options of |nvim_buf_set_extmark()| may also be used here
--- (e.g. "virt_text_pos" and "hl_mode").
--- Options:
--- * severity: Only show virtual text for diagnostics matching the given
--- severity |diagnostic-severity|
--- * source: (boolean or string) Include the diagnostic source in virtual
--- text. Use "if_many" to only show sources if there is more than
--- one diagnostic source in the buffer. Otherwise, any truthy value
--- means to always show the diagnostic source.
--- * spacing: (number) Amount of empty spaces inserted at the beginning
--- of the virtual text.
--- * prefix: (string or function) prepend diagnostic message with prefix.
--- If a function, it must have the signature (diagnostic, i, total)
--- -> string, where {diagnostic} is of type |diagnostic-structure|,
--- {i} is the index of the diagnostic being evaluated, and {total}
--- is the total number of diagnostics for the line. This can be
--- used to render diagnostic symbols or error codes.
--- * suffix: (string or function) Append diagnostic message with suffix.
--- If a function, it must have the signature (diagnostic) ->
--- string, where {diagnostic} is of type |diagnostic-structure|.
--- This can be used to render an LSP diagnostic error code.
--- * format: (function) A function that takes a diagnostic as input and
--- returns a string. The return value is the text used to display
--- the diagnostic. Example:
--- ```lua
--- function(diagnostic)
--- if diagnostic.severity == vim.diagnostic.severity.ERROR then
--- return string.format("E: %s", diagnostic.message)
--- end
--- return diagnostic.message
--- end
--- ```
--- - signs: (default true) Use signs for diagnostics |diagnostic-signs|. Options:
--- * severity: Only show signs for diagnostics matching the given
--- severity |diagnostic-severity|
--- * priority: (number, default 10) Base priority to use for signs. When
--- {severity_sort} is used, the priority of a sign is adjusted based on
--- its severity. Otherwise, all signs use the same priority.
--- * text: (table) A table mapping |diagnostic-severity| to the sign text
--- to display in the sign column. The default is to use "E", "W", "I", and "H"
--- for errors, warnings, information, and hints, respectively. Example:
--- <pre>lua
--- vim.diagnostic.config({
--- signs = { text = { [vim.diagnostic.severity.ERROR] = 'E', ... } }
--- })
--- </pre>
--- * numhl: (table) A table mapping |diagnostic-severity| to the highlight
--- group used for the line number where the sign is placed.
--- * linehl: (table) A table mapping |diagnostic-severity| to the highlight group
--- used for the whole line the sign is placed in.
--- * severity: Only show signs for diagnostics matching the given
--- severity |diagnostic-severity|
--- * priority: (number, default 10) Base priority to use for signs. When
--- {severity_sort} is used, the priority of a sign is adjusted based on
--- its severity. Otherwise, all signs use the same priority.
--- * text: (table) A table mapping |diagnostic-severity| to the sign text
--- to display in the sign column. The default is to use "E", "W", "I", and "H"
--- for errors, warnings, information, and hints, respectively. Example:
--- ```lua
--- vim.diagnostic.config({
--- signs = { text = { [vim.diagnostic.severity.ERROR] = 'E', ... } }
--- })
--- ```
--- * numhl: (table) A table mapping |diagnostic-severity| to the highlight
--- group used for the line number where the sign is placed.
--- * linehl: (table) A table mapping |diagnostic-severity| to the highlight group
--- used for the whole line the sign is placed in.
--- - float: Options for floating windows. See |vim.diagnostic.open_float()|.
--- - update_in_insert: (default false) Update diagnostics in Insert mode (if false,
--- diagnostics are updated on InsertLeave)
--- - severity_sort: (default false) Sort diagnostics by severity. This affects the order in
--- which signs and virtual text are displayed. When true, higher severities
--- are displayed before lower severities (e.g. ERROR is displayed before WARN).
--- Options:
--- * reverse: (boolean) Reverse sort order
--- which signs and virtual text are displayed. When true, higher severities
--- are displayed before lower severities (e.g. ERROR is displayed before WARN).
--- Options:
--- * reverse: (boolean) Reverse sort order
---
---@param namespace integer? Update the options for the given namespace. When omitted, update the
--- global diagnostic options.
@ -1090,8 +1092,8 @@ M.handlers.signs = {
api.nvim_create_namespace(string.format('%s/diagnostic/signs', ns.name))
end
--- Handle legacy diagnostic sign definitions
--- These were deprecated in 0.10 and will be removed in 0.12
-- Handle legacy diagnostic sign definitions
-- These were deprecated in 0.10 and will be removed in 0.12
if opts.signs and not opts.signs.text and not opts.signs.numhl and not opts.signs.texthl then
for _, v in ipairs({ 'Error', 'Warn', 'Info', 'Hint' }) do
local name = string.format('DiagnosticSign%s', v)
@ -1543,7 +1545,8 @@ end
--- Overrides the setting from |vim.diagnostic.config()|.
--- - suffix: Same as {prefix}, but appends the text to the diagnostic instead of
--- prepending it. Overrides the setting from |vim.diagnostic.config()|.
---@return integer?, integer?: ({float_bufnr}, {win_id})
---@return integer? float_bufnr
---@return integer? win_id
function M.open_float(opts, ...)
-- Support old (bufnr, opts) signature
local bufnr --- @type integer?

View File

@ -2279,9 +2279,9 @@ end
--- Perform filetype detection.
---
--- The filetype can be detected using one of three methods:
--- 1. Using an existing buffer
--- 2. Using only a file name
--- 3. Using only file contents
--- 1. Using an existing buffer
--- 2. Using only a file name
--- 3. Using only file contents
---
--- Of these, option 1 provides the most accurate result as it uses both the buffer's filename and
--- (optionally) the buffer contents. Options 2 and 3 can be used without an existing buffer, but

View File

@ -320,7 +320,7 @@ end
--- Normalize a path to a standard format. A tilde (~) character at the
--- beginning of the path is expanded to the user's home directory and any
--- backslash (\\) characters are converted to forward slashes (/). Environment
--- backslash (\) characters are converted to forward slashes (/). Environment
--- variables are also expanded.
---
--- Examples:

View File

@ -1,4 +1,4 @@
---@defgroup vim.highlight
---@brief
---
--- Nvim includes a function for highlighting a selection on yank.
---
@ -19,18 +19,19 @@
--- ```vim
--- au TextYankPost * silent! lua vim.highlight.on_yank {on_visual=false}
--- ```
---
local api = vim.api
local M = {}
--- Table with default priorities used for highlighting:
--- - `syntax`: `50`, used for standard syntax highlighting
--- - `treesitter`: `100`, used for treesitter-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
--- - `syntax`: `50`, used for standard syntax highlighting
--- - `treesitter`: `100`, used for treesitter-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
M.priorities = {
syntax = 50,
treesitter = 100,

View File

@ -1,4 +1,4 @@
---@defgroup vim.iter
--- @brief
---
--- \*vim.iter()\* is an interface for |iterable|s: it wraps a table or function argument into an
--- \*Iter\* object with methods (such as |Iter:filter()| and |Iter:map()|) that transform the
@ -66,6 +66,7 @@
---@class IterMod
---@operator call:Iter
local M = {}
---@class Iter
@ -599,7 +600,7 @@ end
--- -- 12
---
--- ```
---
---@param f any
---@return any
function Iter.find(self, f)
if type(f) ~= 'function' then
@ -645,6 +646,7 @@ end
---
---@see Iter.find
---
---@param f any
---@return any
---@diagnostic disable-next-line: unused-local
function Iter.rfind(self, f) -- luacheck: no unused args
@ -724,6 +726,7 @@ function Iter.nextback(self) -- luacheck: no unused args
error('nextback() requires a list-like table')
end
--- @nodoc
function ListIter.nextback(self)
if self._head ~= self._tail then
local inc = self._head < self._tail and 1 or -1
@ -754,6 +757,7 @@ function Iter.peekback(self) -- luacheck: no unused args
error('peekback() requires a list-like table')
end
---@nodoc
function ListIter.peekback(self)
if self._head ~= self._tail then
local inc = self._head < self._tail and 1 or -1

View File

@ -90,6 +90,8 @@ end
--- vim.keymap.del({'n', 'i', 'v'}, '<leader>w', { buffer = 5 })
--- ```
---
---@param modes string|string[]
---@param lhs string
---@param opts table|nil A table of optional arguments:
--- - "buffer": (integer|boolean) Remove a mapping from the given buffer.
--- When `0` or `true`, use the current buffer.

View File

@ -190,7 +190,6 @@ function Loader.loader_lib(modname)
local sysname = uv.os_uname().sysname:lower() or ''
local is_win = sysname:find('win', 1, true) and not sysname:find('darwin', 1, true)
local ret = M.find(modname, { patterns = is_win and { '.dll' } or { '.so' } })[1]
---@type function?, string?
if ret then
-- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is
-- a) strip prefix up to and including the first dash, if any
@ -208,15 +207,13 @@ end
--- `loadfile` using the cache
--- Note this has the mode and env arguments which is supported by LuaJIT and is 5.1 compatible.
---@param filename? string
---@param mode? "b"|"t"|"bt"
---@param _mode? "b"|"t"|"bt"
---@param env? table
---@return function?, string? error_message
---@private
-- luacheck: ignore 312
function Loader.loadfile(filename, mode, env)
function Loader.loadfile(filename, _mode, env)
-- ignore mode, since we byte-compile the Lua source files
mode = nil
return Loader.load(normalize(filename), { mode = mode, env = env })
return Loader.load(normalize(filename), { env = env })
end
--- Checks whether two cache hashes are the same based on:
@ -273,14 +270,14 @@ end
--- Finds Lua modules for the given module name.
---@param modname string Module name, or `"*"` to find the top-level modules instead
---@param opts? ModuleFindOpts (table|nil) Options for finding a module:
---@param opts? ModuleFindOpts (table) Options for finding a module:
--- - rtp: (boolean) Search for modname in the runtime path (defaults to `true`)
--- - paths: (string[]) Extra paths to search for modname (defaults to `{}`)
--- - patterns: (string[]) List of patterns to use when searching for modules.
--- A pattern is a string added to the basename of the Lua module being searched.
--- (defaults to `{"/init.lua", ".lua"}`)
--- - all: (boolean) Return all matches instead of just the first one (defaults to `false`)
---@return ModuleInfo[] (list) A list of results with the following properties:
---@return ModuleInfo[] (table) A list of results with the following properties:
--- - modpath: (string) the path to the module
--- - modname: (string) the name of the module
--- - stat: (table|nil) the fs_stat of the module path. Won't be returned for `modname="*"`

View File

@ -206,99 +206,96 @@ end
--- |vim.lsp.get_client_by_id()| or |vim.lsp.get_clients()|.
---
--- - Methods:
--- - request(method, params, [handler], bufnr)
--- Sends a request to the server.
--- This is a thin wrapper around {client.rpc.request} with some additional
--- checking.
--- If {handler} is not specified, If one is not found there, then an error will occur.
--- Returns: {status}, {[client_id]}. {status} is a boolean indicating if
--- the notification was successful. If it is `false`, then it will always
--- be `false` (the client has shutdown).
--- If {status} is `true`, the function returns {request_id} as the second
--- result. You can use this with `client.cancel_request(request_id)`
--- to cancel the request.
---
--- - request(method, params, [handler], bufnr)
--- Sends a request to the server.
--- This is a thin wrapper around {client.rpc.request} with some additional
--- checking.
--- If {handler} is not specified, If one is not found there, then an error will occur.
--- Returns: {status}, {[client_id]}. {status} is a boolean indicating if
--- the notification was successful. If it is `false`, then it will always
--- be `false` (the client has shutdown).
--- If {status} is `true`, the function returns {request_id} as the second
--- result. You can use this with `client.cancel_request(request_id)`
--- to cancel the request.
--- - request_sync(method, params, timeout_ms, bufnr)
--- Sends a request to the server and synchronously waits for the response.
--- This is a wrapper around {client.request}
--- Returns: { err=err, result=result }, a dictionary, where `err` and `result` come from
--- the |lsp-handler|. On timeout, cancel or error, returns `(nil, err)` where `err` is a
--- string describing the failure reason. If the request was unsuccessful returns `nil`.
---
--- - request_sync(method, params, timeout_ms, bufnr)
--- Sends a request to the server and synchronously waits for the response.
--- This is a wrapper around {client.request}
--- Returns: { err=err, result=result }, a dictionary, where `err` and `result` come from
--- the |lsp-handler|. On timeout, cancel or error, returns `(nil, err)` where `err` is a
--- string describing the failure reason. If the request was unsuccessful returns `nil`.
--- - notify(method, params)
--- Sends a notification to an LSP server.
--- Returns: a boolean to indicate if the notification was successful. If
--- it is false, then it will always be false (the client has shutdown).
---
--- - notify(method, params)
--- Sends a notification to an LSP server.
--- Returns: a boolean to indicate if the notification was successful. If
--- it is false, then it will always be false (the client has shutdown).
--- - cancel_request(id)
--- Cancels a request with a given request id.
--- Returns: same as `notify()`.
---
--- - cancel_request(id)
--- Cancels a request with a given request id.
--- Returns: same as `notify()`.
--- - stop([force])
--- Stops a client, optionally with force.
--- By default, it will just ask the server to shutdown without force.
--- If you request to stop a client which has previously been requested to
--- shutdown, it will automatically escalate and force shutdown.
---
--- - stop([force])
--- Stops a client, optionally with force.
--- By default, it will just ask the server to shutdown without force.
--- If you request to stop a client which has previously been requested to
--- shutdown, it will automatically escalate and force shutdown.
--- - is_stopped()
--- Checks whether a client is stopped.
--- Returns: true if the client is fully stopped.
---
--- - is_stopped()
--- Checks whether a client is stopped.
--- Returns: true if the client is fully stopped.
--- - on_attach(client, bufnr)
--- Runs the on_attach function from the client's config if it was defined.
--- Useful for buffer-local setup.
---
--- - on_attach(client, bufnr)
--- Runs the on_attach function from the client's config if it was defined.
--- Useful for buffer-local setup.
---
--- - supports_method(method, [opts]): boolean
--- Checks if a client supports a given method.
--- Always returns true for unknown off-spec methods.
--- [opts] is a optional `{bufnr?: integer}` table.
--- Some language server capabilities can be file specific.
--- - supports_method(method, [opts]): boolean
--- Checks if a client supports a given method.
--- Always returns true for unknown off-spec methods.
--- [opts] is a optional `{bufnr?: integer}` table.
--- Some language server capabilities can be file specific.
---
--- - Members
--- - {id} (number): The id allocated to the client.
--- - {id} (number): The id allocated to the client.
---
--- - {name} (string): If a name is specified on creation, that will be
--- used. Otherwise it is just the client id. This is used for
--- logs and messages.
--- - {name} (string): If a name is specified on creation, that will be
--- used. Otherwise it is just the client id. This is used for
--- logs and messages.
---
--- - {rpc} (table): RPC client object, for low level interaction with the
--- client. See |vim.lsp.rpc.start()|.
--- - {rpc} (table): RPC client object, for low level interaction with the
--- client. See |vim.lsp.rpc.start()|.
---
--- - {offset_encoding} (string): The encoding used for communicating
--- with the server. You can modify this in the `config`'s `on_init` method
--- before text is sent to the server.
--- - {offset_encoding} (string): The encoding used for communicating
--- with the server. You can modify this in the `config`'s `on_init` method
--- before text is sent to the server.
---
--- - {handlers} (table): The handlers used by the client as described in |lsp-handler|.
--- - {handlers} (table): The handlers used by the client as described in |lsp-handler|.
---
--- - {commands} (table): Table of command name to function which is called if
--- any LSP action (code action, code lenses, ...) triggers the command.
--- Client commands take precedence over the global command registry.
--- - {commands} (table): Table of command name to function which is called if
--- any LSP action (code action, code lenses, ...) triggers the command.
--- Client commands take precedence over the global command registry.
---
--- - {requests} (table): The current pending requests in flight
--- to the server. Entries are key-value pairs with the key
--- being the request ID while the value is a table with `type`,
--- `bufnr`, and `method` key-value pairs. `type` is either "pending"
--- for an active request, or "cancel" for a cancel request. It will
--- be "complete" ephemerally while executing |LspRequest| autocmds
--- when replies are received from the server.
--- - {requests} (table): The current pending requests in flight
--- to the server. Entries are key-value pairs with the key
--- being the request ID while the value is a table with `type`,
--- `bufnr`, and `method` key-value pairs. `type` is either "pending"
--- for an active request, or "cancel" for a cancel request. It will
--- be "complete" ephemerally while executing |LspRequest| autocmds
--- when replies are received from the server.
---
--- - {config} (table): Reference of the table that was passed by the user
--- to |vim.lsp.start_client()|.
--- - {config} (table): Reference of the table that was passed by the user
--- to |vim.lsp.start_client()|.
---
--- - {server_capabilities} (table): Response from the server sent on
--- `initialize` describing the server's capabilities.
--- - {server_capabilities} (table): Response from the server sent on
--- `initialize` describing the server's capabilities.
---
--- - {progress} A ring buffer (|vim.ringbuf()|) containing progress messages
--- sent by the server.
--- - {progress} A ring buffer (|vim.ringbuf()|) containing progress messages
--- sent by the server.
---
--- - {settings} Map with language server specific settings.
--- See {config} in |vim.lsp.start_client()|
--- - {settings} Map with language server specific settings.
--- See {config} in |vim.lsp.start_client()|
---
--- - {flags} A table with flags for the client. See {config} in |vim.lsp.start_client()|
function lsp.client()
error()
end
--- - {flags} A table with flags for the client. See {config} in |vim.lsp.start_client()|
lsp.client = nil
--- @class lsp.StartOpts
--- @field reuse_client fun(client: lsp.Client, config: table): boolean
@ -581,9 +578,9 @@ end
--- spawn. Must be specified using a table.
--- Non-string values are coerced to string.
--- Example:
--- <pre>
--- { PORT = 8080; HOST = "0.0.0.0"; }
--- </pre>
--- ```
--- { PORT = 8080; HOST = "0.0.0.0"; }
--- ```
---
--- - detached: (boolean, default true) Daemonize the server process so that it runs in a
--- separate process group from Nvim. Nvim will shutdown the process on exit, but if Nvim fails to
@ -598,8 +595,9 @@ end
--- \|vim.lsp.protocol.make_client_capabilities()|, passed to the language
--- server on initialization. Hint: use make_client_capabilities() and modify
--- its result.
--- - Note: To send an empty dictionary use |vim.empty_dict()|, else it will be encoded as an
--- array.
---
--- - Note: To send an empty dictionary use |vim.empty_dict()|, else it will be encoded as an
--- array.
---
--- - handlers: Map of language server method names to |lsp-handler|
---
@ -645,9 +643,9 @@ end
---
--- - on_exit Callback (code, signal, client_id) invoked on client
--- exit.
--- - code: exit code of the process
--- - signal: number describing the signal used to terminate (if any)
--- - client_id: client handle
--- - code: exit code of the process
--- - signal: number describing the signal used to terminate (if any)
--- - client_id: client handle
---
--- - on_attach: Callback (client, bufnr) invoked when client
--- attaches to a buffer.
@ -656,13 +654,13 @@ end
--- server in the initialize request. Invalid/empty values will default to "off"
---
--- - flags: A table with flags for the client. The current (experimental) flags are:
--- - allow_incremental_sync (bool, default true): Allow using incremental sync for buffer edits
--- - debounce_text_changes (number, default 150): Debounce didChange
--- notifications to the server by the given number in milliseconds. No debounce
--- occurs if nil
--- - exit_timeout (number|boolean, default false): Milliseconds to wait for server to
--- exit cleanly after sending the "shutdown" request before sending kill -15.
--- If set to false, nvim exits immediately after sending the "shutdown" request to the server.
--- - allow_incremental_sync (bool, default true): Allow using incremental sync for buffer edits
--- - debounce_text_changes (number, default 150): Debounce didChange
--- notifications to the server by the given number in milliseconds. No debounce
--- occurs if nil
--- - exit_timeout (number|boolean, default false): Milliseconds to wait for server to
--- exit cleanly after sending the "shutdown" request before sending kill -15.
--- If set to false, nvim exits immediately after sending the "shutdown" request to the server.
---
--- - root_dir: (string) Directory where the LSP
--- server will base its workspaceFolders, rootUri, and rootPath
@ -1239,7 +1237,7 @@ end
---
--- Currently only supports a single client. This can be set via
--- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` but will typically or in `on_attach`
--- via ``vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})'``.
--- via `vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})'`.
---
---@param opts table options for customizing the formatting expression which takes the
--- following optional keys:

View File

@ -12,7 +12,7 @@ local M = {}
---@param method (string) LSP method name
---@param params (table|nil) Parameters to send to the server
---@param handler (function|nil) See |lsp-handler|. Follows |lsp-handler-resolution|
--
---
---@return table<integer, integer> client_request_ids Map of client-id:request-id pairs
---for all successful requests.
---@return function _cancel_all_requests Function which can be used to
@ -172,12 +172,13 @@ end
---
--- - filter (function|nil):
--- Predicate used to filter clients. Receives a client as argument and must return a
--- boolean. Clients matching the predicate are included. Example: <pre>lua
--- -- Never request typescript-language-server for formatting
--- vim.lsp.buf.format {
--- filter = function(client) return client.name ~= "tsserver" end
--- }
--- </pre>
--- boolean. Clients matching the predicate are included. Example:
--- ```lua
--- -- Never request typescript-language-server for formatting
--- vim.lsp.buf.format {
--- filter = function(client) return client.name ~= "tsserver" end
--- }
--- ```
---
--- - async boolean|nil
--- If true the method won't block. Defaults to false.
@ -472,6 +473,7 @@ end
--- Add the folder at path to the workspace folders. If {path} is
--- not provided, the user will be prompted for a path using |input()|.
--- @param workspace_folder? string
function M.add_workspace_folder(workspace_folder)
workspace_folder = workspace_folder
or npcall(vim.fn.input, 'Workspace Folder: ', vim.fn.expand('%:p:h'), 'dir')
@ -511,6 +513,7 @@ end
--- Remove the folder at path from the workspace folders. If
--- {path} is not provided, the user will be prompted for
--- a path using |input()|.
--- @param workspace_folder? string
function M.remove_workspace_folder(workspace_folder)
workspace_folder = workspace_folder
or npcall(vim.fn.input, 'Workspace Folder: ', vim.fn.expand('%:p:h'))
@ -725,15 +728,15 @@ end
---
---@param options table|nil Optional table which holds the following optional fields:
--- - context: (table|nil)
--- Corresponds to `CodeActionContext` of the LSP specification:
--- - diagnostics (table|nil):
--- LSP `Diagnostic[]`. Inferred from the current
--- position if not provided.
--- - only (table|nil):
--- List of LSP `CodeActionKind`s used to filter the code actions.
--- Most language servers support values like `refactor`
--- or `quickfix`.
--- - triggerKind (number|nil): The reason why code actions were requested.
--- Corresponds to `CodeActionContext` of the LSP specification:
--- - diagnostics (table|nil):
--- LSP `Diagnostic[]`. Inferred from the current
--- position if not provided.
--- - only (table|nil):
--- List of LSP `CodeActionKind`s used to filter the code actions.
--- Most language servers support values like `refactor`
--- or `quickfix`.
--- - triggerKind (number|nil): The reason why code actions were requested.
--- - filter: (function|nil)
--- Predicate taking an `CodeAction` and returning a boolean.
--- - apply: (boolean|nil)

View File

@ -258,6 +258,8 @@ end
--- |lsp-handler| for the method `textDocument/codeLens`
---
---@param err lsp.ResponseError?
---@param result lsp.CodeLens[]
---@param ctx lsp.HandlerContext
function M.on_codelens(err, result, ctx, _)
if err then

View File

@ -1,5 +1,3 @@
---@brief lsp-diagnostic
local protocol = require('vim.lsp.protocol')
local ms = protocol.Methods
@ -287,6 +285,7 @@ end
--- )
--- ```
---
---@param _ lsp.ResponseError?
---@param result lsp.PublishDiagnosticsParams
---@param ctx lsp.HandlerContext
---@param config? vim.diagnostic.Opts Configuration table (see |vim.diagnostic.config()|).
@ -319,6 +318,7 @@ end
--- )
--- ```
---
---@param _ lsp.ResponseError?
---@param result lsp.DocumentDiagnosticReport
---@param ctx lsp.HandlerContext
---@param config table Configuration table (see |vim.diagnostic.config()|).

View File

@ -368,6 +368,8 @@ end
--- )
--- ```
---
---@param _ lsp.ResponseError?
---@param result lsp.Hover
---@param ctx lsp.HandlerContext
---@param config table Configuration table.
--- - border: (default=nil)
@ -464,7 +466,8 @@ M[ms.textDocument_implementation] = location_handler
--- )
--- ```
---
---@param result table Response from the language server
---@param _ lsp.ResponseError?
---@param result lsp.SignatureHelp Response from the language server
---@param ctx lsp.HandlerContext Client context
---@param config table Configuration table.
--- - border: (default=nil)

View File

@ -165,7 +165,7 @@ end
--- Checks whether the level is sufficient for logging.
---@param level integer log level
---@returns (bool) true if would log, false if not
---@return bool : true if would log, false if not
function log.should_log(level)
return level >= current_log_level
end

View File

@ -273,8 +273,6 @@ end
---@field notify_reply_callbacks table<integer, function> dict of message_id to callback
---@field transport vim.lsp.rpc.Transport
---@field dispatchers vim.lsp.rpc.Dispatchers
---@class vim.lsp.rpc.Client
local Client = {}
---@private

View File

@ -53,7 +53,7 @@ local str_utf_end = vim.str_utf_end
---@param line string the line to index into
---@param byte integer the byte idx
---@param offset_encoding string utf-8|utf-16|utf-32|nil (default: utf-8)
--@returns integer the utf idx for the given encoding
---@return integer utf_idx for the given encoding
local function byte_to_utf(line, byte, offset_encoding)
-- convert to 0 based indexing for str_utfindex
byte = byte - 1
@ -204,7 +204,7 @@ end
--- Normalized to the next codepoint.
--- prev_end_range is the text range sent to the server representing the changed region.
--- curr_end_range is the text that should be collected and sent to the server.
--
---
---@param prev_lines string[] list of lines
---@param curr_lines string[] list of lines
---@param start_range vim.lsp.sync.Range

View File

@ -574,6 +574,7 @@ end
---
---@param text_document_edit table: a `TextDocumentEdit` object
---@param index integer: Optional index of the edit, if from a list of edits (or nil, if not from a list)
---@param offset_encoding? string
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
function M.apply_text_document_edit(text_document_edit, index, offset_encoding)
local text_document = text_document_edit.textDocument
@ -770,7 +771,7 @@ end
---
---@param workspace_edit table `WorkspaceEdit`
---@param offset_encoding string utf-8|utf-16|utf-32 (required)
--see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit, offset_encoding)
if offset_encoding == nil then
vim.notify_once(
@ -1130,6 +1131,7 @@ end
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
---@param location table a single `Location` or `LocationLink`
---@param opts table
---@return integer|nil buffer id of float window
---@return integer|nil window id of float window
function M.preview_location(location, opts)
@ -1243,6 +1245,7 @@ end
---
--- If you want to open a popup with fancy markdown, use `open_floating_preview` instead
---
---@param bufnr integer
---@param contents table of lines to show in window
---@param opts table with optional fields
--- - height of floating window
@ -1603,7 +1606,7 @@ end
---@param contents table of lines to show in window
---@param syntax string of syntax to set for opened buffer
---@param opts table with optional fields (additional keys are filtered with |vim.lsp.util.make_floating_popup_options()|
--- before they are passed on to |nvim_open_win()|)
--- before they are passed on to |nvim_open_win()|)
--- - height: (integer) height of floating window
--- - width: (integer) width of floating window
--- - wrap: (boolean, default true) wrap long lines
@ -1868,6 +1871,7 @@ end
--- Converts symbols to quickfix list items.
---
---@param symbols table DocumentSymbol[] or SymbolInformation[]
---@param bufnr integer
function M.symbols_to_items(symbols, bufnr)
local function _symbols_to_items(_symbols, _items, _bufnr)
for _, symbol in ipairs(_symbols) do

View File

@ -6,6 +6,7 @@
-- or the test suite. (Eventually the test suite will be run in a worker process,
-- so this wouldn't be a separate case to consider)
---@nodoc
---@diagnostic disable-next-line: lowercase-global
vim = vim or {}
@ -191,8 +192,8 @@ end
---
---@param s string String to split
---@param sep string Separator or pattern
---@param opts (table|nil) Keyword arguments |kwargs| accepted by |vim.gsplit()|
---@return string[] List of split components
---@param opts? table Keyword arguments |kwargs| accepted by |vim.gsplit()|
---@return string[] : List of split components
function vim.split(s, sep, opts)
local t = {}
for c in vim.gsplit(s, sep, opts) do
@ -206,9 +207,9 @@ end
---
---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
---@generic T: table
---@generic T
---@param t table<T, any> (table) Table
---@return T[] (list) List of keys
---@return T[] : List of keys
function vim.tbl_keys(t)
vim.validate({ t = { t, 't' } })
--- @cast t table<any,any>
@ -225,7 +226,7 @@ end
---
---@generic T
---@param t table<any, T> (table) Table
---@return T[] (list) List of values
---@return T[] : List of values
function vim.tbl_values(t)
vim.validate({ t = { t, 't' } })
@ -243,7 +244,7 @@ end
---@generic T
---@param func fun(value: T): any (function) Function
---@param t table<any, T> (table) Table
---@return table Table of transformed values
---@return table : Table of transformed values
function vim.tbl_map(func, t)
vim.validate({ func = { func, 'c' }, t = { t, 't' } })
--- @cast t table<any,any>
@ -260,7 +261,7 @@ end
---@generic T
---@param func fun(value: T): boolean (function) Function
---@param t table<any, T> (table) Table
---@return T[] (table) Table of filtered values
---@return T[] : Table of filtered values
function vim.tbl_filter(func, t)
vim.validate({ func = { func, 'c' }, t = { t, 't' } })
--- @cast t table<any,any>
@ -401,7 +402,7 @@ end
--- - "keep": use value from the leftmost map
--- - "force": use value from the rightmost map
---@param ... table Two or more tables
---@return table Merged table
---@return table : Merged table
function vim.tbl_extend(behavior, ...)
return tbl_extend(behavior, false, ...)
end
@ -456,7 +457,7 @@ end
--- Add the reverse lookup values to an existing table.
--- For example:
--- ``tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }``
--- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`
---
--- Note that this *modifies* the input.
---@param o table Table to add the reverse to
@ -493,7 +494,7 @@ end
---
---@param o table Table to index
---@param ... any Optional keys (0 or more, variadic) via which to index the table
---@return any Nested value indexed by key (if it exists), else nil
---@return any : Nested value indexed by key (if it exists), else nil
function vim.tbl_get(o, ...)
local keys = { ... }
if #keys == 0 then
@ -519,8 +520,8 @@ end
---@generic T: table
---@param dst T List which will be modified and appended to
---@param src table List from which values will be inserted
---@param start (integer|nil) Start index on src. Defaults to 1
---@param finish (integer|nil) Final index on src. Defaults to `#src`
---@param start integer? Start index on src. Defaults to 1
---@param finish integer? Final index on src. Defaults to `#src`
---@return T dst
function vim.list_extend(dst, src, start, finish)
vim.validate({
@ -666,7 +667,7 @@ end
---
---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua
---@param t table Table
---@return integer Number of non-nil values in table
---@return integer : Number of non-nil values in table
function vim.tbl_count(t)
vim.validate({ t = { t, 't' } })
--- @cast t table<any,any>
@ -681,10 +682,10 @@ end
--- Creates a copy of a table containing only elements from start to end (inclusive)
---
---@generic T
---@param list T[] (list) Table
---@param list T[] Table
---@param start integer|nil Start range of slice
---@param finish integer|nil End range of slice
---@return T[] (list) Copy of table sliced from start to finish (inclusive)
---@return T[] Copy of table sliced from start to finish (inclusive)
function vim.list_slice(list, start, finish)
local new_list = {} --- @type `T`[]
for i = start or 1, finish or #list do
@ -840,38 +841,37 @@ do
--- Usage example:
---
--- ```lua
--- function user.new(name, age, hobbies)
--- vim.validate{
--- name={name, 'string'},
--- age={age, 'number'},
--- hobbies={hobbies, 'table'},
--- }
--- ...
--- end
--- function user.new(name, age, hobbies)
--- vim.validate{
--- name={name, 'string'},
--- age={age, 'number'},
--- hobbies={hobbies, 'table'},
--- }
--- ...
--- end
--- ```
---
--- Examples with explicit argument values (can be run directly):
---
--- ```lua
--- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
--- --> NOP (success)
--- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
--- --> NOP (success)
---
--- vim.validate{arg1={1, 'table'}}
--- --> error('arg1: expected table, got number')
--- vim.validate{arg1={1, 'table'}}
--- --> error('arg1: expected table, got number')
---
--- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
--- --> error('arg1: expected even number, got 3')
--- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
--- --> error('arg1: expected even number, got 3')
--- ```
---
--- If multiple types are valid they can be given as a list.
---
--- ```lua
--- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}}
--- -- NOP (success)
---
--- vim.validate{arg1={1, {'string', 'table'}}}
--- -- error('arg1: expected string|table, got number')
--- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}}
--- -- NOP (success)
---
--- vim.validate{arg1={1, {'string', 'table'}}}
--- -- error('arg1: expected string|table, got number')
--- ```
---
---@param opt table<vim.validate.Type,vim.validate.Spec> (table) Names of parameters to validate. Each key is a parameter
@ -989,19 +989,19 @@ do
--- Once the buffer is full, adding a new entry overrides the oldest entry.
---
--- ```lua
--- local ringbuf = vim.ringbuf(4)
--- ringbuf:push("a")
--- ringbuf:push("b")
--- ringbuf:push("c")
--- ringbuf:push("d")
--- ringbuf:push("e") -- overrides "a"
--- print(ringbuf:pop()) -- returns "b"
--- print(ringbuf:pop()) -- returns "c"
--- local ringbuf = vim.ringbuf(4)
--- ringbuf:push("a")
--- ringbuf:push("b")
--- ringbuf:push("c")
--- ringbuf:push("d")
--- ringbuf:push("e") -- overrides "a"
--- print(ringbuf:pop()) -- returns "b"
--- print(ringbuf:pop()) -- returns "c"
---
--- -- Can be used as iterator. Pops remaining items:
--- for val in ringbuf do
--- print(val)
--- end
--- -- Can be used as iterator. Pops remaining items:
--- for val in ringbuf do
--- print(val)
--- end
--- ```
---
--- Returns a Ringbuf instance with the following methods:

View File

@ -245,8 +245,6 @@ function Session:set_group_gravity(index, right_gravity)
end
end
--- @class vim.snippet.Snippet
--- @field private _session? vim.snippet.Session
local M = { session = nil }
--- Displays the choices for the given tabstop as completion items.

View File

@ -432,7 +432,7 @@ end
--- Can be used in an ftplugin or FileType autocommand.
---
--- Note: By default, disables regex syntax highlighting, which may be required for some plugins.
--- In this case, add ``vim.bo.syntax = 'on'`` after the call to `start`.
--- In this case, add `vim.bo.syntax = 'on'` after the call to `start`.
---
--- Example:
---

View File

@ -197,7 +197,7 @@ function M.clear(buf)
end
--- @private
--- @param findstart integer
--- @param findstart 0|1
--- @param base string
function M.omnifunc(findstart, base)
if findstart == 1 then

View File

@ -231,7 +231,6 @@ function TSHighlighter:on_changedtree(changes)
end
--- Gets the query used for @param lang
--
---@package
---@param lang string Language used by the highlighter.
---@return vim.treesitter.highlighter.Query

View File

@ -1,5 +1,3 @@
--- @defgroup lua-treesitter-languagetree
---
--- @brief A \*LanguageTree\* contains a tree of parsers: the root treesitter parser for {lang} and
--- any "injected" language parsers, which themselves may inject other languages, recursively.
--- For example a Lua buffer containing some Vimscript commands needs multiple parsers to fully
@ -433,7 +431,7 @@ function LanguageTree:parse(range)
local query_time = 0
local total_parse_time = 0
--- At least 1 region is invalid
-- At least 1 region is invalid
if not self:is_valid(true) then
changes, no_regions_parsed, total_parse_time = self:_parse_regions(range)
-- Need to run injections when we parsed something

View File

@ -231,7 +231,7 @@ end
---@param lang string Language to use for the query
---@param query_name string Name of the query (e.g. "highlights")
---
---@return vim.treesitter.Query|nil -- Parsed query. `nil` if no query files are found.
---@return vim.treesitter.Query|nil : Parsed query. `nil` if no query files are found.
M.get = vim.func._memoize('concat-2', function(lang, query_name)
if explicit_queries[lang][query_name] then
return explicit_queries[lang][query_name]
@ -1019,6 +1019,8 @@ end
--- vim.bo.omnifunc = 'v:lua.vim.treesitter.query.omnifunc'
--- ```
---
--- @param findstart 0|1
--- @param base string
function M.omnifunc(findstart, base)
return vim.treesitter._query_linter.omnifunc(findstart, base)
end

View File

@ -1,4 +1,4 @@
---TODO: This is implemented only for files currently.
-- TODO: This is implemented only for files currently.
-- https://tools.ietf.org/html/rfc3986
-- https://tools.ietf.org/html/rfc2732
-- https://tools.ietf.org/html/rfc2396
@ -116,7 +116,6 @@ end
---Gets the buffer for a uri.
---Creates a new unloaded buffer if no buffer for the uri already exists.
--
---@param uri string
---@return integer bufnr
function M.uri_to_bufnr(uri)

View File

@ -1,6 +1,5 @@
--- @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
--- available tools and dependencies on the current system.
---
@ -13,9 +12,9 @@
--- 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\*
--- VERSION RANGE SPEC *version-range*
---
--- A version "range spec" defines a semantic version range which can be tested against a version,
--- using |vim.version.range()|.

87
scripts/cdoc_grammar.lua Normal file
View File

@ -0,0 +1,87 @@
--[[!
LPEG grammar for C doc comments
]]
--- @class nvim.cdoc.Param
--- @field kind 'param'
--- @field name string
--- @field desc? string
--- @class nvim.cdoc.Return
--- @field kind 'return'
--- @field desc string
--- @class nvim.cdoc.Note
--- @field desc? string
--- @alias nvim.cdoc.grammar.result
--- | nvim.cdoc.Param
--- | nvim.cdoc.Return
--- | nvim.cdoc.Note
--- @class nvim.cdoc.grammar
--- @field match fun(self, input: string): nvim.cdoc.grammar.result?
local lpeg = vim.lpeg
local P, R, S = lpeg.P, lpeg.R, lpeg.S
local Ct, Cg = lpeg.Ct, lpeg.Cg
--- @param x vim.lpeg.Pattern
local function rep(x)
return x ^ 0
end
--- @param x vim.lpeg.Pattern
local function rep1(x)
return x ^ 1
end
--- @param x vim.lpeg.Pattern
local function opt(x)
return x ^ -1
end
local nl = P('\r\n') + P('\n')
local ws = rep1(S(' \t') + nl)
local any = P(1) -- (consume one character)
local letter = R('az', 'AZ') + S('_$')
local ident = letter * rep(letter + R('09'))
local io = P('[') * (P('in') + P('out') + P('inout')) * P(']')
--- @param x string
local function Pf(x)
return opt(ws) * P(x) * opt(ws)
end
--- @type table<string,vim.lpeg.Pattern>
local v = setmetatable({}, {
__index = function(_, k)
return lpeg.V(k)
end,
})
local grammar = P {
rep1(P('@') * v.ats),
ats = v.at_param + v.at_return + v.at_deprecated + v.at_see + v.at_brief + v.at_note + v.at_nodoc,
at_param = Ct(
Cg(P('param'), 'kind') * opt(io) * ws * Cg(ident, 'name') * opt(ws * Cg(rep(any), 'desc'))
),
at_return = Ct(Cg(P('return'), 'kind') * opt(S('s')) * opt(ws * Cg(rep(any), 'desc'))),
at_deprecated = Ct(Cg(P('deprecated'), 'kind')),
at_see = Ct(Cg(P('see'), 'kind') * ws * opt(Pf('#')) * Cg(rep(any), 'desc')),
at_brief = Ct(Cg(P('brief'), 'kind') * ws * Cg(rep(any), 'desc')),
at_note = Ct(Cg(P('note'), 'kind') * ws * Cg(rep(any), 'desc')),
at_nodoc = Ct(Cg(P('nodoc'), 'kind')),
}
return grammar --[[@as nvim.cdoc.grammar]]

223
scripts/cdoc_parser.lua Normal file
View File

@ -0,0 +1,223 @@
local cdoc_grammar = require('scripts.cdoc_grammar')
local c_grammar = require('src.nvim.generators.c_grammar')
--- @class nvim.cdoc.parser.param
--- @field name string
--- @field type string
--- @field desc string
--- @class nvim.cdoc.parser.return
--- @field name string
--- @field type string
--- @field desc string
--- @class nvim.cdoc.parser.note
--- @field desc string
--- @class nvim.cdoc.parser.brief
--- @field kind 'brief'
--- @field desc string
--- @class nvim.cdoc.parser.fun
--- @field name string
--- @field params nvim.cdoc.parser.param[]
--- @field returns nvim.cdoc.parser.return[]
--- @field desc string
--- @field deprecated? true
--- @field since? string
--- @field attrs? string[]
--- @field nodoc? true
--- @field notes? nvim.cdoc.parser.note[]
--- @field see? nvim.cdoc.parser.note[]
--- @class nvim.cdoc.parser.State
--- @field doc_lines? string[]
--- @field cur_obj? nvim.cdoc.parser.obj
--- @field last_doc_item? nvim.cdoc.parser.param|nvim.cdoc.parser.return|nvim.cdoc.parser.note
--- @field last_doc_item_indent? integer
--- @alias nvim.cdoc.parser.obj
--- | nvim.cdoc.parser.fun
--- | nvim.cdoc.parser.brief
--- If we collected any `---` lines. Add them to the existing (or new) object
--- Used for function/class descriptions and multiline param descriptions.
--- @param state nvim.cdoc.parser.State
local function add_doc_lines_to_obj(state)
if state.doc_lines then
state.cur_obj = state.cur_obj or {}
local cur_obj = assert(state.cur_obj)
local txt = table.concat(state.doc_lines, '\n')
if cur_obj.desc then
cur_obj.desc = cur_obj.desc .. '\n' .. txt
else
cur_obj.desc = txt
end
state.doc_lines = nil
end
end
--- @param line string
--- @param state nvim.cdoc.parser.State
local function process_doc_line(line, state)
line = line:gsub('^%s+@', '@')
local parsed = cdoc_grammar:match(line)
if not parsed then
if line:match('^ ') then
line = line:sub(2)
end
if state.last_doc_item then
if not state.last_doc_item_indent then
state.last_doc_item_indent = #line:match('^%s*') + 1
end
state.last_doc_item.desc = (state.last_doc_item.desc or '')
.. '\n'
.. line:sub(state.last_doc_item_indent or 1)
else
state.doc_lines = state.doc_lines or {}
table.insert(state.doc_lines, line)
end
return
end
state.last_doc_item_indent = nil
state.last_doc_item = nil
local kind = parsed.kind
state.cur_obj = state.cur_obj or {}
local cur_obj = assert(state.cur_obj)
if kind == 'brief' then
state.cur_obj = {
kind = 'brief',
desc = parsed.desc,
}
elseif kind == 'param' then
state.last_doc_item_indent = nil
cur_obj.params = cur_obj.params or {}
state.last_doc_item = {
name = parsed.name,
desc = parsed.desc,
}
table.insert(cur_obj.params, state.last_doc_item)
elseif kind == 'return' then
cur_obj.returns = { {
desc = parsed.desc,
} }
state.last_doc_item_indent = nil
state.last_doc_item = cur_obj.returns[1]
elseif kind == 'deprecated' then
cur_obj.deprecated = true
elseif kind == 'nodoc' then
cur_obj.nodoc = true
elseif kind == 'since' then
cur_obj.since = parsed.desc
elseif kind == 'see' then
cur_obj.see = cur_obj.see or {}
table.insert(cur_obj.see, { desc = parsed.desc })
elseif kind == 'note' then
state.last_doc_item_indent = nil
state.last_doc_item = {
desc = parsed.desc,
}
cur_obj.notes = cur_obj.notes or {}
table.insert(cur_obj.notes, state.last_doc_item)
else
error('Unhandled' .. vim.inspect(parsed))
end
end
--- @param item table
--- @param state nvim.cdoc.parser.State
local function process_proto(item, state)
state.cur_obj = state.cur_obj or {}
local cur_obj = assert(state.cur_obj)
cur_obj.name = item.name
cur_obj.params = cur_obj.params or {}
for _, p in ipairs(item.parameters) do
local param = { name = p[2], type = p[1] }
local added = false
for _, cp in ipairs(cur_obj.params) do
if cp.name == param.name then
cp.type = param.type
added = true
break
end
end
if not added then
table.insert(cur_obj.params, param)
end
end
cur_obj.returns = cur_obj.returns or { {} }
cur_obj.returns[1].type = item.return_type
for _, a in ipairs({
'fast',
'remote_only',
'lua_only',
'textlock',
'textlock_allow_cmdwin',
}) do
if item[a] then
cur_obj.attrs = cur_obj.attrs or {}
table.insert(cur_obj.attrs, a)
end
end
cur_obj.deprecated_since = item.deprecated_since
-- Remove some arguments
for i = #cur_obj.params, 1, -1 do
local p = cur_obj.params[i]
if p.name == 'channel_id' or vim.tbl_contains({ 'lstate', 'arena', 'error' }, p.type) then
table.remove(cur_obj.params, i)
end
end
end
local M = {}
--- @param filename string
--- @return {} classes
--- @return nvim.cdoc.parser.fun[] funs
--- @return string[] briefs
function M.parse(filename)
local funs = {} --- @type nvim.cdoc.parser.fun[]
local briefs = {} --- @type string[]
local state = {} --- @type nvim.cdoc.parser.State
local txt = assert(io.open(filename, 'r')):read('*all')
local parsed = c_grammar.grammar:match(txt)
for _, item in ipairs(parsed) do
if item.comment then
process_doc_line(item.comment, state)
else
add_doc_lines_to_obj(state)
if item[1] == 'proto' then
process_proto(item, state)
table.insert(funs, state.cur_obj)
end
local cur_obj = state.cur_obj
if cur_obj and not item.static then
if cur_obj.kind == 'brief' then
table.insert(briefs, cur_obj.desc)
end
end
state = {}
end
end
return {}, funs, briefs
end
-- M.parse('src/nvim/api/vim.c')
return M

View File

@ -3,7 +3,6 @@
-- Generator for various vimdoc and Lua type files
local DEP_API_METADATA = 'build/api_metadata.mpack'
local DEP_API_DOC = 'runtime/doc/api.mpack'
--- @class vim.api.metadata
--- @field name string
@ -210,44 +209,65 @@ end
--- @return table<string, vim.EvalFn>
local function get_api_meta()
local mpack_f = assert(io.open(DEP_API_METADATA, 'rb'))
local metadata = vim.mpack.decode(mpack_f:read('*all')) --[[@as vim.api.metadata[] ]]
local ret = {} --- @type table<string, vim.EvalFn>
local doc_mpack_f = assert(io.open(DEP_API_DOC, 'rb'))
local doc_metadata = vim.mpack.decode(doc_mpack_f:read('*all')) --[[@as table<string,vim.gen_vim_doc_fun>]]
local cdoc_parser = require('scripts.cdoc_parser')
for _, fun in ipairs(metadata) do
if fun.lua then
local fdoc = doc_metadata[fun.name]
local f = 'src/nvim/api'
local params = {} --- @type {[1]:string,[2]:string}[]
for _, p in ipairs(fun.parameters) do
local ptype, pname = p[1], p[2]
params[#params + 1] = {
pname,
api_type(ptype),
fdoc and fdoc.parameters_doc[pname] or nil,
}
end
local r = {
signature = 'NA',
name = fun.name,
params = params,
returns = api_type(fun.return_type),
deprecated = fun.deprecated_since ~= nil,
}
if fdoc then
if #fdoc.doc > 0 then
r.desc = table.concat(fdoc.doc, '\n')
end
r.return_desc = (fdoc['return'] or {})[1]
end
ret[fun.name] = r
local function include(fun)
if not vim.startswith(fun.name, 'nvim_') then
return false
end
if vim.tbl_contains(fun.attrs or {}, 'lua_only') then
return true
end
if vim.tbl_contains(fun.attrs or {}, 'remote_only') then
return false
end
return true
end
--- @type table<string,nvim.cdoc.parser.fun>
local functions = {}
for path, ty in vim.fs.dir(f) do
if ty == 'file' then
local filename = vim.fs.joinpath(f, path)
local _, funs = cdoc_parser.parse(filename)
for _, fn in ipairs(funs) do
if include(fn) then
functions[fn.name] = fn
end
end
end
end
for _, fun in pairs(functions) do
local deprecated = fun.deprecated_since ~= nil
local params = {} --- @type {[1]:string,[2]:string}[]
for _, p in ipairs(fun.params) do
params[#params + 1] = {
p.name,
api_type(p.type),
not deprecated and p.desc or nil,
}
end
local r = {
signature = 'NA',
name = fun.name,
params = params,
returns = api_type(fun.returns[1].type),
deprecated = deprecated,
}
if not deprecated then
r.desc = fun.desc
r.return_desc = fun.returns[1].desc
end
ret[fun.name] = r
end
return ret
end
@ -275,12 +295,10 @@ end
--- @param fun vim.EvalFn
--- @param write fun(line: string)
local function render_api_meta(_f, fun, write)
if not vim.startswith(fun.name, 'nvim_') then
return
end
write('')
local text_utils = require('scripts.text_utils')
if vim.startswith(fun.name, 'nvim__') then
write('--- @private')
end
@ -291,10 +309,10 @@ local function render_api_meta(_f, fun, write)
local desc = fun.desc
if desc then
desc = text_utils.md_to_vimdoc(desc, 0, 0, 74)
for _, l in ipairs(split(norm_text(desc))) do
write('--- ' .. l)
end
write('---')
end
local param_names = {} --- @type string[]
@ -303,8 +321,11 @@ local function render_api_meta(_f, fun, write)
param_names[#param_names + 1] = p[1]
local pdesc = p[3]
if pdesc then
local pdesc_a = split(norm_text(pdesc))
write('--- @param ' .. p[1] .. ' ' .. p[2] .. ' ' .. pdesc_a[1])
local s = '--- @param ' .. p[1] .. ' ' .. p[2] .. ' '
local indent = #('@param ' .. p[1] .. ' ')
pdesc = text_utils.md_to_vimdoc(pdesc, #s, indent, 74, true)
local pdesc_a = split(vim.trim(norm_text(pdesc)))
write(s .. pdesc_a[1])
for i = 2, #pdesc_a do
if not pdesc_a[i] then
break
@ -317,6 +338,7 @@ local function render_api_meta(_f, fun, write)
end
if fun.returns ~= '' then
local ret_desc = fun.returns_desc and ' : ' .. fun.returns_desc or ''
ret_desc = text_utils.md_to_vimdoc(ret_desc, 0, 0, 74)
local ret = LUA_API_RETURN_OVERRIDES[fun.name] or fun.returns
write('--- @return ' .. ret .. ret_desc)
end
@ -328,8 +350,6 @@ end
--- @return table<string, vim.EvalFn>
local function get_api_keysets_meta()
local mpack_f = assert(io.open(DEP_API_METADATA, 'rb'))
--- @diagnostic disable-next-line:no-unknown
local metadata = assert(vim.mpack.decode(mpack_f:read('*all')))
local ret = {} --- @type table<string, vim.EvalFn>

787
scripts/gen_vimdoc.lua Executable file
View File

@ -0,0 +1,787 @@
#!/usr/bin/env -S nvim -l
--- Generates Nvim :help docs from Lua/C docstrings
---
--- The generated :help text for each function is formatted as follows:
--- - Max width of 78 columns (`TEXT_WIDTH`).
--- - Indent with spaces (not tabs).
--- - Indent of 4 columns for body text (`INDENTATION`).
--- - Function signature and helptag (right-aligned) on the same line.
--- - Signature and helptag must have a minimum of 8 spaces between them.
--- - If the signature is too long, it is placed on the line after the helptag.
--- Signature wraps with subsequent lines indented to the open parenthesis.
--- - Subsection bodies are indented an additional 4 spaces.
--- - Body consists of function description, parameters, return description, and
--- C declaration (`INCLUDE_C_DECL`).
--- - Parameters are omitted for the `void` and `Error *` types, or if the
--- parameter is marked as [out].
--- - Each function documentation is separated by a single line.
local luacats_parser = require('scripts.luacats_parser')
local cdoc_parser = require('scripts.cdoc_parser')
local text_utils = require('scripts.text_utils')
local fmt = string.format
local wrap = text_utils.wrap
local md_to_vimdoc = text_utils.md_to_vimdoc
local TEXT_WIDTH = 78
local INDENTATION = 4
--- @class (exact) nvim.gen_vimdoc.Config
---
--- Generated documentation target, e.g. api.txt
--- @field filename string
---
--- @field section_order string[]
---
--- List of files/directories for doxygen to read, relative to `base_dir`.
--- @field files string[]
---
--- @field exclude_types? true
---
--- Section name overrides. Key: filename (e.g., vim.c)
--- @field section_name? table<string,string>
---
--- @field fn_name_pat? string
---
--- @field fn_xform? fun(fun: nvim.luacats.parser.fun)
---
--- For generated section names.
--- @field section_fmt fun(name: string): string
---
--- @field helptag_fmt fun(name: string): string
---
--- Per-function helptag.
--- @field fn_helptag_fmt? fun(fun: nvim.luacats.parser.fun): string
---
--- @field append_only? string[]
local function contains(t, xs)
return vim.tbl_contains(xs, t)
end
--- @type {level:integer, prerelease:boolean}?
local nvim_api_info_
--- @return {level: integer, prerelease:boolean}
local function nvim_api_info()
if not nvim_api_info_ then
--- @type integer?, boolean?
local level, prerelease
for l in io.lines('CMakeLists.txt') do
--- @cast l string
if level and prerelease then
break
end
local m1 = l:match('^set%(NVIM_API_LEVEL%s+(%d+)%)')
if m1 then
level = tonumber(m1) --[[@as integer]]
end
local m2 = l:match('^set%(NVIM_API_PRERELEASE%s+(%w+)%)')
if m2 then
prerelease = m2 == 'true'
end
end
nvim_api_info_ = { level = level, prerelease = prerelease }
end
return nvim_api_info_
end
--- @param fun nvim.luacats.parser.fun
--- @return string
local function fn_helptag_fmt_common(fun)
local fn_sfx = fun.table and '' or '()'
if fun.classvar then
return fmt('*%s:%s%s*', fun.classvar, fun.name, fn_sfx)
end
if fun.module then
return fmt('*%s.%s%s*', fun.module, fun.name, fn_sfx)
end
return fmt('*%s%s*', fun.name, fn_sfx)
end
--- @type table<string,nvim.gen_vimdoc.Config>
local config = {
api = {
filename = 'api.txt',
section_order = {
'vim.c',
'vimscript.c',
'command.c',
'options.c',
'buffer.c',
'extmark.c',
'window.c',
'win_config.c',
'tabpage.c',
'autocmd.c',
'ui.c',
},
exclude_types = true,
fn_name_pat = 'nvim_.*',
files = { 'src/nvim/api' },
section_name = {
['vim.c'] = 'Global',
},
section_fmt = function(name)
return name .. ' Functions'
end,
helptag_fmt = function(name)
return fmt('*api-%s*', name:lower())
end,
},
lua = {
filename = 'lua.txt',
section_order = {
'highlight.lua',
'diff.lua',
'mpack.lua',
'json.lua',
'base64.lua',
'spell.lua',
'builtin.lua',
'_options.lua',
'_editor.lua',
'_inspector.lua',
'shared.lua',
'loader.lua',
'uri.lua',
'ui.lua',
'filetype.lua',
'keymap.lua',
'fs.lua',
'glob.lua',
'lpeg.lua',
're.lua',
'regex.lua',
'secure.lua',
'version.lua',
'iter.lua',
'snippet.lua',
'text.lua',
},
files = {
'runtime/lua/vim/iter.lua',
'runtime/lua/vim/_editor.lua',
'runtime/lua/vim/_options.lua',
'runtime/lua/vim/shared.lua',
'runtime/lua/vim/loader.lua',
'runtime/lua/vim/uri.lua',
'runtime/lua/vim/ui.lua',
'runtime/lua/vim/filetype.lua',
'runtime/lua/vim/keymap.lua',
'runtime/lua/vim/fs.lua',
'runtime/lua/vim/highlight.lua',
'runtime/lua/vim/secure.lua',
'runtime/lua/vim/version.lua',
'runtime/lua/vim/_inspector.lua',
'runtime/lua/vim/snippet.lua',
'runtime/lua/vim/text.lua',
'runtime/lua/vim/glob.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/base64.lua',
'runtime/lua/vim/_meta/regex.lua',
'runtime/lua/vim/_meta/lpeg.lua',
'runtime/lua/vim/_meta/re.lua',
'runtime/lua/vim/_meta/spell.lua',
},
fn_xform = function(fun)
if contains(fun.module, { 'vim.uri', 'vim.shared', 'vim._editor' }) then
fun.module = 'vim'
end
if fun.module == 'vim' and contains(fun.name, { 'cmd', 'inspect' }) then
fun.table = nil
end
if fun.classvar or vim.startswith(fun.name, 'vim.') or fun.module == 'vim.iter' then
return
end
fun.name = fmt('%s.%s', fun.module, fun.name)
end,
section_name = {
['_inspector.lua'] = 'inspector',
},
section_fmt = function(name)
name = name:lower()
if name == '_editor' then
return 'Lua module: vim'
elseif name == '_options' then
return 'LUA-VIMSCRIPT BRIDGE'
elseif name == 'builtin' then
return 'VIM'
end
if
contains(name, {
'highlight',
'mpack',
'json',
'base64',
'diff',
'spell',
'regex',
'lpeg',
're',
})
then
return 'VIM.' .. name:upper()
end
return 'Lua module: vim.' .. name
end,
helptag_fmt = function(name)
if name == '_editor' then
return '*lua-vim*'
elseif name == '_options' then
return '*lua-vimscript*'
end
return '*vim.' .. name:lower() .. '*'
end,
fn_helptag_fmt = function(fun)
local name = fun.name
if vim.startswith(name, 'vim.') then
local fn_sfx = fun.table and '' or '()'
return fmt('*%s%s*', name, fn_sfx)
elseif fun.classvar == 'Option' then
return fmt('*vim.opt:%s()*', name)
end
return fn_helptag_fmt_common(fun)
end,
append_only = {
'shared.lua',
},
},
lsp = {
filename = 'lsp.txt',
section_order = {
'lsp.lua',
'buf.lua',
'diagnostic.lua',
'codelens.lua',
'inlay_hint.lua',
'tagfunc.lua',
'semantic_tokens.lua',
'handlers.lua',
'util.lua',
'log.lua',
'rpc.lua',
'protocol.lua',
},
files = {
'runtime/lua/vim/lsp',
'runtime/lua/vim/lsp.lua',
},
fn_xform = function(fun)
fun.name = fun.name:gsub('result%.', '')
end,
section_fmt = function(name)
if name:lower() == 'lsp' then
return 'Lua module: vim.lsp'
end
return 'Lua module: vim.lsp.' .. name:lower()
end,
helptag_fmt = function(name)
if name:lower() == 'lsp' then
return '*lsp-core*'
end
return fmt('*lsp-%s*', name:lower())
end,
},
diagnostic = {
filename = 'diagnostic.txt',
section_order = {
'diagnostic.lua',
},
files = { 'runtime/lua/vim/diagnostic.lua' },
section_fmt = function()
return 'Lua module: vim.diagnostic'
end,
helptag_fmt = function()
return '*diagnostic-api*'
end,
},
treesitter = {
filename = 'treesitter.txt',
section_order = {
'treesitter.lua',
'language.lua',
'query.lua',
'highlighter.lua',
'languagetree.lua',
'dev.lua',
},
files = {
'runtime/lua/vim/treesitter.lua',
'runtime/lua/vim/treesitter/',
},
section_fmt = function(name)
if name:lower() == 'treesitter' then
return 'Lua module: vim.treesitter'
end
return 'Lua module: vim.treesitter.' .. name:lower()
end,
helptag_fmt = function(name)
if name:lower() == 'treesitter' then
return '*lua-treesitter-core*'
end
return '*lua-treesitter-' .. name:lower() .. '*'
end,
},
}
--- @param ty string
--- @param generics table<string,string>
--- @return string
local function replace_generics(ty, generics)
if ty:sub(-2) == '[]' then
local ty0 = ty:sub(1, -3)
if generics[ty0] then
return generics[ty0] .. '[]'
end
elseif ty:sub(-1) == '?' then
local ty0 = ty:sub(1, -2)
if generics[ty0] then
return generics[ty0] .. '?'
end
end
return generics[ty] or ty
end
--- @param ty string
--- @param generics? table<string,string>
local function render_type(ty, generics)
if generics then
ty = replace_generics(ty, generics)
end
ty = ty:gsub('%s*|%s*nil', '?')
ty = ty:gsub('nil%s*|%s*(.*)', '%1?')
ty = ty:gsub('%s*|%s*', '|')
return fmt('(`%s`)', ty)
end
--- @param p nvim.luacats.parser.param|nvim.luacats.parser.field
local function should_render_param(p)
return not p.access and not contains(p.name, { '_', 'self' })
end
--- @param xs (nvim.luacats.parser.param|nvim.luacats.parser.field)[]
--- @param generics? table<string,string>
--- @param exclude_types? true
local function render_fields_or_params(xs, generics, exclude_types)
local ret = {} --- @type string[]
xs = vim.tbl_filter(should_render_param, xs)
local indent = 0
for _, p in ipairs(xs) do
if p.type or p.desc then
indent = math.max(indent, #p.name + 3)
end
if exclude_types then
p.type = nil
end
end
for _, p in ipairs(xs) do
local nm, ty = p.name, p.type
local desc = p.desc
local pnm = fmt(' • %-' .. indent .. 's', '{' .. nm .. '}')
if ty then
local pty = render_type(ty, generics)
if desc then
desc = fmt('%s %s', pty, desc)
table.insert(ret, pnm)
table.insert(ret, md_to_vimdoc(desc, 1, 9 + indent, TEXT_WIDTH, true))
else
table.insert(ret, fmt('%s %s\n', pnm, pty))
end
else
if desc then
table.insert(ret, pnm)
table.insert(ret, md_to_vimdoc(desc, 1, 9 + indent, TEXT_WIDTH, true))
end
end
end
return table.concat(ret)
end
-- --- @param class lua2vimdoc.class
-- local function render_class(class)
-- writeln(fmt('*%s*', class.name))
-- writeln()
-- if #class.fields > 0 then
-- writeln(' Fields: ~')
-- render_fields_or_params(class.fields)
-- end
-- writeln()
-- end
-- --- @param cls table<string,lua2vimdoc.class>
-- local function render_classes(cls)
-- --- @diagnostic disable-next-line:no-unknown
-- for _, class in vim.spairs(cls) do
-- render_class(class)
-- end
-- end
--- @param fun nvim.luacats.parser.fun
--- @param cfg nvim.gen_vimdoc.Config
local function render_fun_header(fun, cfg)
local ret = {} --- @type string[]
local args = {} --- @type string[]
for _, p in ipairs(fun.params or {}) do
if p.name ~= 'self' then
args[#args + 1] = fmt('{%s}', p.name:gsub('%?$', ''))
end
end
local nm = fun.name
if fun.classvar then
nm = fmt('%s:%s', fun.classvar, nm)
end
local proto = fun.table and nm or nm .. '(' .. table.concat(args, ', ') .. ')'
if not cfg.fn_helptag_fmt then
cfg.fn_helptag_fmt = fn_helptag_fmt_common
end
local tag = cfg.fn_helptag_fmt(fun)
if #proto + #tag > TEXT_WIDTH - 8 then
table.insert(ret, fmt('%78s\n', tag))
local name, pargs = proto:match('([^(]+%()(.*)')
table.insert(ret, name)
table.insert(ret, wrap(pargs, 0, #name, TEXT_WIDTH))
else
local pad = TEXT_WIDTH - #proto - #tag
table.insert(ret, proto .. string.rep(' ', pad) .. tag)
end
return table.concat(ret)
end
--- @param returns nvim.luacats.parser.return[]
--- @param generics? table<string,string>
--- @param exclude_types boolean
local function render_returns(returns, generics, exclude_types)
local ret = {} --- @type string[]
returns = vim.deepcopy(returns)
if exclude_types then
for _, r in ipairs(returns) do
r.type = nil
end
end
if #returns > 1 then
table.insert(ret, ' Return (multiple): ~\n')
elseif #returns == 1 and next(returns[1]) then
table.insert(ret, ' Return: ~\n')
end
for _, p in ipairs(returns) do
local rnm, ty, desc = p.name, p.type, p.desc
local blk = ''
if ty then
blk = render_type(ty, generics)
end
if rnm then
blk = blk .. ' ' .. rnm
end
if desc then
blk = blk .. ' ' .. desc
end
table.insert(ret, md_to_vimdoc(blk, 8, 8, TEXT_WIDTH, true))
end
return table.concat(ret)
end
--- @param fun nvim.luacats.parser.fun
--- @param cfg nvim.gen_vimdoc.Config
local function render_fun(fun, cfg)
if fun.access or fun.deprecated or fun.nodoc then
return
end
if cfg.fn_name_pat and not fun.name:match(cfg.fn_name_pat) then
return
end
if vim.startswith(fun.name, '_') or fun.name:find('[:.]_') then
return
end
local ret = {} --- @type string[]
table.insert(ret, render_fun_header(fun, cfg))
table.insert(ret, '\n')
if fun.desc then
table.insert(ret, md_to_vimdoc(fun.desc, INDENTATION, INDENTATION, TEXT_WIDTH))
end
if fun.since then
local since = tonumber(fun.since)
local info = nvim_api_info()
if since and (since > info.level or since == info.level and info.prerelease) then
fun.notes = fun.notes or {}
table.insert(fun.notes, { desc = 'This API is pre-release (unstable).' })
end
end
if fun.notes then
table.insert(ret, '\n Note: ~\n')
for _, p in ipairs(fun.notes) do
table.insert(ret, '' .. md_to_vimdoc(p.desc, 0, 8, TEXT_WIDTH, true))
end
end
if fun.attrs then
table.insert(ret, '\n Attributes: ~\n')
for _, attr in ipairs(fun.attrs) do
local attr_str = ({
textlock = 'not allowed when |textlock| is active or in the |cmdwin|',
textlock_allow_cmdwin = 'not allowed when |textlock| is active',
fast = '|api-fast|',
remote_only = '|RPC| only',
lua_only = 'Lua |vim.api| only',
})[attr] or attr
table.insert(ret, fmt(' %s\n', attr_str))
end
end
if fun.params and #fun.params > 0 then
local param_txt = render_fields_or_params(fun.params, fun.generics, cfg.exclude_types)
if not param_txt:match('^%s*$') then
table.insert(ret, '\n Parameters: ~\n')
ret[#ret + 1] = param_txt
end
end
if fun.returns then
local txt = render_returns(fun.returns, fun.generics, cfg.exclude_types)
if not txt:match('^%s*$') then
table.insert(ret, '\n')
ret[#ret + 1] = txt
end
end
if fun.see then
table.insert(ret, '\n See also: ~\n')
for _, p in ipairs(fun.see) do
table.insert(ret, '' .. md_to_vimdoc(p.desc, 0, 8, TEXT_WIDTH, true))
end
end
table.insert(ret, '\n')
return table.concat(ret)
end
--- @param funs nvim.luacats.parser.fun[]
--- @param cfg nvim.gen_vimdoc.Config
local function render_funs(funs, cfg)
local ret = {} --- @type string[]
for _, f in ipairs(funs) do
if cfg.fn_xform then
cfg.fn_xform(f)
end
ret[#ret + 1] = render_fun(f, cfg)
end
-- Sort via prototype
table.sort(ret, function(a, b)
local a1 = ('\n' .. a):match('\n[a-zA-Z_][^\n]+\n')
local b1 = ('\n' .. b):match('\n[a-zA-Z_][^\n]+\n')
return a1:lower() < b1:lower()
end)
return table.concat(ret)
end
--- @return string
local function get_script_path()
local str = debug.getinfo(2, 'S').source:sub(2)
return str:match('(.*[/\\])') or './'
end
local script_path = get_script_path()
local base_dir = vim.fs.dirname(assert(vim.fs.dirname(script_path)))
local function delete_lines_below(doc_file, tokenstr)
local lines = {} --- @type string[]
local found = false
for line in io.lines(doc_file) do
if line:find(vim.pesc(tokenstr)) then
found = true
break
end
lines[#lines + 1] = line
end
if not found then
error(fmt('not found: %s in %s', tokenstr, doc_file))
end
lines[#lines] = nil
local fp = assert(io.open(doc_file, 'w'))
fp:write(table.concat(lines, '\n'))
fp:write('\n')
fp:close()
end
--- @param x string
local function mktitle(x)
if x == 'ui' then
return 'UI'
end
return x:sub(1, 1):upper() .. x:sub(2)
end
--- @class nvim.gen_vimdoc.Section
--- @field name string
--- @field title string
--- @field help_tag string
--- @field funs_txt string
--- @field doc? string[]
--- @param filename string
--- @param cfg nvim.gen_vimdoc.Config
--- @param section_docs table<string,nvim.gen_vimdoc.Section>
--- @param funs_txt string
--- @return nvim.gen_vimdoc.Section?
local function make_section(filename, cfg, section_docs, funs_txt)
-- filename: e.g., 'autocmd.c'
-- name: e.g. 'autocmd'
local name = filename:match('(.*)%.[a-z]+')
-- Formatted (this is what's going to be written in the vimdoc)
-- e.g., "Autocmd Functions"
local sectname = cfg.section_name and cfg.section_name[filename] or mktitle(name)
-- section tag: e.g., "*api-autocmd*"
local help_tag = cfg.helptag_fmt(sectname)
if funs_txt == '' and #section_docs == 0 then
return
end
return {
name = sectname,
title = cfg.section_fmt(sectname),
help_tag = help_tag,
funs_txt = funs_txt,
doc = section_docs,
}
end
--- @param section nvim.gen_vimdoc.Section
--- @param add_header? boolean
local function render_section(section, add_header)
local doc = {} --- @type string[]
if add_header ~= false then
vim.list_extend(doc, {
string.rep('=', TEXT_WIDTH),
'\n',
section.title,
fmt('%' .. (TEXT_WIDTH - section.title:len()) .. 's', section.help_tag),
})
end
if section.doc and #section.doc > 0 then
table.insert(doc, '\n\n')
vim.list_extend(doc, section.doc)
end
if section.funs_txt then
table.insert(doc, '\n\n')
table.insert(doc, section.funs_txt)
end
return table.concat(doc)
end
local parsers = {
lua = luacats_parser.parse,
c = cdoc_parser.parse,
h = cdoc_parser.parse,
}
--- @param files string[]
local function expand_files(files)
for k, f in pairs(files) do
if vim.fn.isdirectory(f) == 1 then
table.remove(files, k)
for path, ty in vim.fs.dir(f) do
if ty == 'file' then
table.insert(files, vim.fs.joinpath(f, path))
end
end
end
end
end
--- @param cfg nvim.gen_vimdoc.Config
local function gen_target(cfg)
local sections = {} --- @type table<string,nvim.gen_vimdoc.Section>
expand_files(cfg.files)
for _, f in pairs(cfg.files) do
local ext = assert(f:match('%.([^.]+)$')) --[[@as 'h'|'c'|'lua']]
local parser = assert(parsers[ext])
local _, funs, briefs = parser(f)
local briefs_txt = {} --- @type string[]
for _, b in ipairs(briefs) do
briefs_txt[#briefs_txt + 1] = md_to_vimdoc(b, 0, 0, TEXT_WIDTH)
end
local funs_txt = render_funs(funs, cfg)
-- FIXME: Using f_base will confuse `_meta/protocol.lua` with `protocol.lua`
local f_base = assert(vim.fs.basename(f))
sections[f_base] = make_section(f_base, cfg, briefs_txt, funs_txt)
end
local first_section_tag = sections[cfg.section_order[1]].help_tag
local docs = {} --- @type string[]
for _, f in ipairs(cfg.section_order) do
local section = sections[f]
if section then
local add_sep_and_header = not vim.tbl_contains(cfg.append_only or {}, f)
table.insert(docs, render_section(section, add_sep_and_header))
end
end
table.insert(
docs,
fmt(' vim:tw=78:ts=8:sw=%d:sts=%d:et:ft=help:norl:\n', INDENTATION, INDENTATION)
)
local doc_file = vim.fs.joinpath(base_dir, 'runtime', 'doc', cfg.filename)
if vim.uv.fs_stat(doc_file) then
delete_lines_below(doc_file, first_section_tag)
end
local fp = assert(io.open(doc_file, 'a'))
fp:write(table.concat(docs, '\n'))
fp:close()
end
local function run()
for _, cfg in pairs(config) do
gen_target(cfg)
end
end
run()

File diff suppressed because it is too large Load Diff

View File

@ -1,544 +0,0 @@
-----------------------------------------------------------------------------
-- Copyright (C) 2012 by Simon Dales --
-- simon@purrsoft.co.uk --
-- --
-- This program is free software; you can redistribute it and/or modify --
-- it under the terms of the GNU General Public License as published by --
-- the Free Software Foundation; either version 2 of the License, or --
-- (at your option) any later version. --
-- --
-- This program is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
-- GNU General Public License for more details. --
-- --
-- You should have received a copy of the GNU General Public License --
-- along with this program; if not, write to the --
-- Free Software Foundation, Inc., --
-- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. --
-----------------------------------------------------------------------------
--[[!
Lua-to-Doxygen converter
Partially from lua2dox
http://search.cpan.org/~alec/Doxygen-Lua-0.02/lib/Doxygen/Lua.pm
RUNNING
-------
This script "lua2dox.lua" gets called by "gen_vimdoc.py".
DEBUGGING/DEVELOPING
---------------------
1. To debug, run gen_vimdoc.py with --keep-tmpfiles:
python3 scripts/gen_vimdoc.py -t treesitter --keep-tmpfiles
2. The filtered result will be written to ./tmp-lua2dox-doc/.lua.c
Doxygen must be on your system. You can experiment like so:
- Run "doxygen -g" to create a default Doxyfile.
- Then alter it to let it recognise lua. Add the following line:
FILE_PATTERNS = *.lua
- Then run "doxygen".
The core function reads the input file (filename or stdin) and outputs some pseudo C-ish language.
It only has to be good enough for doxygen to see it as legal.
One limitation is that each line is treated separately (except for long comments).
The implication is that class and function declarations must be on the same line.
There is hack that will insert the "missing" close paren.
The effect is that you will get the function documented, but not with the parameter list you might expect.
]]
local TYPES = { 'integer', 'number', 'string', 'table', 'list', 'boolean', 'function' }
local luacats_parser = require('src/nvim/generators/luacats_grammar')
local debug_outfile = nil --- @type string?
local debug_output = {}
--- write to stdout
--- @param str? string
local function write(str)
if not str then
return
end
io.write(str)
if debug_outfile then
table.insert(debug_output, str)
end
end
--- write to stdout
--- @param str? string
local function writeln(str)
write(str)
write('\n')
end
--- an input file buffer
--- @class StreamRead
--- @field currentLine string?
--- @field contentsLen integer
--- @field currentLineNo integer
--- @field filecontents string[]
local StreamRead = {}
--- @return StreamRead
--- @param filename string
function StreamRead.new(filename)
assert(filename, ('invalid file: %s'):format(filename))
-- get lines from file
-- syphon lines to our table
local filecontents = {} --- @type string[]
for line in io.lines(filename) do
filecontents[#filecontents + 1] = line
end
return setmetatable({
filecontents = filecontents,
contentsLen = #filecontents,
currentLineNo = 1,
}, { __index = StreamRead })
end
-- get a line
function StreamRead:getLine()
if self.currentLine then
self.currentLine = nil
return self.currentLine
end
-- get line
if self.currentLineNo <= self.contentsLen then
local line = self.filecontents[self.currentLineNo]
self.currentLineNo = self.currentLineNo + 1
return line
end
return ''
end
-- save line fragment
--- @param line_fragment string
function StreamRead:ungetLine(line_fragment)
self.currentLine = line_fragment
end
-- is it eof?
function StreamRead:eof()
return not self.currentLine and self.currentLineNo > self.contentsLen
end
-- input filter
--- @class Lua2DoxFilter
local Lua2DoxFilter = {
generics = {}, --- @type table<string,string>
block_ignore = false, --- @type boolean
}
setmetatable(Lua2DoxFilter, { __index = Lua2DoxFilter })
function Lua2DoxFilter:reset()
self.generics = {}
self.block_ignore = false
end
--- trim comment off end of string
---
--- @param line string
--- @return string, string?
local function removeCommentFromLine(line)
local pos_comment = line:find('%-%-')
if not pos_comment then
return line
end
return line:sub(1, pos_comment - 1), line:sub(pos_comment)
end
--- @param parsed luacats.Return
--- @return string
local function get_return_type(parsed)
local elems = {} --- @type string[]
for _, v in ipairs(parsed) do
local e = v.type --- @type string
if v.name then
e = e .. ' ' .. v.name --- @type string
end
elems[#elems + 1] = e
end
return '(' .. table.concat(elems, ', ') .. ')'
end
--- @param name string
--- @return string
local function process_name(name, optional)
if optional then
name = name:sub(1, -2) --- @type string
end
return name
end
--- @param ty string
--- @param generics table<string,string>
--- @return string
local function process_type(ty, generics, optional)
-- replace generic types
for k, v in pairs(generics) do
ty = ty:gsub(k, v) --- @type string
end
-- strip parens
ty = ty:gsub('^%((.*)%)$', '%1')
if optional and not ty:find('nil') then
ty = ty .. '?'
end
-- remove whitespace in unions
ty = ty:gsub('%s*|%s*', '|')
-- replace '|nil' with '?'
ty = ty:gsub('|nil', '?')
ty = ty:gsub('nil|(.*)', '%1?')
return '(`' .. ty .. '`)'
end
--- @param parsed luacats.Param
--- @param generics table<string,string>
--- @return string
local function process_param(parsed, generics)
local name, ty = parsed.name, parsed.type
local optional = vim.endswith(name, '?')
return table.concat({
'/// @param',
process_name(name, optional),
process_type(ty, generics, optional),
parsed.desc,
}, ' ')
end
--- @param parsed luacats.Return
--- @param generics table<string,string>
--- @return string
local function process_return(parsed, generics)
local ty, name --- @type string, string
if #parsed == 1 then
ty, name = parsed[1].type, parsed[1].name or ''
else
ty, name = get_return_type(parsed), ''
end
local optional = vim.endswith(name, '?')
return table.concat({
'/// @return',
process_type(ty, generics, optional),
process_name(name, optional),
parsed.desc,
}, ' ')
end
--- Processes "@…" directives in a docstring line.
---
--- @param line string
--- @return string?
function Lua2DoxFilter:process_magic(line)
line = line:gsub('^%s+@', '@')
line = line:gsub('@package', '@private')
line = line:gsub('@nodoc', '@private')
if self.block_ignore then
return '// gg:" ' .. line .. '"'
end
if not vim.startswith(line, '@') then -- it's a magic comment
return '/// ' .. line
end
local magic_split = vim.split(line, ' ', { plain = true })
local directive = magic_split[1]
if
vim.list_contains({
'@cast',
'@diagnostic',
'@overload',
'@meta',
'@type',
}, directive)
then
-- Ignore LSP directives
return '// gg:"' .. line .. '"'
elseif directive == '@defgroup' or directive == '@addtogroup' then
-- Can't use '.' in defgroup, so convert to '--'
return '/// ' .. line:gsub('%.', '-dot-')
end
if directive == '@alias' then
-- this contiguous block should be all ignored.
self.block_ignore = true
return '// gg:"' .. line .. '"'
end
-- preprocess line before parsing
if directive == '@param' or directive == '@return' then
for _, type in ipairs(TYPES) do
line = line:gsub('^@param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. ')%)', '@param %1 %2')
line = line:gsub('^@param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '|nil)%)', '@param %1 %2')
line = line:gsub('^@param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '%?)%)', '@param %1 %2')
line = line:gsub('^@return%s+.*%((' .. type .. ')%)', '@return %1')
line = line:gsub('^@return%s+.*%((' .. type .. '|nil)%)', '@return %1')
line = line:gsub('^@return%s+.*%((' .. type .. '%?)%)', '@return %1')
end
end
local parsed = luacats_parser:match(line)
if not parsed then
return '/// ' .. line
end
local kind = parsed.kind
if kind == 'generic' then
self.generics[parsed.name] = parsed.type or 'any'
return
elseif kind == 'param' then
return process_param(parsed --[[@as luacats.Param]], self.generics)
elseif kind == 'return' then
return process_return(parsed --[[@as luacats.Return]], self.generics)
end
error(string.format('unhandled parsed line %q: %s', line, parsed))
end
--- @param line string
--- @param in_stream StreamRead
--- @return string
function Lua2DoxFilter:process_block_comment(line, in_stream)
local comment_parts = {} --- @type string[]
local done --- @type boolean?
while not done and not in_stream:eof() do
local thisComment --- @type string?
local closeSquare = line:find(']]')
if not closeSquare then -- need to look on another line
thisComment = line .. '\n'
line = in_stream:getLine()
else
thisComment = line:sub(1, closeSquare - 1)
done = true
-- unget the tail of the line
-- in most cases it's empty. This may make us less efficient but
-- easier to program
in_stream:ungetLine(vim.trim(line:sub(closeSquare + 2)))
end
comment_parts[#comment_parts + 1] = thisComment
end
local comment = table.concat(comment_parts)
if comment:sub(1, 1) == '@' then -- it's a long magic comment
return '/*' .. comment .. '*/ '
end
-- discard
return '/* zz:' .. comment .. '*/ '
end
--- @param line string
--- @return string
function Lua2DoxFilter:process_function_header(line)
local pos_fn = assert(line:find('function'))
-- we've got a function
local fn = removeCommentFromLine(vim.trim(line:sub(pos_fn + 8)))
if fn:sub(1, 1) == '(' then
-- it's an anonymous function
return '// ZZ: ' .. line
end
-- fn has a name, so is interesting
-- want to fix for iffy declarations
if fn:find('[%({]') then
-- we might have a missing close paren
if not fn:find('%)') then
fn = fn .. ' ___MissingCloseParenHere___)'
end
end
-- Big hax
if fn:find(':') then
fn = fn:gsub(':', '.', 1)
local paren_start = fn:find('(', 1, true)
local paren_finish = fn:find(')', 1, true)
-- Nothing in between the parens
local comma --- @type string
if paren_finish == paren_start + 1 then
comma = ''
else
comma = ', '
end
fn = fn:sub(1, paren_start) .. 'self' .. comma .. fn:sub(paren_start + 1)
end
if line:match('local') then
-- Special: tell gen_vimdoc.py this is a local function.
return 'local_function ' .. fn .. '{}'
end
-- add vanilla function
return 'function ' .. fn .. '{}'
end
--- @param line string
--- @param in_stream StreamRead
--- @return string?
function Lua2DoxFilter:process_line(line, in_stream)
local line_raw = line
line = vim.trim(line)
if vim.startswith(line, '---') then
return Lua2DoxFilter:process_magic(line:sub(4))
end
if vim.startswith(line, '--' .. '[[') then -- it's a long comment
return Lua2DoxFilter:process_block_comment(line:sub(5), in_stream)
end
-- Hax... I'm sorry
-- M.fun = vim.memoize(function(...)
-- ->
-- function M.fun(...)
line = line:gsub('^(.+) = .*_memoize%([^,]+, function%((.*)%)$', 'function %1(%2)')
if line:find('^function') or line:find('^local%s+function') then
return Lua2DoxFilter:process_function_header(line)
end
if not line:match('^local') then
local v = line_raw:match('^([A-Za-z][.a-zA-Z_]*)%s+%=')
if v and v:match('%.') then
-- Special: this lets gen_vimdoc.py handle tables.
return 'table ' .. v .. '() {}'
end
end
if #line > 0 then -- we don't know what this line means, so just comment it out
return '// zz: ' .. line
end
return ''
end
-- Processes the file and writes filtered output to stdout.
---@param filename string
function Lua2DoxFilter:filter(filename)
local in_stream = StreamRead.new(filename)
local last_was_magic = false
while not in_stream:eof() do
local line = in_stream:getLine()
local out_line = self:process_line(line, in_stream)
if not vim.startswith(vim.trim(line), '---') then
self:reset()
end
if out_line then
-- Ensure all magic blocks associate with some object to prevent doxygen
-- from getting confused.
if vim.startswith(out_line, '///') then
last_was_magic = true
else
if last_was_magic and out_line:match('^// zz: [^-]+') then
writeln('local_function _ignore() {}')
end
last_was_magic = false
end
writeln(out_line)
end
end
end
--- @class TApp
--- @field timestamp string|osdate
--- @field name string
--- @field version string
--- @field copyright string
--- this application
local TApp = {
timestamp = os.date('%c %Z', os.time()),
name = 'Lua2DoX',
version = '0.2 20130128',
copyright = 'Copyright (c) Simon Dales 2012-13',
}
setmetatable(TApp, { __index = TApp })
function TApp:getRunStamp()
return self.name .. ' (' .. self.version .. ') ' .. self.timestamp
end
function TApp:getVersion()
return self.name .. ' (' .. self.version .. ') '
end
--main
if arg[1] == '--help' then
writeln(TApp:getVersion())
writeln(TApp.copyright)
writeln([[
run as:
nvim -l scripts/lua2dox.lua <param>
--------------
Param:
<filename> : interprets filename
--version : show version/copyright info
--help : this help text]])
elseif arg[1] == '--version' then
writeln(TApp:getVersion())
writeln(TApp.copyright)
else -- It's a filter.
local filename = arg[1]
if arg[2] == '--outdir' then
local outdir = arg[3]
if
type(outdir) ~= 'string'
or (0 ~= vim.fn.filereadable(outdir) and 0 == vim.fn.isdirectory(outdir))
then
error(('invalid --outdir: "%s"'):format(tostring(outdir)))
end
vim.fn.mkdir(outdir, 'p')
debug_outfile = string.format('%s/%s.c', outdir, vim.fs.basename(filename))
end
Lua2DoxFilter:filter(filename)
-- output the tail
writeln('// #######################')
writeln('// app run:' .. TApp:getRunStamp())
writeln('// #######################')
writeln()
if debug_outfile then
local f = assert(io.open(debug_outfile, 'w'))
f:write(table.concat(debug_output))
f:close()
end
end

218
scripts/luacats_grammar.lua Normal file
View File

@ -0,0 +1,218 @@
--[[!
LPEG grammar for LuaCATS
]]
local lpeg = vim.lpeg
local P, R, S = lpeg.P, lpeg.R, lpeg.S
local Ct, Cg = lpeg.Ct, lpeg.Cg
--- @param x vim.lpeg.Pattern
local function rep(x)
return x ^ 0
end
--- @param x vim.lpeg.Pattern
local function rep1(x)
return x ^ 1
end
--- @param x vim.lpeg.Pattern
local function opt(x)
return x ^ -1
end
local nl = P('\r\n') + P('\n')
local ws = rep1(S(' \t') + nl)
local fill = opt(ws)
local any = P(1) -- (consume one character)
local letter = R('az', 'AZ') + S('_$')
local num = R('09')
local ident = letter * rep(letter + num + S '-.')
local string_single = P "'" * rep(any - P "'") * P "'"
local string_double = P '"' * rep(any - P '"') * P '"'
local literal = (string_single + string_double + (opt(P '-') * num) + P 'false' + P 'true')
local lname = (ident + P '...') * opt(P '?')
--- @param x string
local function Pf(x)
return fill * P(x) * fill
end
--- @param x string
local function Sf(x)
return fill * S(x) * fill
end
--- @param x vim.lpeg.Pattern
local function comma(x)
return x * rep(Pf ',' * x)
end
--- @param x vim.lpeg.Pattern
local function parenOpt(x)
return (Pf('(') * x * fill * P(')')) + x
end
--- @type table<string,vim.lpeg.Pattern>
local v = setmetatable({}, {
__index = function(_, k)
return lpeg.V(k)
end,
})
local desc_delim = Sf '#:' + ws
--- @class nvim.luacats.Param
--- @field kind 'param'
--- @field name string
--- @field type string
--- @field desc? string
--- @class nvim.luacats.Return
--- @field kind 'return'
--- @field [integer] { type: string, name?: string}
--- @field desc? string
--- @class nvim.luacats.Generic
--- @field kind 'generic'
--- @field name string
--- @field type? string
--- @class nvim.luacats.Class
--- @field kind 'class'
--- @field name string
--- @field parent? string
--- @class nvim.luacats.Field
--- @field kind 'field'
--- @field name string
--- @field type string
--- @field desc? string
--- @field access? 'private'|'protected'|'package'
--- @class nvim.luacats.Note
--- @field desc? string
--- @alias nvim.luacats.grammar.result
--- | nvim.luacats.Param
--- | nvim.luacats.Return
--- | nvim.luacats.Generic
--- | nvim.luacats.Class
--- | nvim.luacats.Field
--- | nvim.luacats.Note
--- @class nvim.luacats.grammar
--- @field match fun(self, input: string): nvim.luacats.grammar.result?
local grammar = P {
rep1(P('@') * (v.ats + v.ext_ats)),
ats = v.at_param
+ v.at_return
+ v.at_type
+ v.at_cast
+ v.at_generic
+ v.at_class
+ v.at_field
+ v.at_access
+ v.at_deprecated
+ v.at_alias
+ v.at_enum
+ v.at_see
+ v.at_diagnostic
+ v.at_overload
+ v.at_meta,
ext_ats = v.ext_at_note + v.ext_at_since + v.ext_at_nodoc + v.ext_at_brief,
at_param = Ct(
Cg(P('param'), 'kind')
* ws
* Cg(lname, 'name')
* ws
* parenOpt(Cg(v.ltype, 'type'))
* opt(desc_delim * Cg(rep(any), 'desc'))
),
at_return = Ct(
Cg(P('return'), 'kind')
* ws
* parenOpt(comma(Ct(Cg(v.ltype, 'type') * opt(ws * Cg(ident, 'name')))))
* opt(desc_delim * Cg(rep(any), 'desc'))
),
at_type = Ct(
Cg(P('type'), 'kind')
* ws
* parenOpt(comma(Ct(Cg(v.ltype, 'type'))))
* opt(desc_delim * Cg(rep(any), 'desc'))
),
at_cast = Ct(
Cg(P('cast'), 'kind') * ws * Cg(lname, 'name') * ws * opt(Sf('+-')) * Cg(v.ltype, 'type')
),
at_generic = Ct(
Cg(P('generic'), 'kind') * ws * Cg(ident, 'name') * opt(Pf ':' * Cg(v.ltype, 'type'))
),
at_class = Ct(
Cg(P('class'), 'kind')
* ws
* opt(P('(exact)') * ws)
* Cg(lname, 'name')
* opt(Pf(':') * Cg(lname, 'parent'))
),
at_field = Ct(
Cg(P('field'), 'kind')
* ws
* opt(Cg(Pf('private') + Pf('package') + Pf('protected'), 'access'))
* Cg(lname, 'name')
* ws
* Cg(v.ltype, 'type')
* opt(desc_delim * Cg(rep(any), 'desc'))
),
at_access = Ct(Cg(P('private') + P('protected') + P('package'), 'kind')),
at_deprecated = Ct(Cg(P('deprecated'), 'kind')),
-- Types may be provided on subsequent lines
at_alias = Ct(Cg(P('alias'), 'kind') * ws * Cg(lname, 'name') * opt(ws * Cg(v.ltype, 'type'))),
at_enum = Ct(Cg(P('enum'), 'kind') * ws * Cg(lname, 'name')),
at_see = Ct(Cg(P('see'), 'kind') * ws * opt(Pf('#')) * Cg(rep(any), 'desc')),
at_diagnostic = Ct(Cg(P('diagnostic'), 'kind') * ws * opt(Pf('#')) * Cg(rep(any), 'desc')),
at_overload = Ct(Cg(P('overload'), 'kind') * ws * Cg(v.ltype, 'type')),
at_meta = Ct(Cg(P('meta'), 'kind')),
--- Custom extensions
ext_at_note = Ct(Cg(P('note'), 'kind') * ws * Cg(rep(any), 'desc')),
-- TODO only consume 1 line
ext_at_since = Ct(Cg(P('since'), 'kind') * ws * Cg(rep(any), 'desc')),
ext_at_nodoc = Ct(Cg(P('nodoc'), 'kind')),
ext_at_brief = Ct(Cg(P('brief'), 'kind') * opt(ws * Cg(rep(any), 'desc'))),
ltype = v.ty_union + Pf '(' * v.ty_union * fill * P ')',
ty_union = v.ty_opt * rep(Pf '|' * v.ty_opt),
ty = v.ty_fun + ident + v.ty_table + literal,
ty_param = Pf '<' * comma(v.ltype) * fill * P '>',
ty_opt = v.ty * opt(v.ty_param) * opt(P '[]') * opt(P '?'),
table_key = (Pf '[' * literal * Pf ']') + lname,
table_elem = v.table_key * Pf ':' * v.ltype,
ty_table = Pf '{' * comma(v.table_elem) * Pf '}',
fun_param = lname * opt(Pf ':' * v.ltype),
ty_fun = Pf 'fun(' * rep(comma(v.fun_param)) * fill * P ')' * opt(Pf ':' * comma(v.ltype)),
}
return grammar --[[@as nvim.luacats.grammar]]

521
scripts/luacats_parser.lua Normal file
View File

@ -0,0 +1,521 @@
local luacats_grammar = require('scripts.luacats_grammar')
--- @class nvim.luacats.parser.param
--- @field name string
--- @field type string
--- @field desc string
--- @class nvim.luacats.parser.return
--- @field name string
--- @field type string
--- @field desc string
--- @class nvim.luacats.parser.note
--- @field desc string
--- @class nvim.luacats.parser.brief
--- @field kind 'brief'
--- @field desc string
--- @class nvim.luacats.parser.alias
--- @field kind 'alias'
--- @field type string
--- @field desc string
--- @class nvim.luacats.parser.fun
--- @field name string
--- @field params nvim.luacats.parser.param[]
--- @field returns nvim.luacats.parser.return[]
--- @field desc string
--- @field access? 'private'|'package'|'protected'
--- @field class? string
--- @field module? string
--- @field modvar? string
--- @field classvar? string
--- @field deprecated? true
--- @field since? string
--- @field attrs? string[]
--- @field nodoc? true
--- @field generics? table<string,string>
--- @field table? true
--- @field notes? nvim.luacats.parser.note[]
--- @field see? nvim.luacats.parser.note[]
--- @class nvim.luacats.parser.field
--- @field name string
--- @field type string
--- @field desc string
--- @field access? 'private'|'package'|'protected'
--- @class nvim.luacats.parser.class
--- @field kind 'class'
--- @field name string
--- @field desc string
--- @field fields nvim.luacats.parser.field[]
--- @field notes? string[]
--- @class nvim.luacats.parser.State
--- @field doc_lines? string[]
--- @field cur_obj? nvim.luacats.parser.obj
--- @field last_doc_item? nvim.luacats.parser.param|nvim.luacats.parser.return|nvim.luacats.parser.note
--- @field last_doc_item_indent? integer
--- @alias nvim.luacats.parser.obj
--- | nvim.luacats.parser.class
--- | nvim.luacats.parser.fun
--- | nvim.luacats.parser.brief
-- Remove this when we document classes properly
--- Some doc lines have the form:
--- param name some.complex.type (table) description
--- if so then transform the line to remove the complex type:
--- param name (table) description
--- @param line string
local function use_type_alt(line)
for _, type in ipairs({ 'table', 'function' }) do
line = line:gsub('@param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. ')%)', '@param %1 %2')
line = line:gsub('@param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '|nil)%)', '@param %1 %2')
line = line:gsub('@param%s+([a-zA-Z_?]+)%s+.*%((' .. type .. '%?)%)', '@param %1 %2')
line = line:gsub('@return%s+.*%((' .. type .. ')%)', '@return %1')
line = line:gsub('@return%s+.*%((' .. type .. '|nil)%)', '@return %1')
line = line:gsub('@return%s+.*%((' .. type .. '%?)%)', '@return %1')
end
return line
end
--- If we collected any `---` lines. Add them to the existing (or new) object
--- Used for function/class descriptions and multiline param descriptions.
--- @param state nvim.luacats.parser.State
local function add_doc_lines_to_obj(state)
if state.doc_lines then
state.cur_obj = state.cur_obj or {}
local cur_obj = assert(state.cur_obj)
local txt = table.concat(state.doc_lines, '\n')
if cur_obj.desc then
cur_obj.desc = cur_obj.desc .. '\n' .. txt
else
cur_obj.desc = txt
end
state.doc_lines = nil
end
end
--- @param line string
--- @param state nvim.luacats.parser.State
local function process_doc_line(line, state)
line = line:sub(4):gsub('^%s+@', '@')
line = use_type_alt(line)
local parsed = luacats_grammar:match(line)
if not parsed then
if line:match('^ ') then
line = line:sub(2)
end
if state.last_doc_item then
if not state.last_doc_item_indent then
state.last_doc_item_indent = #line:match('^%s*') + 1
end
state.last_doc_item.desc = (state.last_doc_item.desc or '')
.. '\n'
.. line:sub(state.last_doc_item_indent or 1)
else
state.doc_lines = state.doc_lines or {}
table.insert(state.doc_lines, line)
end
return
end
state.last_doc_item_indent = nil
state.last_doc_item = nil
state.cur_obj = state.cur_obj or {}
local cur_obj = assert(state.cur_obj)
local kind = parsed.kind
if kind == 'brief' then
state.cur_obj = {
kind = 'brief',
desc = parsed.desc,
}
elseif kind == 'class' then
--- @cast parsed nvim.luacats.Class
state.cur_obj = {
kind = 'class',
name = parsed.name,
parent = parsed.parent,
desc = '',
fields = {},
}
elseif kind == 'field' then
--- @cast parsed nvim.luacats.Field
if not parsed.access then
parsed.desc = parsed.desc or state.doc_lines and table.concat(state.doc_lines, '\n') or nil
if parsed.desc then
parsed.desc = vim.trim(parsed.desc)
end
table.insert(cur_obj.fields, parsed)
end
state.doc_lines = nil
elseif kind == 'param' then
state.last_doc_item_indent = nil
cur_obj.params = cur_obj.params or {}
if vim.endswith(parsed.name, '?') then
parsed.name = parsed.name:sub(1, -2)
parsed.type = parsed.type .. '?'
end
state.last_doc_item = {
name = parsed.name,
type = parsed.type,
desc = parsed.desc,
}
table.insert(cur_obj.params, state.last_doc_item)
elseif kind == 'return' then
cur_obj.returns = cur_obj.returns or {}
for _, t in ipairs(parsed) do
table.insert(cur_obj.returns, {
name = t.name,
type = t.type,
desc = parsed.desc,
})
end
state.last_doc_item_indent = nil
state.last_doc_item = cur_obj.returns[#cur_obj.returns]
elseif kind == 'private' then
cur_obj.access = 'private'
elseif kind == 'package' then
cur_obj.access = 'package'
elseif kind == 'protected' then
cur_obj.access = 'protected'
elseif kind == 'deprecated' then
cur_obj.deprecated = true
elseif kind == 'nodoc' then
cur_obj.nodoc = true
elseif kind == 'since' then
cur_obj.since = parsed.desc
elseif kind == 'see' then
cur_obj.see = cur_obj.see or {}
table.insert(cur_obj.see, { desc = parsed.desc })
elseif kind == 'note' then
state.last_doc_item_indent = nil
state.last_doc_item = {
desc = parsed.desc,
}
cur_obj.notes = cur_obj.notes or {}
table.insert(cur_obj.notes, state.last_doc_item)
elseif kind == 'type' then
cur_obj.desc = parsed.desc
parsed.desc = nil
parsed.kind = nil
cur_obj.type = parsed
elseif kind == 'alias' then
state.cur_obj = {
kind = 'alias',
desc = parsed.desc,
}
elseif kind == 'enum' then
-- TODO
state.doc_lines = nil
elseif
vim.tbl_contains({
'diagnostic',
'cast',
'overload',
'meta',
}, kind)
then
-- Ignore
return
elseif kind == 'generic' then
cur_obj.generics = cur_obj.generics or {}
cur_obj.generics[parsed.name] = parsed.type or 'any'
else
error('Unhandled' .. vim.inspect(parsed))
end
end
--- @param fun nvim.luacats.parser.fun
--- @return nvim.luacats.parser.field
local function fun2field(fun)
local parts = { 'fun(' }
for _, p in ipairs(fun.params or {}) do
parts[#parts + 1] = string.format('%s: %s', p.name, p.type)
end
parts[#parts + 1] = ')'
if fun.returns then
parts[#parts + 1] = ': '
local tys = {} --- @type string[]
for _, p in ipairs(fun.returns) do
tys[#tys + 1] = p.type
end
parts[#parts + 1] = table.concat(tys, ', ')
end
return {
name = fun.name,
type = table.concat(parts, ''),
access = fun.access,
desc = fun.desc,
}
end
--- Function to normalize known form for declaring functions and normalize into a more standard
--- form.
--- @param line string
--- @return string
local function filter_decl(line)
-- M.fun = vim._memoize(function(...)
-- ->
-- function M.fun(...)
line = line:gsub('^local (.+) = .*_memoize%([^,]+, function%((.*)%)$', 'local function %1(%2)')
line = line:gsub('^(.+) = .*_memoize%([^,]+, function%((.*)%)$', 'function %1(%2)')
return line
end
--- @param line string
--- @param state nvim.luacats.parser.State
--- @param classes table<string,nvim.luacats.parser.class>
--- @param classvars table<string,string>
--- @param has_indent boolean
local function process_lua_line(line, state, classes, classvars, has_indent)
line = filter_decl(line)
if state.cur_obj and state.cur_obj.kind == 'class' then
local nm = line:match('^local%s+([a-zA-Z0-9_]+)%s*=')
if nm then
classvars[nm] = state.cur_obj.name
end
return
end
do
local parent_tbl, sep, fun_or_meth_nm =
line:match('^function%s+([a-zA-Z0-9_]+)([.:])([a-zA-Z0-9_]+)%s*%(')
if parent_tbl then
-- Have a decl. Ensure cur_obj
state.cur_obj = state.cur_obj or {}
local cur_obj = assert(state.cur_obj)
-- Match `Class:foo` methods for defined classes
local class = classvars[parent_tbl]
if class then
--- @cast cur_obj nvim.luacats.parser.fun
cur_obj.name = fun_or_meth_nm
cur_obj.class = class
cur_obj.classvar = parent_tbl
-- Add self param to methods
if sep == ':' then
cur_obj.params = cur_obj.params or {}
table.insert(cur_obj.params, 1, {
name = 'self',
type = class,
})
end
-- Add method as the field to the class
table.insert(classes[class].fields, fun2field(cur_obj))
return
end
-- Match `M.foo`
if cur_obj and parent_tbl == cur_obj.modvar then
cur_obj.name = fun_or_meth_nm
return
end
end
end
do
-- Handle: `function A.B.C.foo(...)`
local fn_nm = line:match('^function%s+([.a-zA-Z0-9_]+)%s*%(')
if fn_nm then
state.cur_obj = state.cur_obj or {}
state.cur_obj.name = fn_nm
return
end
end
do
-- Handle: `M.foo = {...}` where `M` is the modvar
local parent_tbl, tbl_nm = line:match('([a-zA-Z_]+)%.([a-zA-Z0-9_]+)%s*=')
if state.cur_obj and parent_tbl and parent_tbl == state.cur_obj.modvar then
state.cur_obj.name = tbl_nm
state.cur_obj.table = true
return
end
end
do
-- Handle: `foo = {...}`
local tbl_nm = line:match('^([a-zA-Z0-9_]+)%s*=')
if tbl_nm and not has_indent then
state.cur_obj = state.cur_obj or {}
state.cur_obj.name = tbl_nm
state.cur_obj.table = true
return
end
end
do
-- Handle: `vim.foo = {...}`
local tbl_nm = line:match('^(vim%.[a-zA-Z0-9_]+)%s*=')
if state.cur_obj and tbl_nm and not has_indent then
state.cur_obj.name = tbl_nm
state.cur_obj.table = true
return
end
end
if state.cur_obj then
if line:find('^%s*%-%- luacheck:') then
state.cur_obj = nil
elseif line:find('^%s*local%s+') then
state.cur_obj = nil
elseif line:find('^%s*return%s+') then
state.cur_obj = nil
elseif line:find('^%s*[a-zA-Z_.]+%(%s+') then
state.cur_obj = nil
end
end
end
--- Determine the table name used to export functions of a module
--- Usually this is `M`.
--- @param filename string
--- @return string?
local function determine_modvar(filename)
local modvar --- @type string?
for line in io.lines(filename) 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
end
return modvar
end
--- @param obj nvim.luacats.parser.obj
--- @param funs nvim.luacats.parser.fun[]
--- @param classes table<string,nvim.luacats.parser.class>
--- @param briefs string[]
--- @param uncommitted nvim.luacats.parser.obj[]
local function commit_obj(obj, classes, funs, briefs, uncommitted)
local commit = false
if obj.kind == 'class' then
--- @cast obj nvim.luacats.parser.class
if not classes[obj.name] then
classes[obj.name] = obj
commit = true
end
elseif obj.kind == 'alias' then
-- Just pretend
commit = true
elseif obj.kind == 'brief' then
--- @cast obj nvim.luacats.parser.brief`
briefs[#briefs + 1] = obj.desc
commit = true
else
--- @cast obj nvim.luacats.parser.fun`
if obj.name then
funs[#funs + 1] = obj
commit = true
end
end
if not commit then
table.insert(uncommitted, obj)
end
return commit
end
--- @param filename string
--- @param uncommitted nvim.luacats.parser.obj[]
-- luacheck: no unused
local function dump_uncommitted(filename, uncommitted)
local out_path = 'luacats-uncommited/' .. filename:gsub('/', '%%') .. '.txt'
if #uncommitted > 0 then
print(string.format('Could not commit %d objects in %s', #uncommitted, filename))
vim.fn.mkdir(assert(vim.fs.dirname(out_path)), 'p')
local f = assert(io.open(out_path, 'w'))
for i, x in ipairs(uncommitted) do
f:write(i)
f:write(': ')
f:write(vim.inspect(x))
f:write('\n')
end
f:close()
else
vim.fn.delete(out_path)
end
end
local M = {}
--- @param filename string
--- @return table<string,nvim.luacats.parser.class> classes
--- @return nvim.luacats.parser.fun[] funs
--- @return string[] briefs
--- @return nvim.luacats.parser.obj[]
function M.parse(filename)
local funs = {} --- @type nvim.luacats.parser.fun[]
local classes = {} --- @type table<string,nvim.luacats.parser.class>
local briefs = {} --- @type string[]
local mod_return = determine_modvar(filename)
--- @type string
local module = filename:match('.*/lua/([a-z_][a-z0-9_/]+)%.lua') or filename
module = module:gsub('/', '.')
local classvars = {} --- @type table<string,string>
local state = {} --- @type nvim.luacats.parser.State
-- Keep track of any partial objects we don't commit
local uncommitted = {} --- @type nvim.luacats.parser.obj[]
for line in io.lines(filename) do
local has_indent = line:match('^%s+') ~= nil
line = vim.trim(line)
if vim.startswith(line, '---') then
process_doc_line(line, state)
else
add_doc_lines_to_obj(state)
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)
-- Commit the object
local cur_obj = state.cur_obj
if cur_obj then
if not commit_obj(cur_obj, classes, funs, briefs, uncommitted) then
--- @diagnostic disable-next-line:inject-field
cur_obj.line = line
end
end
state = {}
end
end
-- dump_uncommitted(filename, uncommitted)
return classes, funs, briefs, uncommitted
end
return M

239
scripts/text_utils.lua Normal file
View File

@ -0,0 +1,239 @@
local fmt = string.format
--- @class nvim.text_utils.MDNode
--- @field [integer] nvim.text_utils.MDNode
--- @field type string
--- @field text? string
local INDENTATION = 4
local M = {}
local function contains(t, xs)
return vim.tbl_contains(xs, t)
end
--- @param text string
--- @return nvim.text_utils.MDNode
local function parse_md(text)
local parser = vim.treesitter.languagetree.new(text, 'markdown', {
injections = { markdown = '' },
})
local root = parser:parse(true)[1]:root()
local EXCLUDE_TEXT_TYPE = {
list = true,
list_item = true,
section = true,
document = true,
fenced_code_block = true,
fenced_code_block_delimiter = true,
}
--- @param node TSNode
--- @return nvim.text_utils.MDNode?
local function extract(node)
local ntype = node:type()
if ntype:match('^%p$') or contains(ntype, { 'block_continuation' }) then
return
end
--- @type table<any,any>
local ret = { type = ntype }
if not EXCLUDE_TEXT_TYPE[ntype] then
ret.text = vim.treesitter.get_node_text(node, text)
end
for child, child_field in node:iter_children() do
local e = extract(child)
if child_field then
ret[child_field] = e
else
table.insert(ret, e)
end
end
return ret
end
return extract(root) or {}
end
--- @param x string
--- @param start_indent integer
--- @param indent integer
--- @param text_width integer
--- @return string
function M.wrap(x, start_indent, indent, text_width)
local words = vim.split(vim.trim(x), '%s+')
local parts = { string.rep(' ', start_indent) } --- @type string[]
local count = indent
for i, w in ipairs(words) do
if count > indent and count + #w > text_width - 1 then
parts[#parts + 1] = '\n'
parts[#parts + 1] = string.rep(' ', indent)
count = indent
elseif i ~= 1 then
parts[#parts + 1] = ' '
count = count + 1
end
count = count + #w
parts[#parts + 1] = w
end
return (table.concat(parts):gsub('%s+\n', '\n'):gsub('\n+$', ''))
end
--- @param node nvim.text_utils.MDNode
--- @param start_indent integer
--- @param indent integer
--- @param text_width integer
--- @param level integer
--- @return string[]
local function render_md(node, start_indent, indent, text_width, level, is_list)
local parts = {} --- @type string[]
-- For debugging
local add_tag = false
-- local add_tag = true
if add_tag then
parts[#parts + 1] = '<' .. node.type .. '>'
end
if node.type == 'paragraph' then
local text = assert(node.text)
text = text:gsub('(%s)%*(%w+)%*(%s)', '%1%2%3')
text = text:gsub('(%s)_(%w+)_(%s)', '%1%2%3')
text = text:gsub('\\|', '|')
text = text:gsub('\\%*', '*')
text = text:gsub('\\_', '_')
parts[#parts + 1] = M.wrap(text, start_indent, indent, text_width)
parts[#parts + 1] = '\n'
elseif node.type == 'code_fence_content' then
local lines = vim.split(node.text:gsub('\n%s*$', ''), '\n')
local cindent = indent + INDENTATION
if level > 3 then
-- The tree-sitter markdown parser doesn't parse the code blocks indents
-- correctly in lists. Fudge it!
lines[1] = ' ' .. lines[1] -- ¯\_(ツ)_/¯
cindent = indent - level
local _, initial_indent = lines[1]:find('^%s*')
initial_indent = initial_indent + cindent
if initial_indent < indent then
cindent = indent - INDENTATION
end
end
for _, l in ipairs(lines) do
if #l > 0 then
parts[#parts + 1] = string.rep(' ', cindent)
parts[#parts + 1] = l
end
parts[#parts + 1] = '\n'
end
elseif node.type == 'fenced_code_block' then
parts[#parts + 1] = '>'
for _, child in ipairs(node) do
if child.type == 'info_string' then
parts[#parts + 1] = child.text
break
end
end
parts[#parts + 1] = '\n'
for _, child in ipairs(node) do
if child.type ~= 'info_string' then
vim.list_extend(parts, render_md(child, start_indent, indent, text_width, level + 1))
end
end
parts[#parts + 1] = '<\n'
elseif node.type == 'html_block' then
local text = node.text:gsub('^<pre>help', '')
text = text:gsub('</pre>%s*$', '')
parts[#parts + 1] = text
elseif node.type == 'list_marker_dot' then
parts[#parts + 1] = node.text
elseif contains(node.type, { 'list_marker_minus', 'list_marker_star' }) then
parts[#parts + 1] = ''
elseif node.type == 'list_item' then
parts[#parts + 1] = string.rep(' ', indent)
local offset = node[1].type == 'list_marker_dot' and 3 or 2
for i, child in ipairs(node) do
local sindent = i <= 2 and 0 or (indent + offset)
vim.list_extend(
parts,
render_md(child, sindent, indent + offset, text_width, level + 1, true)
)
end
else
if node.text then
error(fmt('cannot render:\n%s', vim.inspect(node)))
end
for i, child in ipairs(node) do
vim.list_extend(parts, render_md(child, start_indent, indent, text_width, level + 1, is_list))
if node.type ~= 'list' and i ~= #node then
if (node[i + 1] or {}).type ~= 'list' then
parts[#parts + 1] = '\n'
end
end
end
end
if add_tag then
parts[#parts + 1] = '</' .. node.type .. '>'
end
return parts
end
--- @param text_width integer
local function align_tags(text_width)
--- @param line string
--- @return string
return function(line)
local tag_pat = '%s+(%*[^ ]+%*)%s*$'
local tags = {}
for m in line:gmatch(tag_pat) do
table.insert(tags, m)
end
if #tags > 0 then
line = line:gsub(tag_pat, '')
local tags_str = ' ' .. table.concat(tags, ' ')
local pad = string.rep(' ', text_width - #line - #tags_str)
return line .. pad .. tags_str
end
return line
end
end
--- @param text string
--- @param start_indent integer
--- @param indent integer
--- @param is_list? boolean
--- @return string
function M.md_to_vimdoc(text, start_indent, indent, text_width, is_list)
-- Add an extra newline so the parser can properly capture ending ```
local parsed = parse_md(text .. '\n')
local ret = render_md(parsed, start_indent, indent, text_width, 0, is_list)
local lines = vim.split(table.concat(ret), '\n')
lines = vim.tbl_map(align_tags(text_width), lines)
local s = table.concat(lines, '\n')
-- Reduce whitespace in code-blocks
s = s:gsub('\n+%s*>([a-z]+)\n?\n', ' >%1\n')
s = s:gsub('\n+%s*>\n?\n', ' >\n')
return s
end
return M

View File

@ -902,14 +902,6 @@ set(VIMDOC_FILES
${NVIM_RUNTIME_DIR}/doc/treesitter.txt
)
set(MPACK_FILES
${NVIM_RUNTIME_DIR}/doc/api.mpack
${NVIM_RUNTIME_DIR}/doc/diagnostic.mpack
${NVIM_RUNTIME_DIR}/doc/lsp.mpack
${NVIM_RUNTIME_DIR}/doc/lua.mpack
${NVIM_RUNTIME_DIR}/doc/treesitter.mpack
)
file(GLOB API_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/src/nvim/api/*.c)
file(GLOB LUA_SOURCES CONFIGURE_DEPENDS
@ -921,25 +913,25 @@ file(GLOB LUA_SOURCES CONFIGURE_DEPENDS
)
add_custom_command(
OUTPUT ${MPACK_FILES}
COMMAND ${PROJECT_SOURCE_DIR}/scripts/gen_vimdoc.py
OUTPUT ${VIMDOC_FILES}
COMMAND ${CMAKE_COMMAND} -E env "VIMRUNTIME=${NVIM_RUNTIME_DIR}"
$<TARGET_FILE:nvim_bin> -l scripts/gen_vimdoc.lua
DEPENDS
nvim_bin
nvim
${API_SOURCES}
${LUA_SOURCES}
${VIMDOC_FILES}
${PROJECT_SOURCE_DIR}/scripts/gen_vimdoc.py
${PROJECT_SOURCE_DIR}/scripts/lua2dox.lua
${PROJECT_SOURCE_DIR}/scripts/gen_vimdoc.lua
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)
add_custom_command(
OUTPUT ${GEN_EVAL_TOUCH}
COMMAND ${CMAKE_COMMAND} -E touch ${GEN_EVAL_TOUCH}
COMMAND $<TARGET_FILE:nvim_bin> -l ${PROJECT_SOURCE_DIR}/scripts/gen_eval_files.lua
COMMAND ${CMAKE_COMMAND} -E env "VIMRUNTIME=${NVIM_RUNTIME_DIR}"
$<TARGET_FILE:nvim_bin> -l ${PROJECT_SOURCE_DIR}/scripts/gen_eval_files.lua
DEPENDS
nvim
${API_METADATA}
${NVIM_RUNTIME_DIR}/doc/api.mpack
${PROJECT_SOURCE_DIR}/scripts/gen_eval_files.lua
${PROJECT_SOURCE_DIR}/src/nvim/eval.lua
${PROJECT_SOURCE_DIR}/src/nvim/options.lua

View File

@ -75,7 +75,7 @@ static int64_t next_autocmd_id = 1;
/// - buffer: Buffer number or list of buffer numbers for buffer local autocommands
/// |autocmd-buflocal|. Cannot be used with {pattern}
/// @return Array of autocommands matching the criteria, with each item
/// containing the following fields:
/// containing the following fields:
/// - id (number): the autocommand id (only when defined with the API).
/// - group (integer): the autocommand group id.
/// - group_name (string): the autocommand group name.
@ -83,10 +83,10 @@ static int64_t next_autocmd_id = 1;
/// - event (string): the autocommand event.
/// - command (string): the autocommand command. Note: this will be empty if a callback is set.
/// - callback (function|string|nil): Lua function or name of a Vim script function
/// which is executed when this autocommand is triggered.
/// which is executed when this autocommand is triggered.
/// - once (boolean): whether the autocommand is only run once.
/// - pattern (string): the autocommand pattern.
/// If the autocommand is buffer local |autocmd-buffer-local|:
/// If the autocommand is buffer local |autocmd-buffer-local|:
/// - buflocal (boolean): true if the autocommand is buffer local.
/// - buffer (number): the buffer number.
Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
@ -536,9 +536,9 @@ void nvim_del_autocmd(Integer id, Error *err)
/// @param opts Parameters
/// - event: (string|table)
/// Examples:
/// - event: "pat1"
/// - event: { "pat1" }
/// - event: { "pat1", "pat2", "pat3" }
/// - event: "pat1"
/// - event: { "pat1" }
/// - event: { "pat1", "pat2", "pat3" }
/// - pattern: (string|table)
/// - pattern or patterns to match exactly.
/// - For example, if you have `*.py` as that pattern for the autocmd,

View File

@ -50,9 +50,8 @@
# include "api/buffer.c.generated.h"
#endif
/// \defgroup api-buffer
///
/// \brief For more information on buffers, see |buffers|
/// @brief <pre>help
/// For more information on buffers, see |buffers|.
///
/// Unloaded Buffers: ~
///
@ -64,6 +63,7 @@
///
/// You can use |nvim_buf_is_loaded()| or |nvim_buf_line_count()| to check
/// whether a buffer is loaded.
/// </pre>
/// Returns the number of lines in the given buffer.
///
@ -229,6 +229,7 @@ Boolean nvim_buf_detach(uint64_t channel_id, Buffer buffer, Error *err)
return true;
}
/// @nodoc
void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -875,8 +876,8 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
/// Gets a list of buffer-local |mapping| definitions.
///
/// @param mode Mode short-name ("n", "i", "v", ...)
/// @param buffer Buffer handle, or 0 for current buffer
/// @param mode Mode short-name ("n", "i", "v", ...)
/// @param[out] err Error details, if any
/// @returns Array of |maparg()|-like dictionaries describing mappings.
/// The "buffer" key holds the associated buffer handle.
@ -1223,6 +1224,7 @@ Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err)
return res;
}
/// @nodoc
Dictionary nvim__buf_stats(Buffer buffer, Arena *arena, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);

View File

@ -67,7 +67,7 @@
/// - file: (boolean) The command expands filenames. Which means characters such as "%",
/// "#" and wildcards are expanded.
/// - bar: (boolean) The "|" character is treated as a command separator and the double
/// quote character (\") is treated as the start of a comment.
/// quote character (") is treated as the start of a comment.
/// - mods: (dictionary) |:command-modifiers|.
/// - filter: (dictionary) |:filter|.
/// - pattern: (string) Filter pattern. Empty string if there is no filter.

View File

@ -61,8 +61,7 @@ Object nvim_execute_lua(String code, Array args, Arena *arena, Error *err)
/// Gets the buffer number
///
/// @deprecated The buffer number now is equal to the object id,
/// so there is no need to use this function.
/// @deprecated The buffer number now is equal to the object id
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param[out] err Error details, if any
@ -100,8 +99,7 @@ void nvim_buf_clear_highlight(Buffer buffer, Integer ns_id, Integer line_start,
/// Set the virtual text (annotation) for a buffer line.
///
/// @deprecated use nvim_buf_set_extmark to use full virtual text
/// functionality.
/// @deprecated use nvim_buf_set_extmark to use full virtual text functionality.
///
/// The text will be placed after the buffer text. Virtual text will never
/// cause reflow, rather virtual text will be truncated at the end of the screen
@ -119,7 +117,7 @@ void nvim_buf_clear_highlight(Buffer buffer, Integer ns_id, Integer line_start,
/// virtual text, the allocated id is then returned.
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace to use or 0 to create a namespace,
/// @param src_id Namespace to use or 0 to create a namespace,
/// or -1 for a ungrouped annotation
/// @param line Line to annotate with virtual text (zero-indexed)
/// @param chunks A list of [text, hl_group] arrays, each representing a

View File

@ -1205,6 +1205,7 @@ free_exit:
return virt_text;
}
/// @nodoc
String nvim__buf_debug_extmarks(Buffer buffer, Boolean keys, Boolean dot, Error *err)
FUNC_API_SINCE(7) FUNC_API_RET_ALLOC
{

View File

@ -272,21 +272,21 @@ Dictionary nvim_get_all_options_info(Arena *arena, Error *err)
/// Gets the option information for one option from arbitrary buffer or window
///
/// Resulting dictionary has keys:
/// - name: Name of the option (like 'filetype')
/// - shortname: Shortened name of the option (like 'ft')
/// - type: type of option ("string", "number" or "boolean")
/// - default: The default value for the option
/// - was_set: Whether the option was set.
/// - name: Name of the option (like 'filetype')
/// - shortname: Shortened name of the option (like 'ft')
/// - type: type of option ("string", "number" or "boolean")
/// - default: The default value for the option
/// - was_set: Whether the option was set.
///
/// - last_set_sid: Last set script id (if any)
/// - last_set_linenr: line number where option was set
/// - last_set_chan: Channel where option was set (0 for local)
/// - last_set_sid: Last set script id (if any)
/// - last_set_linenr: line number where option was set
/// - last_set_chan: Channel where option was set (0 for local)
///
/// - scope: one of "global", "win", or "buf"
/// - global_local: whether win or buf option has a global value
/// - scope: one of "global", "win", or "buf"
/// - global_local: whether win or buf option has a global value
///
/// - commalist: List of comma separated values
/// - flaglist: List of single char flags
/// - commalist: List of comma separated values
/// - flaglist: List of single char flags
///
/// When {scope} is not provided, the last set information applies to the local
/// value in the current buffer or window if it is available, otherwise the

View File

@ -165,7 +165,7 @@ void remote_ui_wait_for_attach(bool only_stdio)
/// Activates UI events on the channel.
///
/// Entry point of all UI clients. Allows |\-\-embed| to continue startup.
/// Entry point of all UI clients. Allows |--embed| to continue startup.
/// Implies that the client is ready to show the UI. Adds the client to the
/// list of UIs. |nvim_list_uis()|
///
@ -541,7 +541,7 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa
///
/// @param channel_id
/// @param event Event name
/// @param payload Event payload
/// @param value Event payload
/// @param[out] err Error details, if any.
void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *err)
FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY

View File

@ -123,7 +123,7 @@ Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, E
///
/// @note Unlike the `:highlight` command which can update a highlight group,
/// this function completely replaces the definition. For example:
/// ``nvim_set_hl(0, 'Visual', {})`` will clear the highlight group
/// `nvim_set_hl(0, 'Visual', {})` will clear the highlight group
/// 'Visual'.
///
/// @note The fg and bg keys also accept the string values `"fg"` or `"bg"`
@ -549,6 +549,7 @@ ArrayOf(String) nvim_list_runtime_paths(Arena *arena, Error *err)
return nvim_get_runtime_file(NULL_STRING, true, arena, err);
}
/// @nodoc
Array nvim__runtime_inspect(Arena *arena)
{
return runtime_inspect(arena);
@ -600,6 +601,7 @@ static bool find_runtime_cb(int num_fnames, char **fnames, bool all, void *c)
return num_fnames > 0;
}
/// @nodoc
String nvim__get_lib_dir(void)
FUNC_API_RET_ALLOC
{
@ -1547,14 +1549,14 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena)
/// @param channel_id
/// @param name Short name for the connected client
/// @param version Dictionary describing the version, with these
/// (optional) keys:
/// (optional) keys:
/// - "major" major version (defaults to 0 if not set, for no release yet)
/// - "minor" minor version
/// - "patch" patch number
/// - "prerelease" string describing a prerelease, like "dev" or "beta1"
/// - "commit" hash or similar identifier of commit
/// @param type Must be one of the following values. Client libraries should
/// default to "remote" unless overridden by the user.
/// default to "remote" unless overridden by the user.
/// - "remote" remote client connected "Nvim flavored" MessagePack-RPC (responses
/// must be in reverse order of requests). |msgpack-rpc|
/// - "msgpack-rpc" remote client connected to Nvim via fully MessagePack-RPC
@ -1565,12 +1567,12 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena)
/// - "host" plugin host, typically started by nvim
/// - "plugin" single plugin, started by nvim
/// @param methods Builtin methods in the client. For a host, this does not
/// include plugin methods which will be discovered later.
/// The key should be the method name, the values are dicts with
/// these (optional) keys (more keys may be added in future
/// versions of Nvim, thus unknown keys are ignored. Clients
/// must only use keys defined in this or later versions of
/// Nvim):
/// include plugin methods which will be discovered later.
/// The key should be the method name, the values are dicts with
/// these (optional) keys (more keys may be added in future
/// versions of Nvim, thus unknown keys are ignored. Clients
/// must only use keys defined in this or later versions of
/// Nvim):
/// - "async" if true, send as a notification. If false or unspecified,
/// use a blocking request
/// - "nargs" Number of arguments. Could be a single integer or an array
@ -1979,7 +1981,7 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Di
pum_ext_select_item((int)item, insert, finish);
}
/// NB: if your UI doesn't use hlstate, this will not return hlstate first time
/// NB: if your UI doesn't use hlstate, this will not return hlstate first time.
Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, Error *err)
{
Array ret = ARRAY_DICT_INIT;
@ -2015,6 +2017,7 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E
return ret;
}
/// @nodoc
void nvim__screenshot(String path)
FUNC_API_FAST
{
@ -2029,6 +2032,7 @@ void nvim__invalidate_glyph_cache(void)
must_redraw = UPD_CLEAR;
}
/// @nodoc
Object nvim__unpack(String str, Arena *arena, Error *err)
FUNC_API_FAST
{
@ -2319,6 +2323,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *
return result;
}
/// @nodoc
void nvim_error_event(uint64_t channel_id, Integer lvl, String data)
FUNC_API_REMOTE_ONLY
{

View File

@ -351,9 +351,7 @@ typedef struct {
Object *ret_node_p;
} ExprASTConvStackItem;
/// @cond DOXYGEN_NOT_A_FUNCTION
typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// @endcond
/// Parse a Vimscript expression.
///
@ -387,8 +385,8 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// - "arg": String, error message argument.
/// - "len": Amount of bytes successfully parsed. With flags equal to ""
/// that should be equal to the length of expr string.
/// (“Successfully parsed” here means “participated in AST
/// creation”, not “till the first error”.)
/// ("Successfully parsed" here means "participated in AST
/// creation", not "till the first error".)
/// - "ast": AST, either nil or a dictionary with these keys:
/// - "type": node type, one of the value names from ExprASTNodeType
/// stringified without "kExprNode" prefix.

View File

@ -116,12 +116,12 @@
/// - width: Window width (in character cells). Minimum of 1.
/// - height: Window height (in character cells). Minimum of 1.
/// - bufpos: Places float relative to buffer text (only when
/// relative="win"). Takes a tuple of zero-indexed [line, column].
/// `row` and `col` if given are applied relative to this
/// position, else they default to:
/// - `row=1` and `col=0` if `anchor` is "NW" or "NE"
/// - `row=0` and `col=0` if `anchor` is "SW" or "SE"
/// (thus like a tooltip near the buffer text).
/// relative="win"). Takes a tuple of zero-indexed [line, column].
/// `row` and `col` if given are applied relative to this
/// position, else they default to:
/// - `row=1` and `col=0` if `anchor` is "NW" or "NE"
/// - `row=0` and `col=0` if `anchor` is "SW" or "SE"
/// (thus like a tooltip near the buffer text).
/// - row: Row position in units of "screen cell height", may be fractional.
/// - col: Column position in units of "screen cell width", may be
/// fractional.
@ -153,7 +153,7 @@
/// 'fillchars' to a space char, and clearing the
/// |hl-EndOfBuffer| region in 'winhighlight'.
/// - border: Style of (optional) window border. This can either be a string
/// or an array. The string values are
/// or an array. The string values are
/// - "none": No border (default).
/// - "single": A single line box.
/// - "double": A double line box.
@ -161,21 +161,31 @@
/// - "solid": Adds padding by a single whitespace cell.
/// - "shadow": A drop shadow effect by blending with the background.
/// - If it is an array, it should have a length of eight or any divisor of
/// eight. The array will specify the eight chars building up the border
/// in a clockwise fashion starting with the top-left corner. As an
/// example, the double box style could be specified as
/// eight. The array will specify the eight chars building up the border
/// in a clockwise fashion starting with the top-left corner. As an
/// example, the double box style could be specified as:
/// ```
/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
/// If the number of chars are less than eight, they will be repeated. Thus
/// an ASCII border could be specified as
/// ```
/// If the number of chars are less than eight, they will be repeated. Thus
/// an ASCII border could be specified as
/// ```
/// [ "/", "-", \"\\\\\", "|" ],
/// or all chars the same as
/// ```
/// or all chars the same as
/// ```
/// [ "x" ].
/// ```
/// An empty string can be used to turn off a specific border, for instance,
/// ```
/// [ "", "", "", ">", "", "", "", "<" ]
/// ```
/// will only make vertical borders but not horizontal ones.
/// By default, `FloatBorder` highlight is used, which links to `WinSeparator`
/// when not defined. It could also be specified by character:
/// ```
/// [ ["+", "MyCorner"], ["x", "MyBorder"] ].
/// ```
/// - title: Title (optional) in window border, string or list.
/// List should consist of `[text, highlight]` tuples.
/// If string, the default highlight group is `FloatTitle`.

View File

@ -452,6 +452,7 @@ Object nvim_win_call(Window window, LuaRef fun, Error *err)
///
/// This takes precedence over the 'winhighlight' option.
///
/// @param window
/// @param ns_id the namespace to use
/// @param[out] err Error details, if any
void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err)

View File

@ -6,46 +6,74 @@ local lpeg = vim.lpeg
local P, R, S = lpeg.P, lpeg.R, lpeg.S
local C, Ct, Cc, Cg = lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg
--- @param pat vim.lpeg.Pattern
local function rep(pat)
return pat ^ 0
end
--- @param pat vim.lpeg.Pattern
local function rep1(pat)
return pat ^ 1
end
--- @param pat vim.lpeg.Pattern
local function opt(pat)
return pat ^ -1
end
local any = P(1) -- (consume one character)
local letter = R('az', 'AZ') + S('_$')
local num = R('09')
local alpha = letter + num
local nl = P('\r\n') + P('\n')
local not_nl = any - nl
local ws = S(' \t') + nl
local fill = ws ^ 0
local c_comment = P('//') * (not_nl ^ 0)
local c_preproc = P('#') * (not_nl ^ 0)
local dllexport = P('DLLEXPORT') * (ws ^ 1)
local typed_container = (P('ArrayOf(') + P('DictionaryOf(') + P('Dict('))
* ((any - P(')')) ^ 1)
local space = S(' \t')
local ws = space + nl
local fill = rep(ws)
local c_comment = P('//') * rep(not_nl)
local cdoc_comment = P('///') * opt(Ct(Cg(rep(space) * rep(not_nl), 'comment')))
local c_preproc = P('#') * rep(not_nl)
local dllexport = P('DLLEXPORT') * rep1(ws)
local typed_container = (
(P('ArrayOf(') + P('DictionaryOf(') + P('Dict('))
* rep1(any - P(')'))
* P(')')
local c_id = (typed_container + (letter * (alpha ^ 0)))
)
local c_id = (typed_container + (letter * rep(alpha)))
local c_void = P('void')
local c_param_type = (
((P('Error') * fill * P('*') * fill) * Cc('error'))
+ ((P('Arena') * fill * P('*') * fill) * Cc('arena'))
+ ((P('lua_State') * fill * P('*') * fill) * Cc('lstate'))
+ C((P('const ') ^ -1) * c_id * (ws ^ 1) * P('*'))
+ (C(c_id) * (ws ^ 1))
+ C(opt(P('const ')) * c_id * rep1(ws) * rep1(P('*')))
+ (C(c_id) * rep1(ws))
)
local c_type = (C(c_void) * (ws ^ 1)) + c_param_type
local c_param = Ct(c_param_type * C(c_id))
local c_param_list = c_param * (fill * (P(',') * fill * c_param) ^ 0)
local c_params = Ct(c_void + c_param_list)
local impl_line = (any - P('}')) * opt(rep(not_nl)) * nl
local ignore_line = rep1(not_nl) * nl
local empty_line = Ct(Cc('empty') * nl * nl)
local c_proto = Ct(
(dllexport ^ -1)
Cc('proto')
* opt(dllexport)
* opt(Cg(P('static') * fill * Cc(true), 'static'))
* Cg(c_type, 'return_type')
* Cg(c_id, 'name')
* fill
* P('(')
* fill
* Cg(c_params, 'parameters')
* fill
* P(')')
* (P('(') * fill * Cg(c_params, 'parameters') * fill * P(')'))
* Cg(Cc(false), 'fast')
* (fill * Cg((P('FUNC_API_SINCE(') * C(num ^ 1)) * P(')'), 'since') ^ -1)
* (fill * Cg((P('FUNC_API_DEPRECATED_SINCE(') * C(num ^ 1)) * P(')'), 'deprecated_since') ^ -1)
* (fill * Cg((P('FUNC_API_SINCE(') * C(rep1(num))) * P(')'), 'since') ^ -1)
* (fill * Cg((P('FUNC_API_DEPRECATED_SINCE(') * C(rep1(num))) * P(')'), 'deprecated_since') ^ -1)
* (fill * Cg((P('FUNC_API_FAST') * Cc(true)), 'fast') ^ -1)
* (fill * Cg((P('FUNC_API_RET_ALLOC') * Cc(true)), 'ret_alloc') ^ -1)
* (fill * Cg((P('FUNC_API_NOEXPORT') * Cc(true)), 'noexport') ^ -1)
@ -60,7 +88,7 @@ local c_proto = Ct(
* (fill * Cg((P('FUNC_API_CLIENT_IMPL') * Cc(true)), 'client_impl') ^ -1)
* (fill * Cg((P('FUNC_API_CLIENT_IGNORE') * Cc(true)), 'client_ignore') ^ -1)
* fill
* P(';')
* (P(';') + (P('{') * nl + (impl_line ^ 0) * P('}')))
)
local c_field = Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * P(';') * fill)
@ -83,5 +111,7 @@ local c_keyset = Ct(
* P(';')
)
local grammar = Ct((c_proto + c_comment + c_preproc + ws + c_keyset) ^ 1)
local grammar = Ct(
rep1(empty_line + c_proto + cdoc_comment + c_comment + c_preproc + ws + c_keyset + ignore_line)
)
return { grammar = grammar, typed_container = typed_container }

View File

@ -23,9 +23,7 @@ local function_names = {}
local c_grammar = require('generators.c_grammar')
local function startswith(String, Start)
return string.sub(String, 1, string.len(Start)) == Start
end
local startswith = vim.startswith
local function add_function(fn)
local public = startswith(fn.name, 'nvim_') or fn.deprecated_since
@ -112,10 +110,12 @@ for i = 6, #arg do
local tmp = c_grammar.grammar:match(input:read('*all'))
for j = 1, #tmp do
local val = tmp[j]
if val.keyset_name then
add_keyset(val)
else
add_function(val)
if val[1] ~= 'empty' then
if val.keyset_name then
add_keyset(val)
else
add_function(val)
end
end
end
input:close()

View File

@ -93,6 +93,10 @@ local function call_ui_event_method(output, ev)
output:write('}\n\n')
end
events = vim.tbl_filter(function(ev)
return ev[1] ~= 'empty'
end, events)
for i = 1, #events do
local ev = events[i]
assert(ev.return_type == 'void')

View File

@ -1,136 +0,0 @@
--[[!
LPEG grammar for LuaCATS
Currently only partially supports:
- @param
- @return
]]
local lpeg = vim.lpeg
local P, R, S = lpeg.P, lpeg.R, lpeg.S
local Ct, Cg = lpeg.Ct, lpeg.Cg
--- @param x vim.lpeg.Pattern
local function rep(x)
return x ^ 0
end
--- @param x vim.lpeg.Pattern
local function rep1(x)
return x ^ 1
end
--- @param x vim.lpeg.Pattern
local function opt(x)
return x ^ -1
end
local nl = P('\r\n') + P('\n')
local ws = rep1(S(' \t') + nl)
local fill = opt(ws)
local any = P(1) -- (consume one character)
local letter = R('az', 'AZ') + S('_$')
local num = R('09')
local ident = letter * rep(letter + num + S '-.')
local string_single = P "'" * rep(any - P "'") * P "'"
local string_double = P '"' * rep(any - P '"') * P '"'
local literal = (string_single + string_double + (opt(P '-') * num) + P 'false' + P 'true')
local lname = (ident + P '...') * opt(P '?')
--- @param x string
local function Pf(x)
return fill * P(x) * fill
end
--- @param x string
local function Sf(x)
return fill * S(x) * fill
end
--- @param x vim.lpeg.Pattern
local function comma(x)
return x * rep(Pf ',' * x)
end
--- @param x vim.lpeg.Pattern
local function parenOpt(x)
return (Pf('(') * x ^ -1 * fill * P(')')) + x ^ -1
end
--- @type table<string,vim.lpeg.Pattern>
local v = setmetatable({}, {
__index = function(_, k)
return lpeg.V(k)
end,
})
local desc_delim = Sf '#:' + ws
--- @class luacats.Param
--- @field kind 'param'
--- @field name string
--- @field type string
--- @field desc? string
--- @class luacats.Return
--- @field kind 'return'
--- @field [integer] { type: string, name?: string}
--- @field desc? string
--- @class luacats.Generic
--- @field kind 'generic'
--- @field name string
--- @field type? string
--- @alias luacats.grammar.result
--- | luacats.Param
--- | luacats.Return
--- | luacats.Generic
--- @class luacats.grammar
--- @field match fun(self, input: string): luacats.grammar.result?
local grammar = P {
rep1(P('@') * v.ats),
ats = (v.at_param + v.at_return + v.at_generic),
at_param = Ct(
Cg(P('param'), 'kind')
* ws
* Cg(lname, 'name')
* ws
* Cg(v.ltype, 'type')
* opt(desc_delim * Cg(rep(any), 'desc'))
),
at_return = Ct(
Cg(P('return'), 'kind')
* ws
* parenOpt(comma(Ct(Cg(v.ltype, 'type') * opt(ws * Cg(ident, 'name')))))
* opt(desc_delim * Cg(rep(any), 'desc'))
),
at_generic = Ct(
Cg(P('generic'), 'kind') * ws * Cg(ident, 'name') * opt(Pf ':' * Cg(v.ltype, 'type'))
),
ltype = v.ty_union + Pf '(' * v.ty_union * fill * P ')',
ty_union = v.ty_opt * rep(Pf '|' * v.ty_opt),
ty = v.ty_fun + ident + v.ty_table + literal,
ty_param = Pf '<' * comma(v.ltype) * fill * P '>',
ty_opt = v.ty * opt(v.ty_param) * opt(P '[]') * opt(P '?'),
table_key = (Pf '[' * literal * Pf ']') + lname,
table_elem = v.table_key * Pf ':' * v.ltype,
ty_table = Pf '{' * comma(v.table_elem) * Pf '}',
fun_param = lname * opt(Pf ':' * v.ltype),
ty_fun = Pf 'fun(' * rep(comma(v.fun_param)) * fill * P ')' * opt(Pf ':' * v.ltype),
}
return grammar --[[@as luacats.grammar]]

View File

@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local grammar = require('src/nvim/generators/luacats_grammar')
local grammar = require('scripts/luacats_grammar')
describe('luacats grammar', function()
--- @param text string
@ -85,7 +85,7 @@ describe('luacats grammar', function()
test('@param level (integer|string) desc', {
kind = 'param',
name = 'level',
type = '(integer|string)',
type = 'integer|string',
desc = 'desc',
})

View File

@ -0,0 +1,39 @@
local helpers = require('test.functional.helpers')(after_each)
local exec_lua = helpers.exec_lua
local eq = helpers.eq
local function md_to_vimdoc(text)
return exec_lua(
[[
local text_utils = require('scripts/text_utils')
return text_utils.md_to_vimdoc(table.concat(..., '\n'), 0, 0, 70)
]],
text
)
end
local function test(act, exp)
eq(table.concat(exp, '\n'), md_to_vimdoc(act))
end
describe('md_to_vimdoc', function()
before_each(function()
helpers.clear()
end)
it('can render para after fenced code', function()
test({
'- Para1',
' ```',
' code',
' ```',
' Para2',
}, {
'• Para1 >',
' code',
'<',
' Para2',
'',
})
end)
end)