From 9beb40a4db5613601fc1a4b828a44e5977eca046 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 15 Feb 2024 17:16:04 +0000 Subject: [PATCH] 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). --- .github/workflows/docs.yml | 4 - CONTRIBUTING.md | 15 +- contrib/flake.nix | 1 - contrib/local.mk.example | 6 - runtime/doc/api.txt | 232 +-- runtime/doc/diagnostic.txt | 17 +- runtime/doc/lsp.txt | 59 +- runtime/doc/lua.txt | 414 ++-- runtime/doc/treesitter.txt | 57 +- runtime/lua/vim/_editor.lua | 14 +- runtime/lua/vim/_inspector.lua | 4 +- runtime/lua/vim/_meta/api.lua | 843 ++++---- runtime/lua/vim/_meta/builtin.lua | 100 +- runtime/lua/vim/_meta/json.lua | 2 +- runtime/lua/vim/_meta/lpeg.lua | 23 +- runtime/lua/vim/_meta/mpack.lua | 5 +- runtime/lua/vim/_meta/re.lua | 13 +- runtime/lua/vim/_meta/regex.lua | 2 - runtime/lua/vim/_options.lua | 300 ++- runtime/lua/vim/diagnostic.lua | 125 +- runtime/lua/vim/filetype.lua | 6 +- runtime/lua/vim/fs.lua | 2 +- runtime/lua/vim/highlight.lua | 15 +- runtime/lua/vim/iter.lua | 8 +- runtime/lua/vim/keymap.lua | 2 + runtime/lua/vim/loader.lua | 13 +- runtime/lua/vim/lsp.lua | 176 +- runtime/lua/vim/lsp/buf.lua | 35 +- runtime/lua/vim/lsp/codelens.lua | 2 + runtime/lua/vim/lsp/diagnostic.lua | 4 +- runtime/lua/vim/lsp/handlers.lua | 5 +- runtime/lua/vim/lsp/log.lua | 2 +- runtime/lua/vim/lsp/rpc.lua | 2 - runtime/lua/vim/lsp/sync.lua | 4 +- runtime/lua/vim/lsp/util.lua | 8 +- runtime/lua/vim/shared.lua | 92 +- runtime/lua/vim/snippet.lua | 2 - runtime/lua/vim/treesitter.lua | 2 +- runtime/lua/vim/treesitter/_query_linter.lua | 2 +- runtime/lua/vim/treesitter/highlighter.lua | 1 - runtime/lua/vim/treesitter/languagetree.lua | 4 +- runtime/lua/vim/treesitter/query.lua | 4 +- runtime/lua/vim/uri.lua | 3 +- runtime/lua/vim/version.lua | 9 +- scripts/cdoc_grammar.lua | 87 + scripts/cdoc_parser.lua | 223 +++ scripts/gen_eval_files.lua | 106 +- scripts/gen_vimdoc.lua | 787 ++++++++ scripts/gen_vimdoc.py | 1766 ----------------- scripts/lua2dox.lua | 544 ----- scripts/luacats_grammar.lua | 218 ++ scripts/luacats_parser.lua | 521 +++++ scripts/text_utils.lua | 239 +++ src/nvim/CMakeLists.txt | 24 +- src/nvim/api/autocmd.c | 12 +- src/nvim/api/buffer.c | 10 +- src/nvim/api/command.c | 2 +- src/nvim/api/deprecated.c | 8 +- src/nvim/api/extmark.c | 1 + src/nvim/api/options.c | 24 +- src/nvim/api/ui.c | 4 +- src/nvim/api/vim.c | 25 +- src/nvim/api/vimscript.c | 6 +- src/nvim/api/win_config.c | 36 +- src/nvim/api/window.c | 1 + src/nvim/generators/c_grammar.lua | 70 +- src/nvim/generators/gen_api_dispatch.lua | 14 +- src/nvim/generators/gen_api_ui_events.lua | 4 + src/nvim/generators/luacats_grammar.lua | 136 -- .../{ => script}/luacats_grammar_spec.lua | 4 +- test/functional/script/text_utils_spec.lua | 39 + 71 files changed, 3701 insertions(+), 3849 deletions(-) create mode 100644 scripts/cdoc_grammar.lua create mode 100644 scripts/cdoc_parser.lua create mode 100755 scripts/gen_vimdoc.lua delete mode 100755 scripts/gen_vimdoc.py delete mode 100644 scripts/lua2dox.lua create mode 100644 scripts/luacats_grammar.lua create mode 100644 scripts/luacats_parser.lua create mode 100644 scripts/text_utils.lua delete mode 100644 src/nvim/generators/luacats_grammar.lua rename test/functional/{ => script}/luacats_grammar_spec.lua (96%) create mode 100644 test/functional/script/text_utils_spec.lua diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 83e7c77dc9..c91f2945fb 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d0e463866b..2f5c2cce5a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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: ``` diff --git a/contrib/flake.nix b/contrib/flake.nix index 51c2014d6c..6355f3a68a 100644 --- a/contrib/flake.nix +++ b/contrib/flake.nix @@ -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; diff --git a/contrib/local.mk.example b/contrib/local.mk.example index bda2c1b4dc..4e8a510f2d 100644 --- a/contrib/local.mk.example +++ b/contrib/local.mk.example @@ -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 diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index e994644be9..1b00777532 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -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 || • 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: diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index bee0445e4e..dbfa0148af 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -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: diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index a94de629b2..c14c0e5b9c 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -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: diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 94b37ad7c6..f56d7f778a 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -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 = { - ['.*‍/etc/foo/.*'] = 'fooscript', + ['.*/etc/foo/.*'] = 'fooscript', -- Using an optional priority - ['.*‍/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("+-*‍/")` 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: diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 8a3770bf27..09c086b7f7 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -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`) + vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl: diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index c5a6e65e86..4e39abb2be 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -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 diff --git a/runtime/lua/vim/_inspector.lua b/runtime/lua/vim/_inspector.lua index 3f7b9d2c23..9a073c32c4 100644 --- a/runtime/lua/vim/_inspector.lua +++ b/runtime/lua/vim/_inspector.lua @@ -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) diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index aee866f324..d2f624fd97 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -38,6 +38,7 @@ function vim.api.nvim__get_runtime(pat, all, opts) end --- @private --- Returns object given as argument. +--- --- This API function is used for testing. One should not rely on its presence --- in plugins. --- @@ -47,6 +48,7 @@ function vim.api.nvim__id(obj) end --- @private --- Returns array given as argument. +--- --- This API function is used for testing. One should not rely on its presence --- in plugins. --- @@ -56,6 +58,7 @@ function vim.api.nvim__id_array(arr) end --- @private --- Returns dictionary given as argument. +--- --- This API function is used for testing. One should not rely on its presence --- in plugins. --- @@ -65,6 +68,7 @@ function vim.api.nvim__id_dictionary(dct) end --- @private --- Returns floating-point value given as argument. +--- --- This API function is used for testing. One should not rely on its presence --- in plugins. --- @@ -108,17 +112,20 @@ function vim.api.nvim__stats() end function vim.api.nvim__unpack(str) end --- Adds a highlight to buffer. +--- --- Useful for plugins that dynamically generate highlights to a buffer (like --- a semantic highlighter or linter). The function adds a single highlight to --- a buffer. Unlike `matchaddpos()` highlights follow changes to line --- numbering (as lines are inserted/removed above the highlighted line), like --- signs and marks do. +--- --- Namespaces are used for batch deletion/updating of a set of highlights. To --- create a namespace, use `nvim_create_namespace()` which returns a --- namespace id. Pass it in to this function as `ns_id` to add highlights to --- the namespace. All highlights in the same namespace can then be cleared --- with single call to `nvim_buf_clear_namespace()`. If the highlight never --- will be deleted by an API call, pass `ns_id = -1`. +--- --- As a shorthand, `ns_id = 0` can be used to create a new namespace for the --- highlight, the allocated id is then returned. If `hl_group` is the empty --- string no highlight is added, but a new `ns_id` is still returned. This is @@ -131,11 +138,12 @@ function vim.api.nvim__unpack(str) end --- @param line integer Line to highlight (zero-indexed) --- @param col_start integer Start of (byte-indexed) column range to highlight --- @param col_end integer End of (byte-indexed) column range to highlight, or -1 to ---- highlight to end of line +--- highlight to end of line --- @return integer function vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start, col_end) end --- Activates buffer-update events on a channel, or as Lua callbacks. +--- --- Example (Lua): capture buffer updates in a global `events` variable (use --- "vim.print(events)" to see its contents): --- @@ -148,6 +156,7 @@ function vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start --- }) --- ``` --- +--- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param send_buffer boolean True if the initial notification should contain the --- whole buffer: first notification will be @@ -155,77 +164,70 @@ function vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start --- will be `nvim_buf_changedtick_event`. Not for Lua --- callbacks. --- @param opts vim.api.keyset.buf_attach Optional parameters. ---- • on_lines: Lua callback invoked on change. Return a ---- truthy value (not `false` or `nil`) ---- to detach. Args: ---- • the string "lines" ---- • buffer handle ---- • b:changedtick ---- • first line that changed (zero-indexed) ---- • last line that was changed ---- • last line in the updated range ---- • 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: ---- • the string "bytes" ---- • buffer handle ---- • b:changedtick ---- • start row of the changed text (zero-indexed) ---- • start column of the changed text ---- • byte offset of the changed text (from the start of ---- the buffer) ---- • old end row of the changed text (offset from start ---- row) ---- • old end column of the changed text (if old end row ---- = 0, offset from start column) ---- • old end byte length of the changed text ---- • new end row of the changed text (offset from start ---- row) ---- • 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. ---- 'inccommand') events. +--- • on_lines: Lua callback invoked on change. Return a truthy +--- value (not `false` or `nil`) to detach. Args: +--- • the string "lines" +--- • buffer handle +--- • b:changedtick +--- • first line that changed (zero-indexed) +--- • last line that was changed +--- • last line in the updated range +--- • 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: +--- • the string "bytes" +--- • buffer handle +--- • b:changedtick +--- • start row of the changed text (zero-indexed) +--- • start column of the changed text +--- • byte offset of the changed text (from the start of the +--- buffer) +--- • old end row of the changed text (offset from start row) +--- • old end column of the changed text (if old end row = 0, +--- offset from start column) +--- • old end byte length of the changed text +--- • new end row of the changed text (offset from start row) +--- • 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. 'inccommand') +--- events. --- @return boolean function vim.api.nvim_buf_attach(buffer, send_buffer, opts) end --- call a function with buffer as temporary current buffer +--- --- This temporarily switches current buffer to "buffer". If the current --- window already shows "buffer", the window is not switched If a window --- inside the current tabpage (including a float) already shows the buffer --- One of these windows will be set as current window temporarily. Otherwise --- a temporary scratch window (called the "autocmd window" for historical --- reasons) will be used. +--- --- This is useful e.g. to call Vimscript functions that only work with the --- current buffer/window currently, like `termopen()`. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param fun function Function to call inside the buffer (currently Lua callable ---- only) +--- only) --- @return any function vim.api.nvim_buf_call(buffer, fun) end @@ -238,14 +240,15 @@ function vim.api.nvim_buf_clear_highlight(buffer, ns_id, line_start, line_end) e --- Clears `namespace`d objects (highlights, `extmarks`, virtual text) from a --- region. +--- --- Lines are 0-indexed. `api-indexing` To clear the namespace in the entire --- buffer, specify line_start=0 and line_end=-1. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param ns_id integer Namespace to clear, or -1 to clear all namespaces. --- @param line_start integer Start of range of lines to clear ---- @param line_end integer End of range of lines to clear (exclusive) or -1 to ---- clear to end of buffer. +--- @param line_end integer End of range of lines to clear (exclusive) or -1 to clear +--- to end of buffer. function vim.api.nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end) end --- Creates a buffer-local command `user-commands`. @@ -279,6 +282,7 @@ function vim.api.nvim_buf_del_keymap(buffer, mode, lhs) end function vim.api.nvim_buf_del_mark(buffer, name) end --- Delete a buffer-local user-defined command. +--- --- Only commands created with `:command-buffer` or --- `nvim_buf_create_user_command()` can be deleted with this function. --- @@ -296,8 +300,8 @@ function vim.api.nvim_buf_del_var(buffer, name) end --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param opts vim.api.keyset.buf_delete Optional parameters. Keys: ---- • force: Force deletion and ignore unsaved changes. ---- • unload: Unloaded only, do not delete. See `:bunload` +--- • force: Force deletion and ignore unsaved changes. +--- • unload: Unloaded only, do not delete. See `:bunload` function vim.api.nvim_buf_delete(buffer, opts) end --- Gets a changed tick of a buffer @@ -319,14 +323,15 @@ function vim.api.nvim_buf_get_commands(buffer, opts) end --- @param ns_id integer Namespace id from `nvim_create_namespace()` --- @param id integer Extmark id --- @param opts vim.api.keyset.get_extmark Optional parameters. Keys: ---- • details: Whether to include the details dict ---- • hl_name: Whether to include highlight group name instead ---- of id, true if omitted +--- • details: Whether to include the details dict +--- • hl_name: Whether to include highlight group name instead of +--- id, true if omitted --- @return vim.api.keyset.get_extmark_item function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end --- Gets `extmarks` in "traversal order" from a `charwise` region defined by --- buffer positions (inclusive, 0-indexed `api-indexing`). +--- --- Region can be given as (row,col) tuples, or valid extmark ids (whose --- positions define the bounds). 0 and -1 are understood as (0,0) and (-1,-1) --- respectively, thus the following are equivalent: @@ -338,12 +343,15 @@ function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end --- --- If `end` is less than `start`, traversal works backwards. (Useful with --- `limit`, to get the first marks prior to a given position.) +--- --- Note: when using extmark ranges (marks with a end_row/end_col position) --- the `overlap` option might be useful. Otherwise only the start position of --- an extmark will be considered. +--- --- Note: legacy signs placed through the `:sign` commands are implemented as --- extmarks and will show up here. Their details array will contain a --- `sign_name` field. +--- --- Example: --- --- ```lua @@ -361,23 +369,23 @@ function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end --- vim.print(ms) --- ``` --- +--- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param ns_id integer Namespace id from `nvim_create_namespace()` or -1 for all ---- namespaces +--- namespaces --- @param start any Start of range: a 0-indexed (row, col) or valid extmark id ---- (whose position defines the bound). `api-indexing` +--- (whose position defines the bound). `api-indexing` --- @param end_ any End of range (inclusive): a 0-indexed (row, col) or valid ---- extmark id (whose position defines the bound). ---- `api-indexing` +--- extmark id (whose position defines the bound). `api-indexing` --- @param opts vim.api.keyset.get_extmarks Optional parameters. Keys: ---- • limit: Maximum number of marks to return ---- • details: Whether to include the details dict ---- • hl_name: Whether to include highlight group name instead ---- of id, true if omitted ---- • overlap: Also include marks which overlap the range, even ---- if their start position is less than `start` ---- • type: Filter marks by type: "highlight", "sign", ---- "virt_text" and "virt_lines" +--- • limit: Maximum number of marks to return +--- • details: Whether to include the details dict +--- • hl_name: Whether to include highlight group name instead of +--- id, true if omitted +--- • overlap: Also include marks which overlap the range, even if +--- their start position is less than `start` +--- • type: Filter marks by type: "highlight", "sign", "virt_text" +--- and "virt_lines" --- @return vim.api.keyset.get_extmark_item[] function vim.api.nvim_buf_get_extmarks(buffer, ns_id, start, end_, opts) end @@ -389,9 +397,11 @@ function vim.api.nvim_buf_get_extmarks(buffer, ns_id, start, end_, opts) end function vim.api.nvim_buf_get_keymap(buffer, mode) end --- Gets a line-range from the buffer. +--- --- Indexing is zero-based, end-exclusive. Negative indices are interpreted as --- length+1+index: -1 refers to the index past the end. So to get the last --- element use start=-2 and end=-1. +--- --- Out-of-bounds indices are clamped to the nearest valid value, unless --- `strict_indexing` is set. --- @@ -405,6 +415,7 @@ function vim.api.nvim_buf_get_lines(buffer, start, end_, strict_indexing) end --- Returns a `(row,col)` tuple representing the position of the named mark. --- "End of line" column position is returned as `v:maxcol` (big number). See --- `mark-motions`. +--- --- Marks are (1,0)-indexed. `api-indexing` --- --- @param buffer integer Buffer handle, or 0 for current buffer @@ -424,10 +435,12 @@ function vim.api.nvim_buf_get_name(buffer) end function vim.api.nvim_buf_get_number(buffer) end --- Returns the byte offset of a line (0-indexed). `api-indexing` +--- --- Line 1 (index=0) has offset 0. UTF-8 bytes are counted. EOL is one byte. --- 'fileformat' and 'fileencoding' are ignored. The line index just after the --- last line gives the total byte-count of the buffer. A final EOL byte is --- counted if it would be written, see 'eol'. +--- --- Unlike `line2byte()`, throws error for out-of-bounds indexing. Returns -1 --- for unloaded buffer. --- @@ -443,10 +456,13 @@ function vim.api.nvim_buf_get_offset(buffer, index) end function vim.api.nvim_buf_get_option(buffer, name) end --- Gets a range from the buffer. +--- --- This differs from `nvim_buf_get_lines()` in that it allows retrieving only --- portions of a line. +--- --- Indexing is zero-based. Row indices are end-inclusive, and column indices --- are end-exclusive. +--- --- Prefer `nvim_buf_get_lines()` when retrieving entire lines. --- --- @param buffer integer Buffer handle, or 0 for current buffer @@ -485,13 +501,16 @@ function vim.api.nvim_buf_is_valid(buffer) end function vim.api.nvim_buf_line_count(buffer) end --- Creates or updates an `extmark`. +--- --- By default a new extmark is created when no id is passed in, but it is --- also possible to create a new mark by passing in a previously unused id or --- move an existing mark by passing in its id. The caller must then keep --- track of existing and unused ids itself. (Useful over RPC, to avoid --- waiting for the return value.) +--- --- Using the optional arguments, it is possible to use this to highlight a --- range of text, and also to associate virtual text to the mark. +--- --- If present, the position defined by `end_col` and `end_row` should be --- after the start position in order for the extmark to cover a range. An --- earlier end position is not an error, but then it behaves like an empty @@ -502,114 +521,110 @@ function vim.api.nvim_buf_line_count(buffer) end --- @param line integer Line where to place the mark, 0-based. `api-indexing` --- @param col integer Column where to place the mark, 0-based. `api-indexing` --- @param opts vim.api.keyset.set_extmark Optional parameters. ---- • id : id of the extmark to edit. ---- • end_row : ending line of the mark, 0-based inclusive. ---- • end_col : ending col of the mark, 0-based exclusive. ---- • hl_group : name of the highlight group used to highlight ---- this mark. ---- • hl_eol : when true, for a multiline highlight covering the ---- EOL of a line, continue the highlight for the rest of the ---- screen line (just like for diff and cursorline highlight). ---- • virt_text : virtual text to link to this mark. A list of ---- [text, highlight] tuples, each representing a text chunk ---- with specified highlight. `highlight` element can either ---- be a single highlight group, or an array of multiple ---- highlight groups that will be stacked (highest priority ---- last). A highlight group can be supplied either as a ---- string or as an integer, the latter which can be obtained ---- using `nvim_get_hl_id_by_name()`. ---- • virt_text_pos : position of virtual text. Possible values: ---- • "eol": right after eol character (default). ---- • "overlay": display over the specified column, without ---- shifting the underlying text. ---- • "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". ---- • virt_text_hide : hide the virtual text when the background ---- text is selected or hidden because of scrolling with ---- 'nowrap' or 'smoothscroll'. Currently only affects ---- "overlay" virt_text. ---- • virt_text_repeat_linebreak : repeat the virtual text on ---- 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. ---- • "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 ---- and window options do not affect the display of the text. ---- In particular 'wrap' and 'linebreak' options do not take ---- effect, so the number of extra screen lines will always ---- match the size of the array. However the 'tabstop' buffer ---- option is still used for hard tabs. By default lines are ---- placed below the buffer line containing the mark. ---- • virt_lines_above: place virtual lines above instead. ---- • virt_lines_leftcol: Place extmarks in the leftmost column ---- of the window, bypassing sign and number columns. ---- • ephemeral : for use with `nvim_set_decoration_provider()` ---- callbacks. The mark will only be used for the current ---- redraw cycle, and not be permantently stored in the ---- buffer. ---- • right_gravity : boolean that indicates the direction the ---- extmark will be shifted in when new text is inserted (true ---- for right, false for left). Defaults to true. ---- • end_right_gravity : boolean that indicates the direction ---- the extmark end position (if it exists) will be shifted in ---- when new text is inserted (true for right, false for ---- left). Defaults to false. ---- • undo_restore : Restore the exact position of the mark if ---- text around the mark was deleted and then restored by ---- undo. Defaults to true. ---- • invalidate : boolean that indicates whether to hide the ---- extmark if the entirety of its range is deleted. For ---- hidden marks, an "invalid" key is added to the "details" ---- array of `nvim_buf_get_extmarks()` and family. If ---- "undo_restore" is false, the extmark is deleted instead. ---- • priority: a priority value for the highlight group, sign ---- attribute or virtual text. For virtual text, item with ---- highest priority is drawn last. For example treesitter ---- highlighting uses a value of 100. ---- • strict: boolean that indicates extmark should not be ---- placed if the line or column value is past the end of the ---- buffer or end of the line respectively. Defaults to true. ---- • sign_text: string of length 1-2 used to display in the ---- sign column. ---- • sign_hl_group: name of the highlight group used to ---- highlight the sign column text. ---- • number_hl_group: name of the highlight group used to ---- highlight the number column. ---- • line_hl_group: name of the highlight group used to ---- highlight the whole line. ---- • cursorline_hl_group: name of the highlight group used to ---- highlight the sign column text when the cursor is on the ---- same line as the mark and 'cursorline' is enabled. ---- • conceal: string which should be either empty or a single ---- character. Enable concealing similar to `:syn-conceal`. ---- When a character is supplied it is used as `:syn-cchar`. ---- "hl_group" is used as highlight for the cchar if provided, ---- otherwise it defaults to `hl-Conceal`. ---- • spell: boolean indicating that spell checking should be ---- performed within this extmark ---- • ui_watched: boolean that indicates the mark should be ---- drawn by a UI. When set, the UI will receive win_extmark ---- events. Note: the mark is positioned by virt_text ---- attributes. Can be used together with virt_text. ---- • url: A URL to associate with this extmark. In the TUI, the ---- OSC 8 control sequence is used to generate a clickable ---- hyperlink to this URL. ---- • scoped: boolean that indicates that the extmark should ---- only be displayed in the namespace scope. (experimental) +--- • id : id of the extmark to edit. +--- • end_row : ending line of the mark, 0-based inclusive. +--- • end_col : ending col of the mark, 0-based exclusive. +--- • hl_group : name of the highlight group used to highlight +--- this mark. +--- • hl_eol : when true, for a multiline highlight covering the +--- EOL of a line, continue the highlight for the rest of the +--- screen line (just like for diff and cursorline highlight). +--- • virt_text : virtual text to link to this mark. A list of +--- [text, highlight] tuples, each representing a text chunk +--- with specified highlight. `highlight` element can either be +--- a single highlight group, or an array of multiple highlight +--- groups that will be stacked (highest priority last). A +--- highlight group can be supplied either as a string or as an +--- integer, the latter which can be obtained using +--- `nvim_get_hl_id_by_name()`. +--- • virt_text_pos : position of virtual text. Possible values: +--- • "eol": right after eol character (default). +--- • "overlay": display over the specified column, without +--- shifting the underlying text. +--- • "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". +--- • virt_text_hide : hide the virtual text when the background +--- text is selected or hidden because of scrolling with +--- 'nowrap' or 'smoothscroll'. Currently only affects "overlay" +--- virt_text. +--- • virt_text_repeat_linebreak : repeat the virtual text on +--- 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. +--- • "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 and +--- window options do not affect the display of the text. In +--- particular 'wrap' and 'linebreak' options do not take +--- effect, so the number of extra screen lines will always +--- match the size of the array. However the 'tabstop' buffer +--- option is still used for hard tabs. By default lines are +--- placed below the buffer line containing the mark. +--- • virt_lines_above: place virtual lines above instead. +--- • virt_lines_leftcol: Place extmarks in the leftmost column of +--- the window, bypassing sign and number columns. +--- • ephemeral : for use with `nvim_set_decoration_provider()` +--- callbacks. The mark will only be used for the current redraw +--- cycle, and not be permantently stored in the buffer. +--- • right_gravity : boolean that indicates the direction the +--- extmark will be shifted in when new text is inserted (true +--- for right, false for left). Defaults to true. +--- • end_right_gravity : boolean that indicates the direction the +--- extmark end position (if it exists) will be shifted in when +--- new text is inserted (true for right, false for left). +--- Defaults to false. +--- • undo_restore : Restore the exact position of the mark if +--- text around the mark was deleted and then restored by undo. +--- Defaults to true. +--- • invalidate : boolean that indicates whether to hide the +--- extmark if the entirety of its range is deleted. For hidden +--- marks, an "invalid" key is added to the "details" array of +--- `nvim_buf_get_extmarks()` and family. If "undo_restore" is +--- false, the extmark is deleted instead. +--- • priority: a priority value for the highlight group, sign +--- attribute or virtual text. For virtual text, item with +--- highest priority is drawn last. For example treesitter +--- highlighting uses a value of 100. +--- • strict: boolean that indicates extmark should not be placed +--- if the line or column value is past the end of the buffer or +--- end of the line respectively. Defaults to true. +--- • sign_text: string of length 1-2 used to display in the sign +--- column. +--- • sign_hl_group: name of the highlight group used to highlight +--- the sign column text. +--- • number_hl_group: name of the highlight group used to +--- highlight the number column. +--- • line_hl_group: name of the highlight group used to highlight +--- the whole line. +--- • cursorline_hl_group: name of the highlight group used to +--- highlight the sign column text when the cursor is on the +--- same line as the mark and 'cursorline' is enabled. +--- • conceal: string which should be either empty or a single +--- character. Enable concealing similar to `:syn-conceal`. When +--- a character is supplied it is used as `:syn-cchar`. +--- "hl_group" is used as highlight for the cchar if provided, +--- otherwise it defaults to `hl-Conceal`. +--- • spell: boolean indicating that spell checking should be +--- performed within this extmark +--- • ui_watched: boolean that indicates the mark should be drawn +--- by a UI. When set, the UI will receive win_extmark events. +--- Note: the mark is positioned by virt_text attributes. Can be +--- used together with virt_text. +--- • url: A URL to associate with this extmark. In the TUI, the +--- OSC 8 control sequence is used to generate a clickable +--- hyperlink to this URL. +--- • scoped: boolean that indicates that the extmark should only +--- be displayed in the namespace scope. (experimental) --- @return integer function vim.api.nvim_buf_set_extmark(buffer, ns_id, line, col, opts) end @@ -623,11 +638,14 @@ function vim.api.nvim_buf_set_extmark(buffer, ns_id, line, col, opts) end function vim.api.nvim_buf_set_keymap(buffer, mode, lhs, rhs, opts) end --- Sets (replaces) a line-range in the buffer. +--- --- Indexing is zero-based, end-exclusive. Negative indices are interpreted as --- length+1+index: -1 refers to the index past the end. So to change or --- delete the last element use start=-2 and end=-1. +--- --- To insert lines at a given index, set `start` and `end` to the same index. --- To delete a range of lines, set `replacement` to an empty array. +--- --- Out-of-bounds indices are clamped to the nearest valid value, unless --- `strict_indexing` is set. --- @@ -640,6 +658,7 @@ function vim.api.nvim_buf_set_lines(buffer, start, end_, strict_indexing, replac --- Sets a named mark in the given buffer, all marks are allowed --- file/uppercase, visual, last change, etc. See `mark-motions`. +--- --- Marks are (1,0)-indexed. `api-indexing` --- --- @param buffer integer Buffer to set the mark on @@ -663,16 +682,21 @@ function vim.api.nvim_buf_set_name(buffer, name) end function vim.api.nvim_buf_set_option(buffer, name, value) end --- Sets (replaces) a range in the buffer +--- --- This is recommended over `nvim_buf_set_lines()` when only modifying parts --- of a line, as extmarks will be preserved on non-modified parts of the --- touched lines. +--- --- Indexing is zero-based. Row indices are end-inclusive, and column indices --- are end-exclusive. +--- --- To insert text at a given `(row, column)` location, use `start_row = --- end_row = row` and `start_col = end_col = col`. To delete the text in a --- range, use `replacement = {}`. +--- --- Prefer `nvim_buf_set_lines()` if you are only adding or deleting entire --- lines. +--- --- Prefer `nvim_put()` if you want to insert text at the cursor position. --- --- @param buffer integer Buffer handle, or 0 for current buffer @@ -700,6 +724,7 @@ function vim.api.nvim_buf_set_var(buffer, name, value) end function vim.api.nvim_buf_set_virtual_text(buffer, src_id, line, chunks, opts) end --- Calls a Vimscript `Dictionary-function` with the given arguments. +--- --- On execution error: fails with Vimscript error, updates v:errmsg. --- --- @param dict any Dictionary, or String evaluating to a Vimscript `self` dict @@ -709,6 +734,7 @@ function vim.api.nvim_buf_set_virtual_text(buffer, src_id, line, chunks, opts) e function vim.api.nvim_call_dict_function(dict, fn, args) end --- Calls a Vimscript function with the given arguments. +--- --- On execution error: fails with Vimscript error, updates v:errmsg. --- --- @param fn string Function to call @@ -720,6 +746,7 @@ function vim.api.nvim_call_function(fn, args) end --- process. For the stdio channel `channel-stdio`, it writes to Nvim's --- stdout. For an internal terminal instance (`nvim_open_term()`) it writes --- directly to terminal output. See `channel-bytes` for more information. +--- --- This function writes raw data, not RPC messages. If the channel was --- created with `rpc=true` then the channel expects RPC messages, use --- `vim.rpcnotify()` and `vim.rpcrequest()` instead. @@ -736,42 +763,41 @@ function vim.api.nvim_chan_send(chan, data) end --- • 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. function vim.api.nvim_clear_autocmds(opts) end --- Executes an Ex command. +--- --- Unlike `nvim_command()` this command takes a structured Dictionary instead --- of a String. This allows for easier construction and manipulation of an Ex --- command. This also allows for things such as having spaces inside a --- command argument, expanding filenames in a command that otherwise doesn't --- expand filenames, etc. Command arguments may also be Number, Boolean or --- String. +--- --- The first argument may also be used instead of count for commands that --- support it in order to make their usage simpler with `vim.cmd()`. For --- example, instead of `vim.cmd.bdelete{ count = 2 }`, you may do --- `vim.cmd.bdelete(2)`. +--- --- On execution error: fails with Vimscript error, updates v:errmsg. --- --- @param cmd vim.api.keyset.cmd Command to execute. Must be a Dictionary that can contain the ---- same values as the return value of `nvim_parse_cmd()` except ---- "addr", "nargs" and "nextcmd" which are ignored if provided. ---- All values except for "cmd" are optional. +--- same values as the return value of `nvim_parse_cmd()` except +--- "addr", "nargs" and "nextcmd" which are ignored if provided. +--- All values except for "cmd" are optional. --- @param opts vim.api.keyset.cmd_opts Optional parameters. --- • output: (boolean, default false) Whether to return command --- output. @@ -779,7 +805,9 @@ function vim.api.nvim_clear_autocmds(opts) end function vim.api.nvim_cmd(cmd, opts) end --- Executes an Ex command. +--- --- On execution error: fails with Vimscript error, updates v:errmsg. +--- --- Prefer using `nvim_cmd()` or `nvim_exec2()` over this. To evaluate --- multiple lines of Vim script or an Ex command directly, use --- `nvim_exec2()`. To construct an Ex command using a structured format and @@ -800,11 +828,12 @@ function vim.api.nvim_command_output(command) end --- --- @param index integer the completion candidate index --- @param opts vim.api.keyset.complete_set Optional parameters. ---- • info: (string) info text. +--- • info: (string) info text. --- @return table function vim.api.nvim_complete_set(index, opts) end --- Create or get an autocommand group `autocmd-groups`. +--- --- To get an existing group id, do: --- --- ```lua @@ -813,6 +842,7 @@ function vim.api.nvim_complete_set(index, opts) end --- }) --- ``` --- +--- --- @param name string String: The name of the group --- @param opts vim.api.keyset.create_augroup Dictionary Parameters --- • clear (bool) optional: defaults to true. Clear existing @@ -820,8 +850,10 @@ function vim.api.nvim_complete_set(index, opts) end --- @return integer function vim.api.nvim_create_augroup(name, opts) end ---- Creates an `autocommand` event handler, defined by `callback` (Lua function ---- or Vimscript function name string) or `command` (Ex command string). +--- 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 @@ -849,39 +881,39 @@ function vim.api.nvim_create_augroup(name, opts) end --- pattern = vim.fn.expand("~") .. "/some/path/*.py" --- ``` --- +--- --- @param event any (string|array) Event(s) that will trigger the handler --- (`callback` or `command`). --- @param opts vim.api.keyset.create_autocmd Options dict: ---- • group (string|integer) optional: autocommand group name or ---- id to match against. ---- • pattern (string|array) optional: pattern(s) to match ---- literally `autocmd-pattern`. ---- • buffer (integer) optional: buffer number for buffer-local ---- autocommands `autocmd-buflocal`. Cannot be used with ---- {pattern}. ---- • desc (string) optional: description (for documentation and ---- troubleshooting). ---- • 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: ---- • id: (number) autocommand id ---- • event: (string) name of the triggered event ---- `autocmd-events` ---- • group: (number|nil) autocommand group id, if any ---- • match: (string) expanded value of `` ---- • buf: (number) expanded value of `` ---- • file: (string) expanded value of `` ---- • 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 ---- autocommand only once `autocmd-once`. ---- • nested (boolean) optional: defaults to false. Run nested ---- autocommands `autocmd-nested`. +--- • group (string|integer) optional: autocommand group name or +--- id to match against. +--- • pattern (string|array) optional: pattern(s) to match +--- literally `autocmd-pattern`. +--- • buffer (integer) optional: buffer number for buffer-local +--- autocommands `autocmd-buflocal`. Cannot be used with +--- {pattern}. +--- • desc (string) optional: description (for documentation and +--- troubleshooting). +--- • 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: +--- • id: (number) autocommand id +--- • event: (string) name of the triggered event +--- `autocmd-events` +--- • group: (number|nil) autocommand group id, if any +--- • match: (string) expanded value of `` +--- • buf: (number) expanded value of `` +--- • file: (string) expanded value of `` +--- • 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 +--- autocommand only once `autocmd-once`. +--- • nested (boolean) optional: defaults to false. Run nested +--- autocommands `autocmd-nested`. --- @return integer function vim.api.nvim_create_autocmd(event, opts) end @@ -894,9 +926,11 @@ function vim.api.nvim_create_autocmd(event, opts) end --- @return integer function vim.api.nvim_create_buf(listed, scratch) end ---- Creates a new namespace or gets an existing one. *namespace* +--- Creates a new namespace or gets an existing one. *namespace* +--- --- Namespaces are used for buffer highlights and virtual text, see --- `nvim_buf_add_highlight()` and `nvim_buf_set_extmark()`. +--- --- Namespaces can be named or anonymous. If `name` matches an existing --- namespace, the associated id is returned. If `name` is an empty string a --- new, anonymous namespace is created. @@ -906,7 +940,9 @@ function vim.api.nvim_create_buf(listed, scratch) end function vim.api.nvim_create_namespace(name) end --- Creates a global `user-commands` command. +--- --- For Lua usage see `lua-guide-commands-create`. +--- --- Example: --- --- ```vim @@ -915,8 +951,9 @@ function vim.api.nvim_create_namespace(name) end --- Hello world! --- ``` --- +--- --- @param name string Name of the new user command. Must begin with an uppercase ---- letter. +--- letter. --- @param command any Replacement command to execute when this user command is --- executed. When called from Lua, the command can also be a --- Lua function. The function is called with a single table @@ -943,23 +980,24 @@ function vim.api.nvim_create_namespace(name) end --- Has the same structure as the "mods" key of --- `nvim_parse_cmd()`. --- @param opts vim.api.keyset.user_command Optional `command-attributes`. ---- • Set boolean attributes such as `:command-bang` or ---- `:command-bar` to true (but not `:command-buffer`, use ---- `nvim_buf_create_user_command()` instead). ---- • "complete" `:command-complete` also accepts a Lua ---- function which works like ---- `:command-completion-customlist`. ---- • Other parameters: ---- • desc: (string) Used for listing the command when a Lua ---- function is used for {command}. ---- • force: (boolean, default true) Override any previous ---- definition. ---- • preview: (function) Preview callback for 'inccommand' ---- `:command-preview` +--- • Set boolean attributes such as `:command-bang` or +--- `:command-bar` to true (but not `:command-buffer`, use +--- `nvim_buf_create_user_command()` instead). +--- • "complete" `:command-complete` also accepts a Lua function +--- which works like `:command-completion-customlist`. +--- • Other parameters: +--- • desc: (string) Used for listing the command when a Lua +--- function is used for {command}. +--- • force: (boolean, default true) Override any previous +--- definition. +--- • preview: (function) Preview callback for 'inccommand' +--- `:command-preview` function vim.api.nvim_create_user_command(name, command, opts) end --- Delete an autocommand group by id. +--- --- To get a group id one can use `nvim_get_autocmds()`. +--- --- NOTE: behavior differs from `:augroup-delete`. When deleting a group, --- autocommands contained in this group will also be deleted and cleared. --- This group will no longer exist. @@ -968,6 +1006,7 @@ function vim.api.nvim_create_user_command(name, command, opts) end function vim.api.nvim_del_augroup_by_id(id) end --- Delete an autocommand group by name. +--- --- NOTE: behavior differs from `:augroup-delete`. When deleting a group, --- autocommands contained in this group will also be deleted and cleared. --- This group will no longer exist. @@ -985,6 +1024,7 @@ function vim.api.nvim_del_autocmd(id) end function vim.api.nvim_del_current_line() end --- Unmaps a global `mapping` for the given mode. +--- --- To unmap a buffer-local mapping, use `nvim_buf_del_keymap()`. --- --- @param mode string @@ -1010,14 +1050,14 @@ function vim.api.nvim_del_var(name) end --- Echo a message. --- --- @param chunks any[] A list of [text, hl_group] arrays, each representing a text ---- chunk with specified highlight. `hl_group` element can be ---- omitted for no highlight. +--- chunk with specified highlight. `hl_group` element can be +--- omitted for no highlight. --- @param history boolean if true, add to `message-history`. --- @param opts vim.api.keyset.echo_opts Optional parameters. ---- • verbose: Message was printed as a result of 'verbose' ---- option if Nvim was invoked with -V3log_file, the message ---- will be redirected to the log_file and suppressed from ---- direct output. +--- • verbose: Message was printed as a result of 'verbose' option +--- if Nvim was invoked with -V3log_file, the message will be +--- redirected to the log_file and suppressed from direct +--- output. function vim.api.nvim_echo(chunks, history, opts) end --- Writes a message to the Vim error buffer. Does not append "\n", the @@ -1034,6 +1074,7 @@ function vim.api.nvim_err_writeln(str) end --- Evaluates a Vimscript `expression`. Dictionaries and Lists are recursively --- expanded. +--- --- On execution error: fails with Vimscript error, updates v:errmsg. --- --- @param expr string Vimscript expression string @@ -1068,8 +1109,10 @@ function vim.api.nvim_exec(src, output) end --- Executes Vimscript (multiline block of Ex commands), like anonymous --- `:source`. +--- --- Unlike `nvim_command()` this function supports heredocs, script-scope --- (s:), etc. +--- --- On execution error: fails with Vimscript error, updates v:errmsg. --- --- @param src string Vimscript code @@ -1084,24 +1127,27 @@ function vim.api.nvim_exec2(src, opts) end --- --- @param event any (String|Array) The event or events to execute --- @param opts vim.api.keyset.exec_autocmds Dictionary of autocommand options: ---- • group (string|integer) optional: the autocommand group name ---- or id to match against. `autocmd-groups`. ---- • pattern (string|array) optional: defaults to "*" ---- `autocmd-pattern`. Cannot be used with {buffer}. ---- • buffer (integer) optional: buffer number ---- `autocmd-buflocal`. Cannot be used with {pattern}. ---- • modeline (bool) optional: defaults to true. Process the ---- modeline after the autocommands ``. ---- • data (any): arbitrary data to send to the autocommand ---- callback. See `nvim_create_autocmd()` for details. +--- • group (string|integer) optional: the autocommand group name +--- or id to match against. `autocmd-groups`. +--- • pattern (string|array) optional: defaults to "*" +--- `autocmd-pattern`. Cannot be used with {buffer}. +--- • buffer (integer) optional: buffer number `autocmd-buflocal`. +--- Cannot be used with {pattern}. +--- • modeline (bool) optional: defaults to true. Process the +--- modeline after the autocommands ``. +--- • data (any): arbitrary data to send to the autocommand +--- callback. See `nvim_create_autocmd()` for details. function vim.api.nvim_exec_autocmds(event, opts) end --- Sends input-keys to Nvim, subject to various quirks controlled by `mode` --- flags. This is a blocking call, unlike `nvim_input()`. +--- --- On execution error: does not fail, but updates v:errmsg. +--- --- To input sequences like use `nvim_replace_termcodes()` (typically --- with escape_ks=false) to replace `keycodes`, then pass the result to --- nvim_feedkeys(). +--- --- Example: --- --- ```vim @@ -1109,6 +1155,7 @@ function vim.api.nvim_exec_autocmds(event, opts) end --- :call nvim_feedkeys(key, 'n', v:false) --- ``` --- +--- --- @param keys string to be typed --- @param mode string behavior flags, see `feedkeys()` --- @param escape_ks boolean If true, escape K_SPECIAL bytes in `keys`. This should be @@ -1117,6 +1164,7 @@ function vim.api.nvim_exec_autocmds(event, opts) end function vim.api.nvim_feedkeys(keys, mode, escape_ks) end --- Gets the option information for all options. +--- --- The dictionary has the full option names as keys and option metadata --- dictionaries as detailed at `nvim_get_option_info2()`. --- @@ -1124,6 +1172,7 @@ function vim.api.nvim_feedkeys(keys, mode, escape_ks) end function vim.api.nvim_get_all_options_info() end --- Get all autocommands that match the corresponding {opts}. +--- --- These examples will get autocommands matching ALL the given criteria: --- --- ```lua @@ -1164,6 +1213,7 @@ function vim.api.nvim_get_chan_info(chan) end --- Returns the 24-bit RGB value of a `nvim_get_color_map()` color name or --- "#rrggbb" hexadecimal string. +--- --- Example: --- --- ```vim @@ -1171,11 +1221,13 @@ function vim.api.nvim_get_chan_info(chan) end --- :echo nvim_get_color_by_name("#cbcbcb") --- ``` --- +--- --- @param name string Color name or "#rrggbb" string --- @return integer function vim.api.nvim_get_color_by_name(name) end --- Returns a map of color names and RGB values. +--- --- Keys are color names (e.g. "Aqua") and values are 24-bit RGB color values --- (e.g. 65535). --- @@ -1183,6 +1235,7 @@ function vim.api.nvim_get_color_by_name(name) end function vim.api.nvim_get_color_map() end --- Gets a map of global (non-buffer-local) Ex commands. +--- --- Currently only `user-commands` are supported, not builtin Ex commands. --- --- @param opts vim.api.keyset.get_commands Optional parameters. Currently only supports {"builtin":false} @@ -1223,12 +1276,12 @@ function vim.api.nvim_get_current_win() end --- `nvim_get_namespaces()`. Use 0 to get global highlight groups --- `:highlight`. --- @param opts vim.api.keyset.get_highlight Options dict: ---- • name: (string) Get a highlight definition by name. ---- • id: (integer) Get a highlight definition by id. ---- • link: (boolean, default true) Show linked group name ---- instead of effective definition `:hi-link`. ---- • create: (boolean, default true) When highlight group ---- doesn't exist create it. +--- • name: (string) Get a highlight definition by name. +--- • id: (integer) Get a highlight definition by id. +--- • link: (boolean, default true) Show linked group name instead +--- of effective definition `:hi-link`. +--- • create: (boolean, default true) When highlight group doesn't +--- exist create it. --- @return vim.api.keyset.hl_info function vim.api.nvim_get_hl(ns_id, opts) end @@ -1245,6 +1298,7 @@ function vim.api.nvim_get_hl_by_id(hl_id, rgb) end function vim.api.nvim_get_hl_by_name(name, rgb) end --- Gets a highlight group by name +--- --- similar to `hlID()`, but allocates a new ID if not present. --- --- @param name string @@ -1270,6 +1324,7 @@ function vim.api.nvim_get_keymap(mode) end --- 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`. +--- --- Marks are (1,0)-indexed. `api-indexing` --- --- @param name string Mark name @@ -1299,6 +1354,7 @@ function vim.api.nvim_get_option(name) end function vim.api.nvim_get_option_info(name) end --- 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') @@ -1360,10 +1416,12 @@ function vim.api.nvim_get_proc(pid) end function vim.api.nvim_get_proc_children(pid) end --- Find files in runtime directories +--- --- "name" can contain wildcards. For example --- nvim_get_runtime_file("colors/*.vim", true) will return all color scheme --- files. Always use forward slashes (/) in the search pattern for --- subdirectories regardless of platform. +--- --- It is not an error to not find any files. An empty array is returned then. --- --- @param name string pattern of files to search for @@ -1386,6 +1444,7 @@ function vim.api.nvim_get_vvar(name) end --- Queues raw user-input. Unlike `nvim_feedkeys()`, this uses a low-level --- input buffer and the call is non-blocking (input is processed --- asynchronously by the eventloop). +--- --- On execution error: does not fail, but updates v:errmsg. --- --- @param keys string to be typed @@ -1393,14 +1452,15 @@ function vim.api.nvim_get_vvar(name) end function vim.api.nvim_input(keys) end --- Send mouse event from GUI. +--- --- Non-blocking: does not wait on any result, but queues the event to be --- processed soon by the event loop. --- --- @param button string Mouse button: one of "left", "right", "middle", "wheel", ---- "move", "x1", "x2". ---- @param action string For ordinary buttons, one of "press", "drag", "release". ---- For the wheel, one of "up", "down", "left", "right". ---- Ignored for "move". +--- "move", "x1", "x2". +--- @param action string For ordinary buttons, one of "press", "drag", "release". For +--- the wheel, one of "up", "down", "left", "right". Ignored for +--- "move". --- @param modifier string String of modifiers each represented by a single char. The --- same specifiers are used as for a key press, except that --- the "-" separator is optional, so "C-A-", "c-a" and "CA" @@ -1411,6 +1471,7 @@ function vim.api.nvim_input(keys) end function vim.api.nvim_input_mouse(button, action, modifier, grid, row, col) end --- Gets the current list of buffer handles +--- --- Includes unlisted (unloaded/deleted) buffers, like `:ls!`. Use --- `nvim_buf_is_loaded()` to check if a buffer is loaded. --- @@ -1449,6 +1510,7 @@ function vim.api.nvim_list_wins() end function vim.api.nvim_load_context(dict) end --- Notify the user with a message +--- --- Relays the call to vim.notify . By default forwards your message in the --- echo area but can be overridden to trigger desktop notifications. --- @@ -1459,10 +1521,12 @@ function vim.api.nvim_load_context(dict) end function vim.api.nvim_notify(msg, log_level, opts) end --- Open a terminal instance in a buffer +--- --- By default (and currently the only option) the terminal will not be --- connected to an external process. Instead, input send on the channel will --- be echoed directly by the terminal. This is useful to display ANSI --- terminal sequences returned as part of a rpc message, or similar. +--- --- Note: to directly initiate the terminal using the right size, display the --- buffer in a configured window before calling this. For instance, for a --- floating display, first create an empty buffer using `nvim_create_buf()`, @@ -1472,27 +1536,30 @@ function vim.api.nvim_notify(msg, log_level, opts) end --- --- @param buffer integer the buffer to use (expected to be empty) --- @param opts vim.api.keyset.open_term Optional parameters. ---- • on_input: Lua callback for input sent, i e keypresses in ---- terminal mode. Note: keypresses are sent raw as they would ---- be to the pty master end. For instance, a carriage return ---- is sent as a "\r", not as a "\n". `textlock` applies. It ---- is possible to call `nvim_chan_send()` directly in the ---- callback however. ["input", term, bufnr, data] ---- • force_crlf: (boolean, default true) Convert "\n" to ---- "\r\n". +--- • on_input: Lua callback for input sent, i e keypresses in +--- terminal mode. Note: keypresses are sent raw as they would +--- be to the pty master end. For instance, a carriage return is +--- sent as a "\r", not as a "\n". `textlock` applies. It is +--- possible to call `nvim_chan_send()` directly in the callback +--- however. ["input", term, bufnr, data] +--- • force_crlf: (boolean, default true) Convert "\n" to "\r\n". --- @return integer function vim.api.nvim_open_term(buffer, opts) end --- 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. +--- --- Floats are windows that are drawn above the split layout, at some anchor --- position in some other window. Floats can be drawn internally or by --- external GUI with the `ui-multigrid` extension. External windows are only --- supported with multigrid GUIs, and are displayed as separate top-level --- windows. +--- --- For a general overview of floats, see `api-floatwin`. +--- --- The `width` and `height` of the new window must be specified when opening --- a floating window, but are optional for normal windows. +--- --- If `relative` and `external` are omitted, a normal "split" window is --- created. The `win` property determines which window will be split. If no --- `win` is provided or `win == 0`, a window will be created adjacent to the @@ -1501,15 +1568,18 @@ function vim.api.nvim_open_term(buffer, opts) end --- control split direction. For `vertical`, the exact direction is determined --- by `'splitright'` and `'splitbelow'`. Split windows cannot have --- `bufpos`/`row`/`col`/`border`/`title`/`footer` properties. +--- --- With relative=editor (row=0,col=0) refers to the top-left corner of the --- screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right --- corner. Fractional values are allowed, but the builtin implementation --- (used by non-multigrid UIs) will always round down to nearest integer. +--- --- Out-of-bounds values, and configurations that make the float not fit --- inside the main editor, are allowed. The builtin implementation truncates --- values so floats are fully within the main screen grid. External GUIs --- could let floats hover outside of the main window like a tooltip, but this --- should not be used to specify arbitrary WM screen positions. +--- --- Example (Lua): window-relative float --- --- ```lua @@ -1533,6 +1603,7 @@ function vim.api.nvim_open_term(buffer, opts) end --- }) --- ``` --- +--- --- @param buffer integer Buffer to display, or 0 for current buffer --- @param enter boolean Enter the window (make it the current window) --- @param config vim.api.keyset.win_config Map defining the window configuration. Keys: @@ -1543,7 +1614,6 @@ function vim.api.nvim_open_term(buffer, opts) end --- 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 @@ -1552,17 +1622,15 @@ function vim.api.nvim_open_term(buffer, opts) end --- • "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 @@ -1583,7 +1651,6 @@ function vim.api.nvim_open_term(buffer, opts) end --- 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 @@ -1596,14 +1663,13 @@ function vim.api.nvim_open_term(buffer, opts) end --- 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. @@ -1611,18 +1677,35 @@ function vim.api.nvim_open_term(buffer, opts) end --- 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 @@ -1654,6 +1737,7 @@ function vim.api.nvim_open_win(buffer, enter, config) end function vim.api.nvim_out_write(str) end --- Parse command line. +--- --- Doesn't check the validity of command arguments. --- --- @param str string Command line string to parse. Cannot contain "\n". @@ -1665,17 +1749,17 @@ function vim.api.nvim_parse_cmd(str, opts) end --- --- @param expr string Expression to parse. Always treated as a single line. --- @param flags string Flags: ---- • "m" if multiple expressions in a row are allowed (only ---- the first one will be parsed), ---- • "E" if EOC tokens are not allowed (determines whether ---- they will stop parsing process or be recognized as an ---- operator/space, though also yielding an error). ---- • "l" when needing to start parsing with lvalues for ---- ":let" or ":for". Common flag sets: ---- • "m" to parse like for ":echo". ---- • "E" to parse like for "=". ---- • empty string for ":call". ---- • "lm" to parse for ":let". +--- • "m" if multiple expressions in a row are allowed (only the +--- first one will be parsed), +--- • "E" if EOC tokens are not allowed (determines whether they +--- will stop parsing process or be recognized as an +--- operator/space, though also yielding an error). +--- • "l" when needing to start parsing with lvalues for ":let" +--- or ":for". Common flag sets: +--- • "m" to parse like for ":echo". +--- • "E" to parse like for "=". +--- • empty string for ":call". +--- • "lm" to parse for ":let". --- @param highlight boolean If true, return value will also include "highlight" key --- containing array of 4-tuples (arrays) (Integer, Integer, --- Integer, String), where first three numbers define the @@ -1686,8 +1770,10 @@ function vim.api.nvim_parse_cmd(str, opts) end function vim.api.nvim_parse_expression(expr, flags, highlight) end --- Pastes at cursor, in any mode. +--- --- Invokes the `vim.paste` handler, which handles each mode appropriately. --- Sets redo/undo. Faster than `nvim_input()`. Lines break at LF ("\n"). +--- --- Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` --- but do not affect the return value (which is strictly decided by --- `vim.paste()`). On error, subsequent calls are ignored ("drained") until @@ -1696,8 +1782,8 @@ function vim.api.nvim_parse_expression(expr, flags, highlight) end --- @param data string Multiline input. May be binary (containing NUL bytes). --- @param crlf boolean Also break lines at CR and CRLF. --- @param phase integer -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) @@ -1705,16 +1791,16 @@ function vim.api.nvim_parse_expression(expr, flags, highlight) end function vim.api.nvim_paste(data, crlf, phase) end --- Puts text at cursor, in any mode. +--- --- Compare `:put` and `p` which are always linewise. --- --- @param lines string[] `readfile()`-style list of lines. `channel-lines` --- @param type string Edit behavior: any `getregtype()` result, or: ---- • "b" `blockwise-visual` mode (may include width, e.g. "b3") ---- • "c" `charwise` mode ---- • "l" `linewise` mode ---- • "" guess by contents, see `setreg()` ---- @param after boolean If true insert after cursor (like `p`), or before (like ---- `P`). +--- • "b" `blockwise-visual` mode (may include width, e.g. "b3") +--- • "c" `charwise` mode +--- • "l" `linewise` mode +--- • "" guess by contents, see `setreg()` +--- @param after boolean If true insert after cursor (like `p`), or before (like `P`). --- @param follow boolean If true place cursor at end of inserted text. function vim.api.nvim_put(lines, type, after, follow) end @@ -1729,14 +1815,15 @@ function vim.api.nvim_put(lines, type, after, follow) end function vim.api.nvim_replace_termcodes(str, from_part, do_lt, special) end --- Selects an item in the completion popup menu. +--- --- If neither `ins-completion` nor `cmdline-completion` popup menu is active --- this API call is silently ignored. Useful for an external UI using --- `ui-popupmenu` to control the popup menu with the mouse. Can also be used --- in a mapping; use `:map-cmd` or a Lua mapping to ensure the mapping --- doesn't end completion mode. --- ---- @param item integer Index (zero-based) of the item to select. Value of -1 ---- selects nothing and restores the original text. +--- @param item integer Index (zero-based) of the item to select. Value of -1 selects +--- nothing and restores the original text. --- @param insert boolean For `ins-completion`, whether the selection should be --- inserted in the buffer. Ignored for `cmdline-completion`. --- @param finish boolean Finish the completion and dismiss the popup menu. Implies @@ -1770,13 +1857,16 @@ function vim.api.nvim_set_current_tabpage(tabpage) end function vim.api.nvim_set_current_win(window) end --- Set or change decoration provider for a `namespace` +--- --- This is a very general purpose interface for having Lua callbacks being --- triggered during the redraw code. +--- --- The expected usage is to set `extmarks` for the currently redrawn buffer. --- `nvim_buf_set_extmark()` can be called to add marks on a per-window or --- per-lines basis. Use the `ephemeral` key to only use the mark for the --- current screen redraw (the callback will be called again for the next --- redraw). +--- --- Note: this function should not be called often. Rather, the callbacks --- themselves can be used to throttle unneeded callbacks. the `on_start` --- callback can return `false` to disable the provider until the next redraw. @@ -1785,26 +1875,27 @@ function vim.api.nvim_set_current_win(window) end --- plugin managing multiple sources of decoration should ideally only set one --- provider, and merge the sources internally. You can use multiple `ns_id` --- for the extmarks set/modified inside the callback anyway. +--- --- Note: doing anything other than setting extmarks is considered --- experimental. Doing things like changing options are not explicitly --- forbidden, but is likely to have unexpected consequences (such as 100% CPU --- consumption). doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is --- quite dubious for the moment. +--- --- Note: It is not allowed to remove or update extmarks in 'on_line' --- callbacks. --- --- @param ns_id integer Namespace id from `nvim_create_namespace()` --- @param opts vim.api.keyset.set_decoration_provider Table of callbacks: ---- • on_start: called first on each screen redraw ["start", ---- tick] ---- • on_buf: called for each buffer being redrawn (before window ---- callbacks) ["buf", bufnr, tick] ---- • on_win: called when starting to redraw a specific window. ---- ["win", winid, bufnr, topline, botline] ---- • on_line: called for each buffer line being redrawn. (The ---- interaction with fold lines is subject to change) ["line", ---- winid, bufnr, row] ---- • on_end: called at the end of a redraw cycle ["end", tick] +--- • on_start: called first on each screen redraw ["start", tick] +--- • on_buf: called for each buffer being redrawn (before window +--- callbacks) ["buf", bufnr, tick] +--- • on_win: called when starting to redraw a specific window. +--- ["win", winid, bufnr, topline, botline] +--- • on_line: called for each buffer line being redrawn. (The +--- interaction with fold lines is subject to change) ["line", +--- winid, bufnr, row] +--- • on_end: called at the end of a redraw cycle ["end", tick] function vim.api.nvim_set_decoration_provider(ns_id, opts) end --- Sets a highlight group. @@ -1816,31 +1907,31 @@ function vim.api.nvim_set_decoration_provider(ns_id, opts) end --- activate them. --- @param name string Highlight group name, e.g. "ErrorMsg" --- @param val vim.api.keyset.highlight Highlight definition map, accepts the following keys: ---- • fg: color name or "#RRGGBB", see note. ---- • bg: color name or "#RRGGBB", see note. ---- • sp: color name or "#RRGGBB" ---- • blend: integer between 0 and 100 ---- • bold: boolean ---- • standout: boolean ---- • underline: boolean ---- • undercurl: boolean ---- • underdouble: boolean ---- • underdotted: boolean ---- • underdashed: boolean ---- • strikethrough: boolean ---- • italic: boolean ---- • reverse: boolean ---- • nocombine: boolean ---- • link: name of another highlight group to link to, see ---- `:hi-link`. ---- • default: Don't override existing definition `:hi-default` ---- • ctermfg: Sets foreground of cterm color `ctermfg` ---- • ctermbg: Sets background of cterm color `ctermbg` ---- • cterm: cterm attribute map, like `highlight-args`. If not ---- set, cterm attributes will match those from the attribute ---- map documented above. ---- • force: if true force update the highlight group when it ---- exists. +--- • fg: color name or "#RRGGBB", see note. +--- • bg: color name or "#RRGGBB", see note. +--- • sp: color name or "#RRGGBB" +--- • blend: integer between 0 and 100 +--- • bold: boolean +--- • standout: boolean +--- • underline: boolean +--- • undercurl: boolean +--- • underdouble: boolean +--- • underdotted: boolean +--- • underdashed: boolean +--- • strikethrough: boolean +--- • italic: boolean +--- • reverse: boolean +--- • nocombine: boolean +--- • link: name of another highlight group to link to, see +--- `:hi-link`. +--- • default: Don't override existing definition `:hi-default` +--- • ctermfg: Sets foreground of cterm color `ctermfg` +--- • ctermbg: Sets background of cterm color `ctermbg` +--- • cterm: cterm attribute map, like `highlight-args`. If not +--- set, cterm attributes will match those from the attribute map +--- documented above. +--- • force: if true force update the highlight group when it +--- exists. function vim.api.nvim_set_hl(ns_id, name, val) end --- Set active namespace for highlights defined with `nvim_set_hl()`. This can @@ -1851,6 +1942,7 @@ function vim.api.nvim_set_hl_ns(ns_id) end --- Set active namespace for highlights defined with `nvim_set_hl()` while --- redrawing. +--- --- This function meant to be called while redrawing, primarily from --- `nvim_set_decoration_provider()` on_win and on_line callbacks, which are --- allowed to change the namespace during a redraw cycle. @@ -1859,9 +1951,12 @@ function vim.api.nvim_set_hl_ns(ns_id) end function vim.api.nvim_set_hl_ns_fast(ns_id) end --- Sets a global `mapping` for the given mode. +--- --- To set a buffer-local mapping, use `nvim_buf_set_keymap()`. +--- --- Unlike `:map`, leading/trailing whitespace is accepted as part of the --- {lhs} or {rhs}. Empty {rhs} is ``. `keycodes` are replaced as usual. +--- --- Example: --- --- ```vim @@ -1874,8 +1969,9 @@ function vim.api.nvim_set_hl_ns_fast(ns_id) end --- nmap --- ``` --- ---- @param mode string Mode short-name (map command prefix: "n", "i", "v", "x", …) or ---- "!" for `:map!`, or empty string for `:map`. "ia", "ca" or +--- +--- @param mode string 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 --- @param lhs string Left-hand-side `{lhs}` of the mapping. @@ -1899,15 +1995,16 @@ function vim.api.nvim_set_option(name, value) end --- 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}. +--- --- Note the options {win} and {buf} cannot be used together. --- --- @param name string Option name --- @param value any New option value --- @param opts vim.api.keyset.option Optional parameters ---- • scope: One of "global" or "local". Analogous to ---- `:setglobal` and `:setlocal`, respectively. ---- • win: `window-ID`. Used for setting window local option. ---- • buf: Buffer number. Used for setting buffer local option. +--- • scope: One of "global" or "local". Analogous to `:setglobal` +--- and `:setlocal`, respectively. +--- • win: `window-ID`. Used for setting window local option. +--- • buf: Buffer number. Used for setting buffer local option. function vim.api.nvim_set_option_value(name, value, opts) end --- Sets a global (g:) variable. @@ -1990,7 +2087,7 @@ function vim.api.nvim_win_add_ns(window, ns_id) end --- --- @param window integer Window handle, or 0 for current window --- @param fun function Function to call inside the window (currently Lua callable ---- only) +--- only) --- @return any function vim.api.nvim_win_call(window, fun) end @@ -1998,8 +2095,8 @@ function vim.api.nvim_win_call(window, fun) end --- --- @param window integer Window handle, or 0 for current window --- @param force boolean Behave like `:close!` The last window of a buffer with ---- unwritten changes can be closed. The buffer will become ---- hidden, even if 'hidden' is not set. +--- unwritten changes can be closed. The buffer will become +--- hidden, even if 'hidden' is not set. function vim.api.nvim_win_close(window, force) end --- Removes a window-scoped (w:) variable @@ -2015,7 +2112,9 @@ function vim.api.nvim_win_del_var(window, name) end function vim.api.nvim_win_get_buf(window) end --- Gets window configuration. +--- --- The returned value may be given to `nvim_open_win()`. +--- --- `relative` is empty for normal windows. --- --- @param window integer Window handle, or 0 for current window @@ -2081,6 +2180,7 @@ function vim.api.nvim_win_get_width(window) end --- Closes the window and hide the buffer it contains (like `:hide` with a --- `window-ID`). +--- --- Like `:hide` the buffer becomes hidden unless another window is editing --- it, or 'bufhidden' is `unload`, `delete` or `wipe` as opposed to `:close` --- or `nvim_win_close()`, which will close the buffer. @@ -2109,6 +2209,7 @@ function vim.api.nvim_win_set_buf(window, buffer) end --- Configures window layout. Currently only for floating and external windows --- (including changing a split window to those layouts). +--- --- When reconfiguring a floating window, absent option keys will not be --- changed. `row`/`col` and `relative` must be reconfigured together. --- @@ -2132,6 +2233,7 @@ function vim.api.nvim_win_set_height(window, height) end --- Set highlight namespace for a window. This will use highlights defined --- with `nvim_set_hl()` for this namespace, but fall back to global --- highlights (ns=0) when missing. +--- --- This takes precedence over the 'winhighlight' option. --- --- @param window integer @@ -2160,23 +2262,26 @@ function vim.api.nvim_win_set_width(window, width) end --- 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. +--- --- Diff filler or virtual lines above a line are counted as a part of that --- line, unless the line is on "start_row" and "start_vcol" is specified. +--- --- Diff filler or virtual lines below the last buffer line are counted in the --- result when "end_row" is omitted. +--- --- Line indexing is similar to `nvim_buf_get_text()`. --- --- @param window integer Window handle, or 0 for current window. --- @param opts vim.api.keyset.win_text_height Optional parameters: ---- • start_row: Starting line index, 0-based inclusive. When ---- omitted start at the very top. ---- • end_row: Ending line index, 0-based inclusive. When ---- omitted end at the very bottom. ---- • start_vcol: Starting virtual column index on "start_row", ---- 0-based inclusive, rounded down to full screen lines. When ---- omitted include the whole line. ---- • end_vcol: Ending virtual column index on "end_row", ---- 0-based exclusive, rounded up to full screen lines. When ---- omitted include the whole line. +--- • start_row: Starting line index, 0-based inclusive. When +--- omitted start at the very top. +--- • end_row: Ending line index, 0-based inclusive. When omitted +--- end at the very bottom. +--- • start_vcol: Starting virtual column index on "start_row", +--- 0-based inclusive, rounded down to full screen lines. When +--- omitted include the whole line. +--- • end_vcol: Ending virtual column index on "end_row", 0-based +--- exclusive, rounded up to full screen lines. When omitted +--- include the whole line. --- @return table function vim.api.nvim_win_text_height(window, opts) end diff --git a/runtime/lua/vim/_meta/builtin.lua b/runtime/lua/vim/_meta/builtin.lua index a422a65792..472162ecc1 100644 --- a/runtime/lua/vim/_meta/builtin.lua +++ b/runtime/lua/vim/_meta/builtin.lua @@ -3,65 +3,63 @@ error('Cannot require a meta file') ----@defgroup vim.builtin +--- @brief
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 
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
----
----
+---
---@class vim.NIL diff --git a/runtime/lua/vim/_meta/json.lua b/runtime/lua/vim/_meta/json.lua index e010086615..07d89aafc8 100644 --- a/runtime/lua/vim/_meta/json.lua +++ b/runtime/lua/vim/_meta/json.lua @@ -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()|. diff --git a/runtime/lua/vim/_meta/lpeg.lua b/runtime/lua/vim/_meta/lpeg.lua index 5bd502a7c8..f2239e5e5a 100644 --- a/runtime/lua/vim/_meta/lpeg.lua +++ b/runtime/lua/vim/_meta/lpeg.lua @@ -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 ----
help
----LPeg is a pattern-matching library for Lua, based on
----Parsing Expression Grammars (https://bford.info/packrat/) (PEGs).
+--- @brief 
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).
 ---
----
+---
---- *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 diff --git a/runtime/lua/vim/_meta/mpack.lua b/runtime/lua/vim/_meta/mpack.lua index 54e097ad97..3970341b78 100644 --- a/runtime/lua/vim/_meta/mpack.lua +++ b/runtime/lua/vim/_meta/mpack.lua @@ -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 diff --git a/runtime/lua/vim/_meta/re.lua b/runtime/lua/vim/_meta/re.lua index 4f254b19a0..14c94c7824 100644 --- a/runtime/lua/vim/_meta/re.lua +++ b/runtime/lua/vim/_meta/re.lua @@ -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 ----
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.
----
----
+--- 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 diff --git a/runtime/lua/vim/_meta/regex.lua b/runtime/lua/vim/_meta/regex.lua index 58aa2be8c2..ab403b97e7 100644 --- a/runtime/lua/vim/_meta/regex.lua +++ b/runtime/lua/vim/_meta/regex.lua @@ -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. diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua index b83a8dd4b1..f1fed50c6d 100644 --- a/runtime/lua/vim/_options.lua +++ b/runtime/lua/vim/_options.lua @@ -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
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 
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`.
----
+--- vim.v *vim.v* +--- |v:| variables. +--- Invalid or unset key returns `nil`. +---
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
help
----` `                                                                *lua-options*
----                                                             *lua-vim-options*
----                                                                 *lua-vim-set*
----                                                            *lua-vim-setlocal*
+--- @brief 
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|.
----
+--- 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|. +---
--- 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
help
----` `                                                                       *vim.opt_local*
----                                                                       *vim.opt_global*
----                                                                              *vim.opt*
+--- @brief 
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`.
----
+--- 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`. +---
---- @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 diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 91f91b5879..49165c4db9 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -70,6 +70,7 @@ local M = {} --- @field linehl? table --- @field texthl? table +--- @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 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: ----
lua
----                         function(diagnostic)
----                           if diagnostic.severity == vim.diagnostic.severity.ERROR then
----                             return string.format("E: %s", diagnostic.message)
----                           end
----                           return diagnostic.message
----                         end
----                       
+--- 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: ----
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. +--- * 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? diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index b43072a725..e7971d8916 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -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 diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index 22612a7255..0af5fc4f30 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -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: diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index b055cce49d..effe280dee 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -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, diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua index d720745110..798428014d 100644 --- a/runtime/lua/vim/iter.lua +++ b/runtime/lua/vim/iter.lua @@ -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 diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index 8e4e123fe0..84e9b4197d 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -90,6 +90,8 @@ end --- vim.keymap.del({'n', 'i', 'v'}, '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. diff --git a/runtime/lua/vim/loader.lua b/runtime/lua/vim/loader.lua index ec99e417c2..5f3da55544 100644 --- a/runtime/lua/vim/loader.lua +++ b/runtime/lua/vim/loader.lua @@ -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="*"` diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 3a74c3ee90..19497e40dc 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -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: ----
----                   { 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 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: diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 7fc5286a78..d2e92de083 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -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 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:
lua
----                     -- Never request typescript-language-server for formatting
----                     vim.lsp.buf.format {
----                       filter = function(client) return client.name ~= "tsserver" end
----                     }
----         
+--- 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) diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 966c7f4d03..7aed6f99e3 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -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 diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 33051ab61c..1fa67fc473 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -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()|). diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index a9da812231..781d720486 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -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) diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index a9d49bc8f4..018003bb81 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -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 diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index e849bb4f2a..1455ab51fa 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -273,8 +273,6 @@ end ---@field notify_reply_callbacks table 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 diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 62fa0b33f4..936579e003 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -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 diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index b60135f851..e371cb0e15 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -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 diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 5cf8390843..83fdfede89 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -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 (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 @@ -225,7 +226,7 @@ end --- ---@generic T ---@param t table (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 (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 @@ -260,7 +261,7 @@ end ---@generic T ---@param func fun(value: T): boolean (function) Function ---@param t table (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 @@ -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 @@ -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 (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: diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 7e37d84393..09b7576d97 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -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. diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index e2197168f0..9b69f95f54 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -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: --- diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua index 556c910feb..6ec997eb4a 100644 --- a/runtime/lua/vim/treesitter/_query_linter.lua +++ b/runtime/lua/vim/treesitter/_query_linter.lua @@ -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 diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 99cc9bea09..8fb591bc46 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -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 diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 79566f5eeb..d01da8be71 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -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 diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 5bb9e07a82..57272dbd60 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -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 diff --git a/runtime/lua/vim/uri.lua b/runtime/lua/vim/uri.lua index 038aa8acfb..7660dc42e7 100644 --- a/runtime/lua/vim/uri.lua +++ b/runtime/lua/vim/uri.lua @@ -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) diff --git a/runtime/lua/vim/version.lua b/runtime/lua/vim/version.lua index 58c2a2386d..09a6fa825b 100644 --- a/runtime/lua/vim/version.lua +++ b/runtime/lua/vim/version.lua @@ -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()|. diff --git a/scripts/cdoc_grammar.lua b/scripts/cdoc_grammar.lua new file mode 100644 index 0000000000..6a7610883b --- /dev/null +++ b/scripts/cdoc_grammar.lua @@ -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 +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]] diff --git a/scripts/cdoc_parser.lua b/scripts/cdoc_parser.lua new file mode 100644 index 0000000000..5f0dc7be2c --- /dev/null +++ b/scripts/cdoc_parser.lua @@ -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 diff --git a/scripts/gen_eval_files.lua b/scripts/gen_eval_files.lua index b7f17a2d58..895033d5af 100755 --- a/scripts/gen_eval_files.lua +++ b/scripts/gen_eval_files.lua @@ -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 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 - local doc_mpack_f = assert(io.open(DEP_API_DOC, 'rb')) - local doc_metadata = vim.mpack.decode(doc_mpack_f:read('*all')) --[[@as table]] + 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 + 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 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 diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua new file mode 100755 index 0000000000..290cd83fbc --- /dev/null +++ b/scripts/gen_vimdoc.lua @@ -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 +--- +--- @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 +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 +--- @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 +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 +--- @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 +-- 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 +--- @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 +--- @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 + + 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() diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py deleted file mode 100755 index c1a2183f24..0000000000 --- a/scripts/gen_vimdoc.py +++ /dev/null @@ -1,1766 +0,0 @@ -#!/usr/bin/env python3 - -r"""Generates Nvim :help docs from C/Lua docstrings, using Doxygen. - -Also generates *.mpack files. To inspect the *.mpack structure: - :new | put=v:lua.vim.inspect(v:lua.vim.mpack.decode(readfile('runtime/doc/api.mpack','B'))) - -Flow: - main - extract_from_xml - fmt_node_as_vimhelp \ - para_as_map } recursive - update_params_map / - render_node - -TODO: eliminate this script and use Lua+treesitter (requires parsers for C and -Lua markdown-style 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 at `text_width - 8` characters 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. -""" - -from __future__ import annotations # PEP-563, python 3.7+ - -import argparse -import collections -import dataclasses -import logging -import os -import re -import shutil -import subprocess -import sys -import textwrap -from pathlib import Path -from typing import Any, Callable, Dict, List, Tuple -from xml.dom import minidom - -if sys.version_info >= (3, 8): - from typing import Literal - -import msgpack - -Element = minidom.Element -Document = minidom.Document - -MIN_PYTHON_VERSION = (3, 7) -MIN_DOXYGEN_VERSION = (1, 9, 0) - -if sys.version_info < MIN_PYTHON_VERSION: - print("requires Python {}.{}+".format(*MIN_PYTHON_VERSION)) - sys.exit(1) - -doxygen_version = tuple((int(i) for i in subprocess.check_output(["doxygen", "-v"], - universal_newlines=True).split()[0].split('.'))) - -if doxygen_version < MIN_DOXYGEN_VERSION: - print("\nRequires doxygen {}.{}.{}+".format(*MIN_DOXYGEN_VERSION)) - print("Your doxygen version is {}.{}.{}\n".format(*doxygen_version)) - sys.exit(1) - - -# Need a `nvim` that supports `-l`, try the local build -nvim_path = Path(__file__).parent / "../build/bin/nvim" -if nvim_path.exists(): - nvim = nvim_path.resolve() -else: - # Until 0.9 is released, use this hacky way to check that "nvim -l foo.lua" works. - nvim_out = subprocess.check_output(['nvim', '-h'], universal_newlines=True) - nvim_version = [line for line in nvim_out.split('\n') - if '-l ' in line] - if len(nvim_version) == 0: - print(( - "\nYou need to have a local Neovim build or a `nvim` version 0.9 for `-l` " - "support to build the documentation.")) - sys.exit(1) - nvim = 'nvim' - - -# DEBUG = ('DEBUG' in os.environ) -INCLUDE_C_DECL = os.environ.get('INCLUDE_C_DECL', '0') != '0' -INCLUDE_DEPRECATED = os.environ.get('INCLUDE_DEPRECATED', '0') != '0' - -log = logging.getLogger(__name__) - -LOG_LEVELS = { - logging.getLevelName(level): level for level in [ - logging.DEBUG, logging.INFO, logging.ERROR - ] -} - -text_width = 78 -indentation = 4 -SECTION_SEP = '=' * text_width - -script_path = os.path.abspath(__file__) -base_dir = os.path.dirname(os.path.dirname(script_path)) -out_dir = os.path.join(base_dir, 'tmp-{target}-doc') -filter_cmd = '%s %s' % (sys.executable, script_path) -msgs = [] # Messages to show on exit. -lua2dox = os.path.join(base_dir, 'scripts', 'lua2dox.lua') - - -SectionName = str - -Docstring = str # Represents (formatted) vimdoc string - -FunctionName = str - - -@dataclasses.dataclass -class Config: - """Config for documentation.""" - - mode: Literal['c', 'lua'] - - filename: str - """Generated documentation target, e.g. api.txt""" - - section_order: List[str] - """Section ordering.""" - - files: List[str] - """List of files/directories for doxygen to read, relative to `base_dir`.""" - - file_patterns: str - """file patterns used by doxygen.""" - - section_name: Dict[str, SectionName] - """Section name overrides. Key: filename (e.g., vim.c)""" - - section_fmt: Callable[[SectionName], str] - """For generated section names.""" - - helptag_fmt: Callable[[SectionName], str] - """Section helptag.""" - - fn_helptag_fmt: Callable[[str, str, bool], str] - """Per-function helptag.""" - - module_override: Dict[str, str] - """Module name overrides (for Lua).""" - - append_only: List[str] - """Append the docs for these modules, do not start a new section.""" - - fn_name_prefix: str - """Only function with this prefix are considered""" - - fn_name_fmt: Callable[[str, str], str] | None = None - - include_tables: bool = True - - -CONFIG: Dict[str, Config] = { - 'api': Config( - mode='c', - filename = 'api.txt', - # Section ordering. - section_order=[x for x in [ - 'vim.c', - 'vimscript.c', - 'command.c', - 'options.c', - 'buffer.c', - 'extmark.c', - 'window.c', - 'win_config.c', - 'tabpage.c', - 'autocmd.c', - 'ui.c', - 'deprecated.c' if INCLUDE_DEPRECATED else '' - ] if x], - files=['src/nvim/api'], - file_patterns = '*.h *.c', - fn_name_prefix = 'nvim_', - section_name={ - 'vim.c': 'Global', - }, - section_fmt=lambda name: f'{name} Functions', - helptag_fmt=lambda name: f'*api-{name.lower()}*', - fn_helptag_fmt=lambda fstem, name, istbl: f'*{name}()*', - module_override={}, - append_only=[], - ), - 'lua': Config( - mode='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', - ], - file_patterns='*.lua', - fn_name_prefix='', - fn_name_fmt=lambda fstem, name: ( - name if fstem in [ 'vim.iter' ] else - f'vim.{name}' if fstem in [ '_editor', 'vim.regex'] else - f'vim.{name}' if fstem == '_options' and not name[0].isupper() else - f'{fstem}.{name}' if fstem.startswith('vim') else - name - ), - section_name={ - 'lsp.lua': 'core', - '_inspector.lua': 'inspector', - }, - section_fmt=lambda name: ( - 'Lua module: vim' if name.lower() == '_editor' else - 'LUA-VIMSCRIPT BRIDGE' if name.lower() == '_options' else - f'VIM.{name.upper()}' if name.lower() in [ - 'highlight', 'mpack', 'json', 'base64', 'diff', 'spell', - 'regex', 'lpeg', 're', - ] else - 'VIM' if name.lower() == 'builtin' else - f'Lua module: vim.{name.lower()}'), - helptag_fmt=lambda name: ( - '*lua-vim*' if name.lower() == '_editor' else - '*lua-vimscript*' if name.lower() == '_options' else - f'*vim.{name.lower()}*'), - fn_helptag_fmt=lambda fstem, name, istbl: ( - f'*vim.opt:{name.split(":")[-1]}()*' if ':' in name and name.startswith('Option') else - # Exclude fstem for methods - f'*{name}()*' if ':' in name else - f'*vim.{name}()*' if fstem.lower() == '_editor' else - f'*vim.{name}*' if fstem.lower() == '_options' and istbl else - # Prevents vim.regex.regex - f'*{fstem}()*' if fstem.endswith('.' + name) else - f'*{fstem}.{name}{"" if istbl else "()"}*' - ), - module_override={ - # `shared` functions are exposed on the `vim` module. - 'shared': 'vim', - '_inspector': 'vim', - 'uri': 'vim', - 'ui': 'vim.ui', - 'loader': 'vim.loader', - 'filetype': 'vim.filetype', - 'keymap': 'vim.keymap', - 'fs': 'vim.fs', - 'highlight': 'vim.highlight', - 'secure': 'vim.secure', - 'version': 'vim.version', - 'iter': 'vim.iter', - 'diff': 'vim', - 'builtin': 'vim', - 'mpack': 'vim.mpack', - 'json': 'vim.json', - 'base64': 'vim.base64', - 'regex': 'vim.regex', - 'lpeg': 'vim.lpeg', - 're': 'vim.re', - 'spell': 'vim.spell', - 'snippet': 'vim.snippet', - 'text': 'vim.text', - 'glob': 'vim.glob', - }, - append_only=[ - 'shared.lua', - ], - ), - 'lsp': Config( - mode='lua', - 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', - ], - file_patterns='*.lua', - fn_name_prefix='', - section_name={'lsp.lua': 'lsp'}, - section_fmt=lambda name: ( - 'Lua module: vim.lsp' - if name.lower() == 'lsp' - else f'Lua module: vim.lsp.{name.lower()}'), - helptag_fmt=lambda name: ( - '*lsp-core*' - if name.lower() == 'lsp' - else f'*lsp-{name.lower()}*'), - fn_helptag_fmt=lambda fstem, name, istbl: ( - f'*vim.lsp.{name}{"" if istbl else "()"}*' if fstem == 'lsp' and name != 'client' else - # HACK. TODO(justinmk): class/structure support in lua2dox - '*vim.lsp.client*' if 'lsp.client' == f'{fstem}.{name}' else - f'*vim.lsp.{fstem}.{name}{"" if istbl else "()"}*'), - module_override={}, - append_only=[], - ), - 'diagnostic': Config( - mode='lua', - filename='diagnostic.txt', - section_order=[ - 'diagnostic.lua', - ], - files=['runtime/lua/vim/diagnostic.lua'], - file_patterns='*.lua', - fn_name_prefix='', - include_tables=False, - section_name={'diagnostic.lua': 'diagnostic'}, - section_fmt=lambda _: 'Lua module: vim.diagnostic', - helptag_fmt=lambda _: '*diagnostic-api*', - fn_helptag_fmt=lambda fstem, name, istbl: f'*vim.{fstem}.{name}{"" if istbl else "()"}*', - module_override={}, - append_only=[], - ), - 'treesitter': Config( - mode='lua', - 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/', - ], - file_patterns='*.lua', - fn_name_prefix='', - section_name={}, - section_fmt=lambda name: ( - 'Lua module: vim.treesitter' - if name.lower() == 'treesitter' - else f'Lua module: vim.treesitter.{name.lower()}'), - helptag_fmt=lambda name: ( - '*lua-treesitter-core*' - if name.lower() == 'treesitter' - else f'*lua-treesitter-{name.lower()}*'), - fn_helptag_fmt=lambda fstem, name, istbl: ( - f'*vim.{fstem}.{name}()*' - if fstem == 'treesitter' - else f'*{name}()*' - if name[0].isupper() - else f'*vim.treesitter.{fstem}.{name}()*'), - module_override={}, - append_only=[], - ), -} - -param_exclude = ( - 'channel_id', -) - -# Annotations are displayed as line items after API function descriptions. -annotation_map = { - 'FUNC_API_FAST': '|api-fast|', - 'FUNC_API_TEXTLOCK': 'not allowed when |textlock| is active or in the |cmdwin|', - 'FUNC_API_TEXTLOCK_ALLOW_CMDWIN': 'not allowed when |textlock| is active', - 'FUNC_API_REMOTE_ONLY': '|RPC| only', - 'FUNC_API_LUA_ONLY': 'Lua |vim.api| only', -} - - -def nvim_api_info() -> Tuple[int, bool]: - """Returns NVIM_API_LEVEL, NVIM_API_PRERELEASE from CMakeLists.txt""" - if not hasattr(nvim_api_info, 'LEVEL'): - script_dir = os.path.dirname(os.path.abspath(__file__)) - cmake_file_path = os.path.join(script_dir, '..', 'CMakeLists.txt') - with open(cmake_file_path, 'r') as cmake_file: - cmake_content = cmake_file.read() - - api_level_match = re.search(r'set\(NVIM_API_LEVEL (\d+)\)', cmake_content) - api_prerelease_match = re.search( - r'set\(NVIM_API_PRERELEASE (\w+)\)', cmake_content - ) - - if not api_level_match or not api_prerelease_match: - raise RuntimeError( - 'Could not find NVIM_API_LEVEL or NVIM_API_PRERELEASE in CMakeLists.txt' - ) - - nvim_api_info.LEVEL = int(api_level_match.group(1)) - nvim_api_info.PRERELEASE = api_prerelease_match.group(1).lower() == 'true' - - return nvim_api_info.LEVEL, nvim_api_info.PRERELEASE - - -# Raises an error with details about `o`, if `cond` is in object `o`, -# or if `cond()` is callable and returns True. -def debug_this(o, cond=True): - name = '' - if cond is False: - return - if not isinstance(o, str): - try: - name = o.nodeName - o = o.toprettyxml(indent=' ', newl='\n') - except Exception: - pass - if (cond is True - or (callable(cond) and cond()) - or (not callable(cond) and cond in o)): - raise RuntimeError('xxx: {}\n{}'.format(name, o)) - - -# Appends a message to a list which will be printed on exit. -def msg(s): - msgs.append(s) - - -# Print all collected messages. -def msg_report(): - for m in msgs: - print(f' {m}') - - -# Print collected messages, then throw an exception. -def fail(s): - msg_report() - raise RuntimeError(s) - - -def find_first(parent, name): - """Finds the first matching node within parent.""" - sub = parent.getElementsByTagName(name) - if not sub: - return None - return sub[0] - - -def iter_children(parent, name): - """Yields matching child nodes within parent.""" - for child in parent.childNodes: - if child.nodeType == child.ELEMENT_NODE and child.nodeName == name: - yield child - - -def get_child(parent, name): - """Gets the first matching child node.""" - for child in iter_children(parent, name): - return child - return None - - -def self_or_child(n): - """Gets the first child node, or self.""" - if len(n.childNodes) == 0: - return n - return n.childNodes[0] - - -def align_tags(line): - tag_regex = r"\s(\*.+?\*)(?:\s|$)" - tags = re.findall(tag_regex, line) - - if len(tags) > 0: - line = re.sub(tag_regex, "", line) - tags = " " + " ".join(tags) - line = line + (" " * (78 - len(line) - len(tags))) + tags - return line - - -def clean_lines(text): - """Removes superfluous lines. - - The beginning and end of the string is trimmed. Empty lines are collapsed. - """ - return re.sub(r'\A\n\s*\n*|\n\s*\n*\Z', '', re.sub(r'(\n\s*\n+)+', '\n\n', text)) - - -def is_blank(text): - return '' == clean_lines(text) - - -def get_text(n): - """Recursively concatenates all text in a node tree.""" - text = '' - if n.nodeType == n.TEXT_NODE: - return n.data - if n.nodeName == 'computeroutput': - for node in n.childNodes: - text += get_text(node) - return '`{}`'.format(text) - if n.nodeName == 'sp': # space, used in "programlisting" nodes - return ' ' - for node in n.childNodes: - if node.nodeType == node.TEXT_NODE: - text += node.data - elif node.nodeType == node.ELEMENT_NODE: - text += get_text(node) - return text - - -# Gets the length of the last line in `text`, excluding newline ("\n") char. -def len_lastline(text): - lastnl = text.rfind('\n') - if -1 == lastnl: - return len(text) - if '\n' == text[-1]: - return lastnl - (1 + text.rfind('\n', 0, lastnl)) - return len(text) - (1 + lastnl) - - -def len_lastline_withoutindent(text, indent): - n = len_lastline(text) - return (n - len(indent)) if n > len(indent) else 0 - - -# Returns True if node `n` contains only inline (not block-level) elements. -def is_inline(n): - # if len(n.childNodes) == 0: - # return n.nodeType == n.TEXT_NODE or n.nodeName == 'computeroutput' - for c in n.childNodes: - if c.nodeType != c.TEXT_NODE and c.nodeName != 'computeroutput': - return False - if not is_inline(c): - return False - return True - - -def doc_wrap(text, prefix='', width=70, func=False, indent=None) -> str: - """Wraps text to `width`. - - First line is prefixed with `prefix`, subsequent lines are aligned. - If `func` is True, only wrap at commas. - """ - if not width: - # return prefix + text - return text - - # Whitespace used to indent all lines except the first line. - indent = ' ' * len(prefix) if indent is None else indent - indent_only = (prefix == '' and indent is not None) - - if func: - lines = [prefix] - for part in text.split(', '): - if part[-1] not in ');': - part += ', ' - if len(lines[-1]) + len(part) > width: - lines.append(indent) - lines[-1] += part - return '\n'.join(x.rstrip() for x in lines).rstrip() - - # XXX: Dummy prefix to force TextWrapper() to wrap the first line. - if indent_only: - prefix = indent - - tw = textwrap.TextWrapper(break_long_words=False, - break_on_hyphens=False, - width=width, - initial_indent=prefix, - subsequent_indent=indent) - result = '\n'.join(tw.wrap(text.strip())) - - # XXX: Remove the dummy prefix. - if indent_only: - result = result[len(indent):] - - return result - - -def max_name(names): - if len(names) == 0: - return 0 - return max(len(name) for name in names) - - -def update_params_map(parent, ret_map, width=text_width - indentation): - """Updates `ret_map` with name:desc key-value pairs extracted - from Doxygen XML node `parent`. - """ - params = collections.OrderedDict() - for node in parent.childNodes: - if node.nodeType == node.TEXT_NODE: - continue - name_node = find_first(node, 'parametername') - if name_node.getAttribute('direction') == 'out': - continue - name = get_text(name_node) - if name in param_exclude: - continue - params[name.strip()] = node - max_name_len = max_name(params.keys()) + 8 - # `ret_map` is a name:desc map. - for name, node in params.items(): - desc = '' - desc_node = get_child(node, 'parameterdescription') - if desc_node: - desc = fmt_node_as_vimhelp( - desc_node, width=width, indent=(' ' * max_name_len)) - ret_map[name] = desc - return ret_map - - -def render_node(n: Element, text: str, prefix='', *, - indent: str = '', - width: int = (text_width - indentation), - fmt_vimhelp: bool = False): - """Renders a node as Vim help text, recursively traversing all descendants.""" - - def ind(s): - return s if fmt_vimhelp else '' - - # Get the current column offset from the last line of `text` - # (needed to appropriately wrap multiple and contiguous inline elements) - col_offset: int = len_lastline(text) - - text = '' - # space_preceding = (len(text) > 0 and ' ' == text[-1][-1]) - # text += (int(not space_preceding) * ' ') - - if n.nodeName == 'preformatted': - o = get_text(n) - ensure_nl = '' if o[-1] == '\n' else '\n' - if o[0:4] == 'lua\n': - text += '>lua{}{}\n<'.format(ensure_nl, o[3:-1]) - elif o[0:4] == 'vim\n': - text += '>vim{}{}\n<'.format(ensure_nl, o[3:-1]) - elif o[0:5] == 'help\n': - text += o[4:-1] - else: - text += '>{}{}\n<'.format(ensure_nl, o) - elif n.nodeName == 'programlisting': # codeblock (```) - o = get_text(n) - text += '>' - if 'filename' in n.attributes: - filename = n.attributes['filename'].value - text += filename.lstrip('.') - - text += '\n{}\n<'.format(textwrap.indent(o, ' ' * 4)) - elif is_inline(n): - o = get_text(n).strip() - if o: - DEL = chr(127) # a dummy character to pad for proper line wrap - assert len(DEL) == 1 - dummy_padding = DEL * max(0, col_offset - len(prefix)) - text += doc_wrap(dummy_padding + o, - prefix=prefix, indent=indent, width=width - ).replace(DEL, "") - elif n.nodeName == 'verbatim': - # TODO: currently we don't use this. The "[verbatim]" hint is there as - # a reminder that we must decide how to format this if we do use it. - text += ' [verbatim] {}'.format(get_text(n)) - elif n.nodeName == 'listitem': - for c in n.childNodes: - result = render_node( - c, - text, - indent=indent + (' ' * len(prefix)), - width=width - ) - if is_blank(result): - continue - text += indent + prefix + result - elif n.nodeName in ('para', 'heading'): - did_prefix = False - for c in n.childNodes: - c_text = render_node(c, text, prefix=(prefix if not did_prefix else ''), indent=indent, width=width) - if (is_inline(c) - and '' != c_text.strip() - and text - and text[-1] not in (' ', '(', '|') - and not c_text.startswith(')')): - text += ' ' - text += c_text - did_prefix = True - elif n.nodeName == 'itemizedlist': - for c in n.childNodes: - text += '{}\n'.format(render_node(c, text, prefix='• ', - indent=indent, width=width)) - elif n.nodeName == 'orderedlist': - i = 1 - for c in n.childNodes: - if is_blank(get_text(c)): - text += '\n' - continue - text += '{}\n'.format(render_node(c, text, prefix='{}. '.format(i), - indent=indent, width=width)) - i = i + 1 - elif n.nodeName == 'simplesect' and 'note' == n.getAttribute('kind'): - text += ind(' ') - for c in n.childNodes: - if is_blank(render_node(c, text, prefix='• ', indent=' ', width=width)): - continue - text += render_node(c, text, prefix='• ', indent=' ', width=width) - # text += '\n' - elif n.nodeName == 'simplesect' and 'warning' == n.getAttribute('kind'): - text += 'Warning:\n ' - for c in n.childNodes: - text += render_node(c, text, indent=' ', width=width) - text += '\n' - elif n.nodeName == 'simplesect' and 'see' == n.getAttribute('kind'): - text += ind(' ') - # Example: - # - # |autocommand| - # - for c in n.childNodes: - text += render_node(c, text, prefix='• ', indent=' ', width=width) - elif n.nodeName == 'simplesect' and 'return' == n.getAttribute('kind'): - text += ind(' ') - for c in n.childNodes: - text += render_node(c, text, indent=' ', width=width) - elif n.nodeName == 'computeroutput': - return get_text(n) - else: - raise RuntimeError('unhandled node type: {}\n{}'.format( - n.nodeName, n.toprettyxml(indent=' ', newl='\n'))) - - return text - - -def para_as_map(parent: Element, - indent: str = '', - width: int = (text_width - indentation), - ): - """Extracts a Doxygen XML node to a map. - - Keys: - 'text': Text from this element - 'note': List of @note strings - 'params': map - 'return': List of @return strings - 'seealso': List of @see strings - 'xrefs': ? - """ - chunks = { - 'text': '', - 'note': [], - 'params': collections.OrderedDict(), - 'return': [], - 'seealso': [], - 'prerelease': False, - 'xrefs': [] - } - - # Ordered dict of ordered lists. - groups = collections.OrderedDict([ - ('note', []), - ('params', []), - ('return', []), - ('seealso', []), - ('xrefs', []), - ]) - - # Gather nodes into groups. Mostly this is because we want "parameterlist" - # nodes to appear together. - text = '' - kind = '' - if is_inline(parent): - # Flatten inline text from a tree of non-block nodes. - text = doc_wrap(render_node(parent, ""), - indent=indent, width=width) - else: - prev = None # Previous node - for child in parent.childNodes: - if child.nodeName == 'parameterlist': - groups['params'].append(child) - elif child.nodeName == 'xrefsect': - groups['xrefs'].append(child) - elif child.nodeName == 'simplesect': - kind = child.getAttribute('kind') - if kind == 'note': - groups['note'].append(child) - elif kind == 'return': - groups['return'].append(child) - elif kind == 'see': - groups['seealso'].append(child) - elif kind == 'warning': - text += render_node(child, text, indent=indent, width=width) - elif kind == 'since': - since_match = re.match(r'^(\d+)', get_text(child)) - since = int(since_match.group(1)) if since_match else 0 - NVIM_API_LEVEL, NVIM_API_PRERELEASE = nvim_api_info() - if since > NVIM_API_LEVEL or ( - since == NVIM_API_LEVEL and NVIM_API_PRERELEASE - ): - chunks['prerelease'] = True - else: - raise RuntimeError('unhandled simplesect: {}\n{}'.format( - child.nodeName, child.toprettyxml(indent=' ', newl='\n'))) - else: - child_text = render_node(child, text, indent=indent, width=width) - if (prev is not None - and is_inline(self_or_child(prev)) - and is_inline(self_or_child(child)) - and '' != get_text(self_or_child(child)).strip() - and text - and text[-1] not in (' ', '(', '|') - and not child_text.startswith(')')): - text += ' ' - - text += child_text - prev = child - - chunks['text'] += text - - # Generate map from the gathered items. - if len(groups['params']) > 0: - for child in groups['params']: - update_params_map(child, ret_map=chunks['params'], width=width) - for child in groups['note']: - chunks['note'].append(render_node( - child, '', indent=indent, width=width).rstrip()) - for child in groups['return']: - chunks['return'].append(render_node( - child, '', indent=indent, width=width)) - for child in groups['seealso']: - # Example: - # - # |autocommand| - # - chunks['seealso'].append(render_node( - child, '', indent=indent, width=width)) - - xrefs = set() - for child in groups['xrefs']: - # XXX: Add a space (or any char) to `title` here, otherwise xrefs - # ("Deprecated" section) acts very weird... - title = get_text(get_child(child, 'xreftitle')) + ' ' - xrefs.add(title) - xrefdesc = get_text(get_child(child, 'xrefdescription')) - chunks['xrefs'].append(doc_wrap(xrefdesc, prefix='{}: '.format(title), - width=width) + '\n') - - return chunks, xrefs - - -def is_program_listing(para): - """ - Return True if `para` contains a "programlisting" (i.e. a Markdown code - block ```). - - Sometimes a element will have only a single "programlisting" child - node, but othertimes it will have extra whitespace around the - "programlisting" node. - - @param para XML node - @return True if is a programlisting - """ - - # Remove any child text nodes that are only whitespace - children = [ - n for n in para.childNodes - if n.nodeType != n.TEXT_NODE or n.data.strip() != '' - ] - - return len(children) == 1 and children[0].nodeName == 'programlisting' - - -FunctionParam = Tuple[ - str, # type - str, # parameter name -] - -@dataclasses.dataclass -class FunctionDoc: - """Data structure for function documentation. Also exported as msgpack.""" - - annotations: List[str] - """Attributes, e.g., FUNC_API_REMOTE_ONLY. See annotation_map""" - - notes: List[Docstring] - """Notes: (@note strings)""" - - signature: str - """Function signature with *tags*.""" - - parameters: List[FunctionParam] - """Parameters: (type, name)""" - - parameters_doc: Dict[str, Docstring] - """Parameters documentation. Key is parameter name, value is doc.""" - - doc: List[Docstring] - """Main description for the function. Separated by paragraph.""" - - return_: List[Docstring] - """Return:, or Return (multiple): (@return strings)""" - - seealso: List[Docstring] - """See also: (@see strings)""" - - xrefs: List[Docstring] - """XRefs. Currently only used to track Deprecated functions.""" - - # for INCLUDE_C_DECL - c_decl: str | None = None - - prerelease: bool = False - - def export_mpack(self) -> Dict[str, Any]: - """Convert a dict to be exported as mpack data.""" - exported = self.__dict__.copy() - del exported['notes'] - del exported['c_decl'] - del exported['prerelease'] - del exported['xrefs'] - exported['return'] = exported.pop('return_') - return exported - - def doc_concatenated(self) -> Docstring: - """Concatenate all the paragraphs in `doc` into a single string, but - remove blank lines before 'programlisting' blocks. #25127 - - BEFORE (without programlisting processing): - ```vimdoc - Example: - - >vim - :echo nvim_get_color_by_name("Pink") - < - ``` - - AFTER: - ```vimdoc - Example: >vim - :echo nvim_get_color_by_name("Pink") - < - ``` - """ - def is_program_listing(paragraph: str) -> bool: - lines = paragraph.strip().split('\n') - return lines[0].startswith('>') and lines[-1] == '<' - - rendered = [] - for paragraph in self.doc: - if is_program_listing(paragraph): - rendered.append(' ') # Example: >vim - elif rendered: - rendered.append('\n\n') - rendered.append(paragraph) - return ''.join(rendered) - - def render(self) -> Docstring: - """Renders function documentation as Vim :help text.""" - rendered_blocks: List[Docstring] = [] - - def fmt_param_doc(m): - """Renders a params map as Vim :help text.""" - max_name_len = max_name(m.keys()) + 4 - out = '' - for name, desc in m.items(): - if name == 'self': - continue - name = ' • {}'.format('{{{}}}'.format(name).ljust(max_name_len)) - out += '{}{}\n'.format(name, desc) - return out.rstrip() - - # Generate text from the gathered items. - chunks: List[Docstring] = [self.doc_concatenated()] - - notes = [] - if self.prerelease: - notes = [" This API is pre-release (unstable)."] - notes += self.notes - if len(notes) > 0: - chunks.append('\nNote: ~') - for s in notes: - chunks.append(' ' + s) - - if self.parameters_doc: - chunks.append('\nParameters: ~') - chunks.append(fmt_param_doc(self.parameters_doc)) - - if self.return_: - chunks.append('\nReturn (multiple): ~' if len(self.return_) > 1 - else '\nReturn: ~') - for s in self.return_: - chunks.append(' ' + s) - - if self.seealso: - chunks.append('\nSee also: ~') - for s in self.seealso: - chunks.append(' ' + s) - - # Note: xrefs are currently only used to remark "Deprecated: " - # for deprecated functions; visible when INCLUDE_DEPRECATED is set - for s in self.xrefs: - chunks.append('\n' + s) - - rendered_blocks.append(clean_lines('\n'.join(chunks).strip())) - rendered_blocks.append('') - - return clean_lines('\n'.join(rendered_blocks).strip()) - - -def fmt_node_as_vimhelp(parent: Element, width=text_width - indentation, indent=''): - """Renders (nested) Doxygen nodes as Vim :help text. - - Only handles "text" nodes. Used for individual elements (see render_node()) - and in extract_defgroups(). - - NB: Blank lines in a docstring manifest as tags. - """ - rendered_blocks = [] - - for child in parent.childNodes: - para, _ = para_as_map(child, indent, width) - - # 'programlisting' blocks are Markdown code blocks. Do not include - # these as a separate paragraph, but append to the last non-empty line - # in the text - if is_program_listing(child): - while rendered_blocks and rendered_blocks[-1] == '': - rendered_blocks.pop() - rendered_blocks[-1] += ' ' + para['text'] - continue - - # Generate text from the gathered items. - chunks = [para['text']] - - rendered_blocks.append(clean_lines('\n'.join(chunks).strip())) - rendered_blocks.append('') - - return clean_lines('\n'.join(rendered_blocks).strip()) - - -def extract_from_xml(filename, target, *, - width: int, fmt_vimhelp: bool) -> Tuple[ - Dict[FunctionName, FunctionDoc], - Dict[FunctionName, FunctionDoc], -]: - """Extracts Doxygen info as maps without formatting the text. - - Returns two maps: - 1. Functions - 2. Deprecated functions - - The `fmt_vimhelp` variable controls some special cases for use by - fmt_doxygen_xml_as_vimhelp(). (TODO: ugly :) - """ - config: Config = CONFIG[target] - - fns: Dict[FunctionName, FunctionDoc] = {} - deprecated_fns: Dict[FunctionName, FunctionDoc] = {} - - dom = minidom.parse(filename) - compoundname = get_text(dom.getElementsByTagName('compoundname')[0]) - for member in dom.getElementsByTagName('memberdef'): - if member.getAttribute('static') == 'yes' or \ - member.getAttribute('kind') != 'function' or \ - member.getAttribute('prot') == 'private' or \ - get_text(get_child(member, 'name')).startswith('_'): - continue - - loc = find_first(member, 'location') - if 'private' in loc.getAttribute('file'): - continue - - return_type = get_text(get_child(member, 'type')) - if return_type == '': - continue - - if 'local_function' in return_type: # Special from lua2dox.lua. - continue - - istbl = return_type.startswith('table') # Special from lua2dox.lua. - if istbl and not config.include_tables: - continue - - if return_type.startswith(('ArrayOf', 'DictionaryOf')): - parts = return_type.strip('_').split('_') - return_type = '{}({})'.format(parts[0], ', '.join(parts[1:])) - - name = get_text(get_child(member, 'name')) - - annotations = get_text(get_child(member, 'argsstring')) - if annotations and ')' in annotations: - annotations = annotations.rsplit(')', 1)[-1].strip() - # XXX: (doxygen 1.8.11) 'argsstring' only includes attributes of - # non-void functions. Special-case void functions here. - if name == 'nvim_get_mode' and len(annotations) == 0: - annotations += 'FUNC_API_FAST' - annotations = filter(None, map(lambda x: annotation_map.get(x), - annotations.split())) - - params = [] - type_length = 0 - - for param in iter_children(member, 'param'): - param_type = get_text(get_child(param, 'type')).strip() - param_name = '' - declname = get_child(param, 'declname') - if declname: - param_name = get_text(declname).strip() - elif config.mode == 'lua': - # XXX: this is what lua2dox gives us... - param_name = param_type - param_type = '' - - if param_name in param_exclude: - continue - - if fmt_vimhelp and param_type.endswith('*'): - param_type = param_type.strip('* ') - param_name = '*' + param_name - - type_length = max(type_length, len(param_type)) - params.append((param_type, param_name)) - - # Handle Object Oriented style functions here. - # We make sure they have "self" in the parameters, - # and a parent function - if return_type.startswith('function') \ - and len(return_type.split(' ')) >= 2 \ - and any(x[1] == 'self' for x in params): - split_return = return_type.split(' ') - name = f'{split_return[1]}:{name}' - params = [x for x in params if x[1] != 'self'] - - c_args = [] - for param_type, param_name in params: - c_args.append((' ' if fmt_vimhelp else '') + ( - '%s %s' % (param_type.ljust(type_length), param_name)).strip()) - - if not fmt_vimhelp: - pass - else: - fstem = '?' - if '.' in compoundname: - fstem = compoundname.split('.')[0] - fstem = config.module_override.get(fstem, fstem) - vimtag = config.fn_helptag_fmt(fstem, name, istbl) - - if config.fn_name_fmt: - name = config.fn_name_fmt(fstem, name) - - if istbl: - aopen, aclose = '', '' - else: - aopen, aclose = '(', ')' - - prefix = name + aopen - suffix = ', '.join('{%s}' % a[1] for a in params - if a[0] not in ('void', 'Error', 'Arena', - 'lua_State')) + aclose - - if not fmt_vimhelp: - c_decl = '%s %s(%s);' % (return_type, name, ', '.join(c_args)) - signature = prefix + suffix - else: - c_decl = textwrap.indent('%s %s(\n%s\n);' % (return_type, name, - ',\n'.join(c_args)), - ' ') - - # Minimum 8 chars between signature and vimtag - lhs = (width - 8) - len(vimtag) - - if len(prefix) + len(suffix) > lhs: - signature = vimtag.rjust(width) + '\n' - signature += doc_wrap(suffix, width=width, prefix=prefix, - func=True) - else: - signature = prefix + suffix - signature += vimtag.rjust(width - len(signature)) - - # Tracks `xrefsect` titles. As of this writing, used only for separating - # deprecated functions. - xrefs_all = set() - paras: List[Dict[str, Any]] = [] # paras means paragraphs! - brief_desc = find_first(member, 'briefdescription') - if brief_desc: - for child in brief_desc.childNodes: - para, xrefs = para_as_map(child) - paras.append(para) - xrefs_all.update(xrefs) - - desc = find_first(member, 'detaileddescription') - if desc: - paras_detail = [] # override briefdescription - for child in desc.childNodes: - para, xrefs = para_as_map(child) - paras_detail.append(para) - xrefs_all.update(xrefs) - log.debug( - textwrap.indent( - re.sub(r'\n\s*\n+', '\n', - desc.toprettyxml(indent=' ', newl='\n')), - ' ' * indentation)) - - # override briefdescription, if detaileddescription is not empty - # (note: briefdescription can contain some erroneous luadoc - # comments from preceding comments, this is a bug of lua2dox) - if any((para['text'] or para['note'] or para['params'] or - para['return'] or para['seealso'] - ) for para in paras_detail): - paras = paras_detail - - fn = FunctionDoc( - annotations=list(annotations), - notes=[], - signature=signature, - parameters=params, - parameters_doc=collections.OrderedDict(), - doc=[], - return_=[], - seealso=[], - xrefs=[], - ) - - for m in paras: - if m.get('text', ''): - fn.doc.append(m['text']) - if 'params' in m: - # Merge OrderedDicts. - fn.parameters_doc.update(m['params']) - if 'return' in m and len(m['return']) > 0: - fn.return_ += m['return'] - if 'seealso' in m and len(m['seealso']) > 0: - fn.seealso += m['seealso'] - if m.get('prerelease', False): - fn.prerelease = True - if 'note' in m: - fn.notes += m['note'] - if 'xrefs' in m: - fn.xrefs += m['xrefs'] - - if INCLUDE_C_DECL: - fn.c_decl = c_decl - - if 'Deprecated' in str(xrefs_all): - deprecated_fns[name] = fn - elif name.startswith(config.fn_name_prefix): - fns[name] = fn - - # sort functions by name (lexicographically) - fns = collections.OrderedDict(sorted( - fns.items(), - key=lambda key_item_tuple: key_item_tuple[0].lower(), - )) - deprecated_fns = collections.OrderedDict(sorted(deprecated_fns.items())) - return fns, deprecated_fns - - -def fmt_doxygen_xml_as_vimhelp(filename, target) -> Tuple[Docstring, Docstring]: - """Entrypoint for generating Vim :help from from Doxygen XML. - - Returns 2 items: - 1. Vim help text for functions found in `filename`. - 2. Vim help text for deprecated functions. - """ - config: Config = CONFIG[target] - - fns_txt = {} # Map of func_name:vim-help-text. - deprecated_fns_txt = {} # Map of func_name:vim-help-text. - - fns: Dict[FunctionName, FunctionDoc] - deprecated_fns: Dict[FunctionName, FunctionDoc] - fns, deprecated_fns = extract_from_xml( - filename, target, width=text_width, fmt_vimhelp=True) - - def _handle_fn(fn_name: FunctionName, fn: FunctionDoc, - fns_txt: Dict[FunctionName, Docstring], deprecated=False): - # Generate Vim :help for parameters. - - # Generate body from FunctionDoc, not XML nodes - doc = fn.render() - if not doc and fn_name.startswith("nvim__"): - return - if not doc: - doc = ('TODO: Documentation' if not deprecated - else 'Deprecated.') - - # Annotations: put before Parameters - annotations: str = '\n'.join(fn.annotations) - if annotations: - annotations = ('\n\nAttributes: ~\n' + - textwrap.indent(annotations, ' ')) - i = doc.rfind('Parameters: ~') - if i == -1: - doc += annotations - else: - doc = doc[:i] + annotations + '\n\n' + doc[i:] - - # C Declaration: (debug only) - if INCLUDE_C_DECL: - doc += '\n\nC Declaration: ~\n>\n' - assert fn.c_decl is not None - doc += fn.c_decl - doc += '\n<' - - # Start of function documentations. e.g., - # nvim_cmd({*cmd}, {*opts}) *nvim_cmd()* - func_doc = fn.signature + '\n' - func_doc += textwrap.indent(clean_lines(doc), ' ' * indentation) - - # Verbatim handling. - func_doc = re.sub(r'^\s+([<>])$', r'\1', func_doc, flags=re.M) - - def process_helptags(func_doc: str) -> str: - lines: List[str] = func_doc.split('\n') - # skip ">lang ... <" regions - is_verbatim: bool = False - for i in range(len(lines)): - if re.search(' >([a-z])*$', lines[i]): - is_verbatim = True - elif is_verbatim and lines[i].strip() == '<': - is_verbatim = False - if not is_verbatim: - lines[i] = align_tags(lines[i]) - return "\n".join(lines) - - func_doc = process_helptags(func_doc) - - if (fn_name.startswith(config.fn_name_prefix) - and fn_name != "nvim_error_event"): - fns_txt[fn_name] = func_doc - - for fn_name, fn in fns.items(): - _handle_fn(fn_name, fn, fns_txt) - for fn_name, fn in deprecated_fns.items(): - _handle_fn(fn_name, fn, deprecated_fns_txt, deprecated=True) - - return ( - '\n\n'.join(list(fns_txt.values())), - '\n\n'.join(list(deprecated_fns_txt.values())), - ) - - -def delete_lines_below(filename, tokenstr): - """Deletes all lines below the line containing `tokenstr`, the line itself, - and one line above it. - """ - lines = open(filename).readlines() - i = 0 - found = False - for i, line in enumerate(lines, 1): - if tokenstr in line: - found = True - break - if not found: - raise RuntimeError(f'not found: "{tokenstr}"') - i = max(0, i - 2) - with open(filename, 'wt') as fp: - fp.writelines(lines[0:i]) - - -def extract_defgroups(base: str, dom: Document) -> Dict[SectionName, Docstring]: - '''Generate module-level (section) docs (@defgroup).''' - section_docs = {} - - for compound in dom.getElementsByTagName('compound'): - if compound.getAttribute('kind') != 'group': - continue - - # Doxygen "@defgroup" directive. - groupname = get_text(find_first(compound, 'name')) - groupxml = os.path.join(base, '%s.xml' % - compound.getAttribute('refid')) - - group_parsed = minidom.parse(groupxml) - doc_list = [] - brief_desc = find_first(group_parsed, 'briefdescription') - if brief_desc: - for child in brief_desc.childNodes: - doc_list.append(fmt_node_as_vimhelp(child)) - - desc = find_first(group_parsed, 'detaileddescription') - if desc: - doc = fmt_node_as_vimhelp(desc) - - if doc: - doc_list.append(doc) - - # Can't use '.' in @defgroup, so convert to '--' - # "vim.json" => "vim-dot-json" - groupname = groupname.replace('-dot-', '.') - - section_docs[groupname] = "\n".join(doc_list) - - return section_docs - - -@dataclasses.dataclass -class Section: - """Represents a section. Includes section heading (defgroup) - and all the FunctionDoc that belongs to this section.""" - - name: str - '''Name of the section. Usually derived from basename of lua/c src file. - Example: "Autocmd".''' - - title: str - '''Formatted section config. see config.section_fmt(). - Example: "Autocmd Functions". ''' - - helptag: str - '''see config.helptag_fmt(). Example: *api-autocmd*''' - - @property - def id(self) -> str: - '''section id: Module/Section id matched against @defgroup. - e.g., "*api-autocmd*" => "api-autocmd" - ''' - return self.helptag.strip('*') - - doc: str = "" - '''Section heading docs extracted from @defgroup.''' - - # TODO: Do not carry rendered text, but handle FunctionDoc for better OOP - functions_text: Docstring | None = None - '''(Rendered) doc of all the functions that belong to this section.''' - - deprecated_functions_text: Docstring | None = None - '''(Rendered) doc of all the deprecated functions that belong to this - section.''' - - def __repr__(self): - return f"Section(title='{self.title}', helptag='{self.helptag}')" - - @classmethod - def make_from(cls, filename: str, config: Config, - section_docs: Dict[SectionName, str], - *, - functions_text: Docstring, - deprecated_functions_text: Docstring, - ): - # filename: e.g., 'autocmd.c' - # name: e.g. 'autocmd' - name = os.path.splitext(filename)[0].lower() - - # section name: e.g. "Autocmd" - sectname: SectionName - sectname = name.upper() if name == 'ui' else name.title() - sectname = config.section_name.get(filename, sectname) - - # Formatted (this is what's going to be written in the vimdoc) - # e.g., "Autocmd Functions" - title: str = config.section_fmt(sectname) - - # section tag: e.g., "*api-autocmd*" - section_tag: str = config.helptag_fmt(sectname) - - section = cls(name=sectname, title=title, helptag=section_tag, - functions_text=functions_text, - deprecated_functions_text=deprecated_functions_text, - ) - section.doc = section_docs.get(section.id) or '' - return section - - def render(self, add_header=True) -> str: - """Render as vimdoc.""" - doc = '' - - if add_header: - doc += SECTION_SEP - doc += '\n{}{}'.format( - self.title, - self.helptag.rjust(text_width - len(self.title)) - ) - - if self.doc: - doc += '\n\n' + self.doc - - if self.functions_text: - doc += '\n\n' + self.functions_text - - if INCLUDE_DEPRECATED and self.deprecated_functions_text: - doc += f'\n\n\nDeprecated {self.name} Functions: ~\n\n' - doc += self.deprecated_functions_text - - return doc - - def __bool__(self) -> bool: - """Whether this section has contents. Used for skipping empty ones.""" - return bool(self.doc or self.functions_text or - (INCLUDE_DEPRECATED and self.deprecated_functions_text)) - - -def main(doxygen_config, args): - """Generates: - - 1. Vim :help docs - 2. *.mpack files for use by API clients - - Doxygen is called and configured through stdin. - """ - for target in CONFIG: - if args.target is not None and target != args.target: - continue - - config: Config = CONFIG[target] - - mpack_file = os.path.join( - base_dir, 'runtime', 'doc', - config.filename.replace('.txt', '.mpack')) - if os.path.exists(mpack_file): - os.remove(mpack_file) - - output_dir = out_dir.format(target=target) - log.info("Generating documentation for %s in folder %s", - target, output_dir) - debug = args.log_level >= logging.DEBUG - p = subprocess.Popen( - ['doxygen', '-'], - stdin=subprocess.PIPE, - # silence warnings - # runtime/lua/vim/lsp.lua:209: warning: argument 'foo' not found - stderr=(subprocess.STDOUT if debug else subprocess.DEVNULL)) - p.communicate( - doxygen_config.format( - input=' '.join([f'"{file}"' for file in config.files]), - output=output_dir, - filter=filter_cmd, - file_patterns=config.file_patterns) - .encode('utf8') - ) - if p.returncode: - sys.exit(p.returncode) - - # Collects all functions as each module is processed. - fn_map_full: Dict[FunctionName, FunctionDoc] = {} - # key: filename (e.g. autocmd.c) - sections: Dict[str, Section] = {} - - base = os.path.join(output_dir, 'xml') - dom = minidom.parse(os.path.join(base, 'index.xml')) - - # Collect all @defgroups (section headings after the '===...' separator - section_docs: Dict[SectionName, Docstring] = extract_defgroups(base, dom) - - # Generate docs for all functions in the current module. - for compound in dom.getElementsByTagName('compound'): - if compound.getAttribute('kind') != 'file': - continue - - filename = get_text(find_first(compound, 'name')) - if not ( - filename.endswith('.c') or - filename.endswith('.lua') - ): - continue - - xmlfile = os.path.join(base, '{}.xml'.format(compound.getAttribute('refid'))) - - # Extract unformatted (*.mpack). - fn_map, _ = extract_from_xml( - xmlfile, target, width=9999, fmt_vimhelp=False) - - # Extract formatted (:help). - functions_text, deprecated_text = fmt_doxygen_xml_as_vimhelp( - xmlfile, target) - - if not functions_text and not deprecated_text: - continue - - filename = os.path.basename(filename) - - section: Section = Section.make_from( - filename, config, section_docs, - functions_text=functions_text, - deprecated_functions_text=deprecated_text, - ) - - if section: # if not empty - sections[filename] = section - fn_map_full.update(fn_map) - else: - log.debug("Skipping empty section: %s", section) - - if len(sections) == 0: - fail(f'no sections for target: {target} (look for errors near "Preprocessing" log lines above)') - if len(sections) > len(config.section_order): - raise RuntimeError( - '{}: found new modules {}; ' - 'update the "section_order" map'.format( - target, - set(sections).difference(config.section_order)) - ) - first_section_tag = sections[config.section_order[0]].helptag - - docs = '' - - for filename in config.section_order: - try: - section: Section = sections.pop(filename) - except KeyError: - msg(f'warning: empty docs, skipping (target={target}): {filename}') - msg(f' existing docs: {sections.keys()}') - continue - - add_sep_and_header = filename not in config.append_only - docs += section.render(add_header=add_sep_and_header) - docs += '\n\n\n' - - docs = docs.rstrip() + '\n\n' - docs += f' vim:tw=78:ts=8:sw={indentation}:sts={indentation}:et:ft=help:norl:\n' - - doc_file = os.path.join(base_dir, 'runtime', 'doc', config.filename) - - if os.path.exists(doc_file): - delete_lines_below(doc_file, first_section_tag) - with open(doc_file, 'ab') as fp: - fp.write(docs.encode('utf8')) - - fn_map_full_exported = collections.OrderedDict(sorted( - (name, fn_doc.export_mpack()) for (name, fn_doc) in fn_map_full.items() - )) - with open(mpack_file, 'wb') as fp: - fp.write(msgpack.packb(fn_map_full_exported, use_bin_type=True)) # type: ignore - - if not args.keep_tmpfiles: - shutil.rmtree(output_dir) - - msg_report() - - -def filter_source(filename, keep_tmpfiles): - output_dir = out_dir.format(target='lua2dox') - name, extension = os.path.splitext(filename) - if extension == '.lua': - args = [str(nvim), '-l', lua2dox, filename] + (['--outdir', output_dir] if keep_tmpfiles else []) - p = subprocess.run(args, stdout=subprocess.PIPE) - op = ('?' if 0 != p.returncode else p.stdout.decode('utf-8')) - print(op) - else: - """Filters the source to fix macros that confuse Doxygen.""" - with open(filename, 'rt') as fp: - print(re.sub(r'^(ArrayOf|DictionaryOf|Dict)(\(.*?\))', - lambda m: m.group(1)+'_'.join( - re.split(r'[^\w]+', m.group(2))), - fp.read(), flags=re.M)) - - -def parse_args(): - targets = ', '.join(CONFIG.keys()) - ap = argparse.ArgumentParser( - description="Generate helpdoc from source code") - ap.add_argument( - "--log-level", "-l", choices=LOG_LEVELS.keys(), - default=logging.getLevelName(logging.ERROR), help="Set log verbosity" - ) - ap.add_argument('source_filter', nargs='*', - help="Filter source file(s)") - ap.add_argument('-k', '--keep-tmpfiles', action='store_true', - help="Keep temporary files (tmp-xx-doc/ directories, including tmp-lua2dox-doc/ for lua2dox.lua quasi-C output)") - ap.add_argument('-t', '--target', - help=f'One of ({targets}), defaults to "all"') - return ap.parse_args() - - -Doxyfile = textwrap.dedent(''' - OUTPUT_DIRECTORY = {output} - INPUT = {input} - INPUT_ENCODING = UTF-8 - FILE_PATTERNS = {file_patterns} - RECURSIVE = YES - INPUT_FILTER = "{filter}" - EXCLUDE = - EXCLUDE_SYMLINKS = NO - EXCLUDE_PATTERNS = */private/* */health.lua */_*.lua - EXCLUDE_SYMBOLS = - EXTENSION_MAPPING = lua=C - EXTRACT_PRIVATE = NO - - GENERATE_HTML = NO - GENERATE_DOCSET = NO - GENERATE_HTMLHELP = NO - GENERATE_QHP = NO - GENERATE_TREEVIEW = NO - GENERATE_LATEX = NO - GENERATE_RTF = NO - GENERATE_MAN = NO - GENERATE_DOCBOOK = NO - GENERATE_AUTOGEN_DEF = NO - - GENERATE_XML = YES - XML_OUTPUT = xml - XML_PROGRAMLISTING = NO - - ENABLE_PREPROCESSING = YES - MACRO_EXPANSION = YES - EXPAND_ONLY_PREDEF = NO - MARKDOWN_SUPPORT = YES -''') - -if __name__ == "__main__": - args = parse_args() - print("Setting log level to %s" % args.log_level) - args.log_level = LOG_LEVELS[args.log_level] - log.setLevel(args.log_level) - log.addHandler(logging.StreamHandler()) - - # When invoked as a filter, args won't be passed, so use an env var. - if args.keep_tmpfiles: - os.environ['NVIM_KEEP_TMPFILES'] = '1' - keep_tmpfiles = ('NVIM_KEEP_TMPFILES' in os.environ) - - if len(args.source_filter) > 0: - filter_source(args.source_filter[0], keep_tmpfiles) - else: - main(Doxyfile, args) - -# vim: set ft=python ts=4 sw=4 tw=79 et : diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua deleted file mode 100644 index 0b3daa59b2..0000000000 --- a/scripts/lua2dox.lua +++ /dev/null @@ -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 - 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 ---- @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 ---- @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 ---- @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: - : 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 diff --git a/scripts/luacats_grammar.lua b/scripts/luacats_grammar.lua new file mode 100644 index 0000000000..ee0f9d8e87 --- /dev/null +++ b/scripts/luacats_grammar.lua @@ -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 +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]] diff --git a/scripts/luacats_parser.lua b/scripts/luacats_parser.lua new file mode 100644 index 0000000000..520272d1dc --- /dev/null +++ b/scripts/luacats_parser.lua @@ -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 +--- @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 +--- @param classvars table +--- @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 +--- @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 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 + 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 + + 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 diff --git a/scripts/text_utils.lua b/scripts/text_utils.lua new file mode 100644 index 0000000000..5167ec42f2 --- /dev/null +++ b/scripts/text_utils.lua @@ -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 + 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('^
help', '')
+    text = text:gsub('
%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] = '' + 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 diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 54ad43e8f3..5ec0e4d9ec 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -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}" + $ -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 $ -l ${PROJECT_SOURCE_DIR}/scripts/gen_eval_files.lua + COMMAND ${CMAKE_COMMAND} -E env "VIMRUNTIME=${NVIM_RUNTIME_DIR}" + $ -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 diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 7e33a77d24..06f21919f9 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -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, diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 41a3743895..7f195de959 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -50,9 +50,8 @@ # include "api/buffer.c.generated.h" #endif -/// \defgroup api-buffer -/// -/// \brief For more information on buffers, see |buffers| +/// @brief
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.
+/// 
/// 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); diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index f2d5342a5f..e08035b0eb 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -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. diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 166b04adf0..6254e9fbd8 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -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 diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 653140a7ae..e35840915f 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -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 { diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 7deadb8eb5..d9bc0ccc92 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -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 diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index d5843caa96..0f016d2f29 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -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 diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b3d38cde69..54bf290e6b 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -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 { diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 7239971c21..8f57e61c76 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -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. diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index e76db82c61..3cc520dc78 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -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`. diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index c41c5d4b07..ed51eedf1b 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -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) diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua index 8a3e70990a..9ce9f3d7a6 100644 --- a/src/nvim/generators/c_grammar.lua +++ b/src/nvim/generators/c_grammar.lua @@ -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 } diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index c3fc5aa0a3..56331e4162 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -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() diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua index 89f8c654f4..697626b793 100644 --- a/src/nvim/generators/gen_api_ui_events.lua +++ b/src/nvim/generators/gen_api_ui_events.lua @@ -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') diff --git a/src/nvim/generators/luacats_grammar.lua b/src/nvim/generators/luacats_grammar.lua deleted file mode 100644 index dcccd028ce..0000000000 --- a/src/nvim/generators/luacats_grammar.lua +++ /dev/null @@ -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 -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]] diff --git a/test/functional/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua similarity index 96% rename from test/functional/luacats_grammar_spec.lua rename to test/functional/script/luacats_grammar_spec.lua index 5671848709..931fe42dd0 100644 --- a/test/functional/luacats_grammar_spec.lua +++ b/test/functional/script/luacats_grammar_spec.lua @@ -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', }) diff --git a/test/functional/script/text_utils_spec.lua b/test/functional/script/text_utils_spec.lua new file mode 100644 index 0000000000..c429d306d5 --- /dev/null +++ b/test/functional/script/text_utils_spec.lua @@ -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)