Merge #20352 feat(gen_help_html.lua): adapt to new parser

This commit is contained in:
Justin M. Keyes 2022-09-28 12:55:52 -04:00 committed by GitHub
commit 268bad4798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 609 additions and 421 deletions

View File

@ -210,8 +210,8 @@ set(TREESITTER_LUA_SHA256 564594fe0ffd2f2fb3578a15019b723e1bc94ac82cb6a0103a6b3b
set(TREESITTER_VIM_URL https://github.com/vigoux/tree-sitter-viml/archive/v0.2.0.tar.gz) set(TREESITTER_VIM_URL https://github.com/vigoux/tree-sitter-viml/archive/v0.2.0.tar.gz)
set(TREESITTER_VIM_SHA256 608dcc31a7948cb66ae7f45494620e2e9face1af75598205541f80d782ec4501) set(TREESITTER_VIM_SHA256 608dcc31a7948cb66ae7f45494620e2e9face1af75598205541f80d782ec4501)
set(TREESITTER_HELP_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v1.0.0.tar.gz) set(TREESITTER_HELP_URL https://github.com/neovim/tree-sitter-vimdoc/archive/2ba61cf9e7236d0ae3ce5c526bbd689ace3ff3bd.tar.gz)
set(TREESITTER_HELP_SHA256 bb026d479b0a8ac4d05b6c0cc11f698f2476828e7df9ff34c11dc5178a361e5a) set(TREESITTER_HELP_SHA256 ce89e486c2cc52c0d82edf0600d0f67af9ae9e4b438673224633d0c9f47c62be)
set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.7.tar.gz) set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.7.tar.gz)
set(TREESITTER_SHA256 b355e968ec2d0241bbd96748e00a9038f83968f85d822ecb9940cbe4c42e182e) set(TREESITTER_SHA256 b355e968ec2d0241bbd96748e00a9038f83968f85d822ecb9940cbe4c42e182e)

View File

@ -83,6 +83,7 @@ and |rpcnotify()|:
let nvim = jobstart(['nvim', '--embed'], {'rpc': v:true}) let nvim = jobstart(['nvim', '--embed'], {'rpc': v:true})
echo rpcrequest(nvim, 'nvim_eval', '"Hello " . "world!"') echo rpcrequest(nvim, 'nvim_eval', '"Hello " . "world!"')
call jobstop(nvim) call jobstop(nvim)
<
============================================================================== ==============================================================================
API Definitions *api-definitions* API Definitions *api-definitions*
@ -92,7 +93,7 @@ The Nvim C API defines custom types for all function parameters. Some are just
typedefs around C99 standard types, others are Nvim-defined data structures. typedefs around C99 standard types, others are Nvim-defined data structures.
Basic types ~ Basic types ~
>
API Type C type API Type C type
------------------------------------------------------------------------ ------------------------------------------------------------------------
Nil Nil
@ -103,7 +104,7 @@ Basic types ~
Array Array
Dictionary (msgpack: map) Dictionary (msgpack: map)
Object Object
<
Note: empty Array is accepted as a valid argument for Dictionary parameter. Note: empty Array is accepted as a valid argument for Dictionary parameter.
Special types (msgpack EXT) ~ Special types (msgpack EXT) ~
@ -115,13 +116,13 @@ Special types (msgpack EXT) ~
The EXT object data is the (integer) object handle. The EXT type codes given The EXT object data is the (integer) object handle. The EXT type codes given
in the |api-metadata| `types` key are stable: they will not change and are in the |api-metadata| `types` key are stable: they will not change and are
thus forward-compatible. thus forward-compatible.
>
EXT Type C type Data EXT Type C type Data
------------------------------------------------------------------------ ------------------------------------------------------------------------
Buffer enum value kObjectTypeBuffer |bufnr()| Buffer enum value kObjectTypeBuffer |bufnr()|
Window enum value kObjectTypeWindow |window-ID| Window enum value kObjectTypeWindow |window-ID|
Tabpage enum value kObjectTypeTabpage internal handle Tabpage enum value kObjectTypeTabpage internal handle
<
*api-indexing* *api-indexing*
Most of the API uses 0-based indices, and ranges are end-exclusive. For the Most of the API uses 0-based indices, and ranges are end-exclusive. For the
@ -130,19 +131,19 @@ end of a range, -1 denotes the last line/column.
Exception: the following API functions use "mark-like" indexing (1-based Exception: the following API functions use "mark-like" indexing (1-based
lines, 0-based columns): lines, 0-based columns):
|nvim_get_mark()| - |nvim_get_mark()|
|nvim_buf_get_mark()| - |nvim_buf_get_mark()|
|nvim_buf_set_mark()| - |nvim_buf_set_mark()|
|nvim_win_get_cursor()| - |nvim_win_get_cursor()|
|nvim_win_set_cursor()| - |nvim_win_set_cursor()|
Exception: the following API functions use |extmarks| indexing (0-based Exception: the following API functions use |extmarks| indexing (0-based
indices, end-inclusive): indices, end-inclusive):
|nvim_buf_del_extmark()| - |nvim_buf_del_extmark()|
|nvim_buf_get_extmark_by_id()| - |nvim_buf_get_extmark_by_id()|
|nvim_buf_get_extmarks()| - |nvim_buf_get_extmarks()|
|nvim_buf_set_extmark()| - |nvim_buf_set_extmark()|
*api-fast* *api-fast*
Most API functions are "deferred": they are queued on the main loop and Most API functions are "deferred": they are queued on the main loop and
@ -162,19 +163,19 @@ and return values.
Nvim exposes its API metadata as a Dictionary with these items: Nvim exposes its API metadata as a Dictionary with these items:
version Nvim version, API level/compatibility - version Nvim version, API level/compatibility
version.api_level API version integer *api-level* - version.api_level API version integer *api-level*
version.api_compatible API is backwards-compatible with this level - version.api_compatible API is backwards-compatible with this level
version.api_prerelease Declares the API as unstable/unreleased > - version.api_prerelease Declares the API as unstable/unreleased
(version.api_prerelease && fn.since == version.api_level) `(version.api_prerelease && fn.since == version.api_level)`
functions API function signatures, containing |api-types| info - functions API function signatures, containing |api-types| info
describing the return value and parameters. describing the return value and parameters.
ui_events |UI| event signatures - ui_events |UI| event signatures
ui_options Supported |ui-option|s - ui_options Supported |ui-option|s
{fn}.since API level where function {fn} was introduced - {fn}.since API level where function {fn} was introduced
{fn}.deprecated_since API level where function {fn} was deprecated - {fn}.deprecated_since API level where function {fn} was deprecated
types Custom handle types defined by Nvim - types Custom handle types defined by Nvim
error_types Possible error types returned by API functions - error_types Possible error types returned by API functions
About the `functions` map: About the `functions` map:

View File

@ -151,6 +151,23 @@ DOCUMENTATION *dev-doc*
/// @param dirname The path fragment before `pend` /// @param dirname The path fragment before `pend`
< <
Documentation format ~
For Nvim-owned docs, use the following strict subset of "vimdoc" to ensure
the help doc renders nicely in other formats (such as HTML:
https://neovim.io/doc/user ).
Strict "vimdoc" subset:
- Use lists (like this!) prefixed with "-", "*", or "•", for adjacent lines
that you don't want auto-wrapped. Lists are always rendered with "flow"
(soft-wrapped) layout instead of preformatted (hard-wrapped) layout common
in legacy :help docs.
- Separate blocks (paragraphs) of content by a blank line(s).
- Do not use indentation in random places—that prevents the page from using
"flow" layout. If you need a preformatted section, put it in
a |help-codeblock| starting with ">".
C docstrings ~ C docstrings ~
Nvim API documentation lives in the source code, as docstrings (Doxygen Nvim API documentation lives in the source code, as docstrings (Doxygen

View File

@ -4119,7 +4119,7 @@ This example sorts lines with a specific compare function. >
As a one-liner: > As a one-liner: >
:call setline(1, sort(getline(1, '$'), function("Strcmp"))) :call setline(1, sort(getline(1, '$'), function("Strcmp")))
<
scanf() replacement ~ scanf() replacement ~
*sscanf* *sscanf*

View File

@ -178,7 +178,7 @@ If a file type that you want to use is not detected yet, there are a few ways
to add it. In any way, it's better not to modify the $VIMRUNTIME/filetype.lua to add it. In any way, it's better not to modify the $VIMRUNTIME/filetype.lua
or $VIMRUNTIME/filetype.vim files. They will be overwritten when installing a or $VIMRUNTIME/filetype.vim files. They will be overwritten when installing a
new version of Nvim. The following explains the legacy Vim mechanism (enabled new version of Nvim. The following explains the legacy Vim mechanism (enabled
if |do_legacy_filetype| is set). For Nvim's default mechanism, see if |g:do_legacy_filetype| is set). For Nvim's default mechanism, see
|vim.filetype.add()|. |vim.filetype.add()|.
A. If you want to overrule all default file type checks. A. If you want to overrule all default file type checks.

View File

@ -212,12 +212,6 @@ This is done when viewing the file in Vim, the file itself is not changed. It
is done by going through all help files and obtaining the first line of each is done by going through all help files and obtaining the first line of each
file. The files in $VIMRUNTIME/doc are skipped. file. The files in $VIMRUNTIME/doc are skipped.
*help-xterm-window*
If you want to have the help in another xterm window, you could use this
command: >
:!xterm -e vim +help &
<
*:helpt* *:helptags* *:helpt* *:helptags*
*E150* *E151* *E152* *E153* *E154* *E670* *E856* *E150* *E151* *E152* *E153* *E154* *E670* *E856*
:helpt[ags] [++t] {dir} :helpt[ags] [++t] {dir}
@ -372,6 +366,7 @@ To separate sections in a help file, place a series of '=' characters in a
line starting from the first column. The section separator line is highlighted line starting from the first column. The section separator line is highlighted
differently. differently.
*help-codeblock*
To quote a block of ex-commands verbatim, place a greater than (>) character To quote a block of ex-commands verbatim, place a greater than (>) character
at the end of the line before the block and a less than (<) character as the at the end of the line before the block and a less than (<) character as the
first non-blank on a line following the block. Any line starting in column 1 first non-blank on a line following the block. Any line starting in column 1

View File

@ -55,7 +55,6 @@ Lua means "moon" in Portuguese and is pronounced LOO-ah.
============================================================================== ==============================================================================
2 THE LANGUAGE *luaref-language* 2 THE LANGUAGE *luaref-language*
==============================================================================
This section describes the lexis, the syntax, and the semantics of Lua. In This section describes the lexis, the syntax, and the semantics of Lua. In
other words, this section describes which tokens are valid, how they can be other words, this section describes which tokens are valid, how they can be
@ -450,21 +449,22 @@ through an arithmetic progression. It has the following syntax:
< <
The `block` is repeated for `name` starting at the value of the first `exp`, until The `block` is repeated for `name` starting at the value of the first `exp`, until
it passes the second `exp` by steps of the third `exp`. More precisely, it passes the second `exp` by steps of the third `exp`. More precisely,
a `for` statement like a `for` statement like >
`for var =` `e1, e2, e3` `do` `block` `end` for var = e1, e2, e3 do block end
is equivalent to the code: < is equivalent to the code: >
`do` do
`local` `var, limit, step` `= tonumber(e1), tonumber(e2), tonumber(e3)` local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
`if not (` `var` `and` `limit` `and` `step` `) then error() end` if not ( var and limit and step ) then error() end
`while (` `step` `>0 and` `var` `<=` `limit` `)` while ( step >0 and var <= limit )
`or (` `step` `<=0 and` `var` `>=` `limit` `) do` or ( step <=0 and var >= limit ) do
`block` block
`var` `=` `var` `+` `step` var = var + step
`end` end
`end` end
<
Note the following: Note the following:
@ -490,18 +490,18 @@ A `for` statement like
`for` `var1, ..., varn` `in` `explist` `do` `block` `end` `for` `var1, ..., varn` `in` `explist` `do` `block` `end`
is equivalent to the code: is equivalent to the code: >
`do`
`local` `f, s, var` `=` `explist`
`while true do`
`local` `var1, ..., varn` `=` `f(s, var)`
`var` `=` `var1`
`if` `var` `== nil then break end`
`block`
`end`
`end`
do
local f, s, var = explist
while true do
local var1, ..., varn = f(s, var)
var = var1
if var == nil then break end
block
end
end
<
Note the following: Note the following:
- `explist` is evaluated only once. Its results are an iterator function, - `explist` is evaluated only once. Its results are an iterator function,
@ -1871,25 +1871,25 @@ lua_gc *lua_gc()*
This function performs several tasks, according to the value of the This function performs several tasks, according to the value of the
parameter `what`: parameter `what`:
`LUA_GCSTOP` stops the garbage collector. - `LUA_GCSTOP` stops the garbage collector.
`LUA_GCRESTART` restarts the garbage collector. - `LUA_GCRESTART` restarts the garbage collector.
`LUA_GCCOLLECT` performs a full garbage-collection cycle. - `LUA_GCCOLLECT` performs a full garbage-collection cycle.
`LUA_GCCOUNT` returns the current amount of memory (in Kbytes) in - `LUA_GCCOUNT` returns the current amount of memory (in Kbytes) in
use by Lua. use by Lua.
`LUA_GCCOUNTB` returns the remainder of dividing the current - `LUA_GCCOUNTB` returns the remainder of dividing the current
amount of bytes of memory in use by Lua by 1024. amount of bytes of memory in use by Lua by 1024.
`LUA_GCSTEP` performs an incremental step of garbage collection. - `LUA_GCSTEP` performs an incremental step of garbage collection.
The step "size" is controlled by `data` (larger The step "size" is controlled by `data` (larger
values mean more steps) in a non-specified way. If values mean more steps) in a non-specified way. If
you want to control the step size you must you want to control the step size you must
experimentally tune the value of `data`. The experimentally tune the value of `data`. The
function returns 1 if the step finished a function returns 1 if the step finished a
garbage-collection cycle. garbage-collection cycle.
`LUA_GCSETPAUSE` sets `data` /100 as the new value for the - `LUA_GCSETPAUSE` sets `data` /100 as the new value for the
`pause` of the collector (see |luaref-langGC|). `pause` of the collector (see |luaref-langGC|).
The function returns the previous value of the The function returns the previous value of the
pause. pause.
`LUA_GCSETSTEPMUL` sets `data` /100 as the new value for the - `LUA_GCSETSTEPMUL`sets `data` /100 as the new value for the
`step` `multiplier` of the collector (see `step` `multiplier` of the collector (see
|luaref-langGC|). The function returns the |luaref-langGC|). The function returns the
previous value of the step multiplier. previous value of the step multiplier.
@ -2717,20 +2717,22 @@ need "inside information" from the interpreter.
lua_Debug *lua_Debug()* lua_Debug *lua_Debug()*
`typedef struct lua_Debug {` >
`int event;` typedef struct lua_Debug {
`const char *name; /* (n) */` int event;
`const char *namewhat; /* (n) */` const char *name; /* (n) */
`const char *what; /* (S) */` const char *namewhat; /* (n) */
`const char *source; /* (S) */` const char *what; /* (S) */
`int currentline; /* (l) */` const char *source; /* (S) */
`int nups; /* (u) number of upvalues */` int currentline; /* (l) */
`int linedefined; /* (S) */` int nups; /* (u) number of upvalues */
`int lastlinedefined; /* (S) */` int linedefined; /* (S) */
`char short_src[LUA_IDSIZE]; /* (S) */` int lastlinedefined; /* (S) */
`/* private part */` char short_src[LUA_IDSIZE]; /* (S) */
`other fields` /* private part */
`} lua_Debug;` other fields
} lua_Debug;
<
A structure used to carry different pieces of information about an active A structure used to carry different pieces of information about an active
function. `lua_getstack` (see |lua_getstack()|) fills only the private part function. `lua_getstack` (see |lua_getstack()|) fills only the private part
@ -2739,28 +2741,28 @@ useful information, call `lua_getinfo` (see |lua_getinfo()|).
The fields of `lua_Debug` have the following meaning: The fields of `lua_Debug` have the following meaning:
`source` If the function was defined in a string, then `source` is - `source` If the function was defined in a string, then `source` is
that string. If the function was defined in a file, then that string. If the function was defined in a file, then
`source` starts with a `@` followed by the file name. `source` starts with a `@` followed by the file name.
`short_src` a "printable" version of `source`, to be used in error messages. - `short_src` a "printable" version of `source`, to be used in error messages.
`linedefined` the line number where the definition of the function starts. - `linedefined` the line number where the definition of the function starts.
`lastlinedefined` the line number where the definition of the function ends. - `lastlinedefined` the line number where the definition of the function ends.
`what` the string `"Lua"` if the function is a Lua function, - `what` the string `"Lua"` if the function is a Lua function,
`"C"` if it is a C function, `"main"` if it is the main `"C"` if it is a C function, `"main"` if it is the main
part of a chunk, and `"tail"` if it was a function that part of a chunk, and `"tail"` if it was a function that
did a tail call. In the latter case, Lua has no other did a tail call. In the latter case, Lua has no other
information about the function. information about the function.
`currentline` the current line where the given function is executing. - `currentline` the current line where the given function is executing.
When no line information is available, `currentline` is When no line information is available, `currentline` is
set to -1. set to -1.
`name` a reasonable name for the given function. Because - `name` a reasonable name for the given function. Because
functions in Lua are first-class values, they do not have functions in Lua are first-class values, they do not have
a fixed name: some functions may be the value of multiple a fixed name: some functions may be the value of multiple
global variables, while others may be stored only in a global variables, while others may be stored only in a
table field. The `lua_getinfo` function checks how the table field. The `lua_getinfo` function checks how the
function was called to find a suitable name. If it cannot function was called to find a suitable name. If it cannot
find a name, then `name` is set to `NULL`. find a name, then `name` is set to `NULL`.
`namewhat` explains the `name` field. The value of `namewhat` can be - `namewhat` explains the `name` field. The value of `namewhat` can be
`"global"`, `"local"`, `"method"`, `"field"`, `"global"`, `"local"`, `"method"`, `"field"`,
`"upvalue"`, or `""` (the empty string), according to how `"upvalue"`, or `""` (the empty string), according to how
the function was called. (Lua uses the empty string when the function was called. (Lua uses the empty string when

View File

@ -3,7 +3,8 @@
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
Quick reference guide ==============================================================================
Quick reference guide
*quickref* *Contents* *quickref* *Contents*
tag subject tag subject ~ tag subject tag subject ~
@ -29,11 +30,11 @@
|Q_to| Text objects |Q_gu| GUI commands |Q_to| Text objects |Q_gu| GUI commands
|Q_fo| Folding |Q_fo| Folding
------------------------------------------------------------------------------
N is used to indicate an optional count that can be given before the command.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_lr* Left-right motions *Q_lr* Left-right motions
N is used to indicate an optional count that can be given before the command.
|h| N h left (also: CTRL-H, <BS>, or <Left> key) |h| N h left (also: CTRL-H, <BS>, or <Left> key)
|l| N l right (also: <Space> or <Right> key) |l| N l right (also: <Space> or <Right> key)
|0| 0 to first character in the line (also: <Home> key) |0| 0 to first character in the line (also: <Home> key)
@ -56,6 +57,7 @@ N is used to indicate an optional count that can be given before the command.
|;| N ; repeat the last "f", "F", "t", or "T" N times |;| N ; repeat the last "f", "F", "t", or "T" N times
|,| N , repeat the last "f", "F", "t", or "T" N times in |,| N , repeat the last "f", "F", "t", or "T" N times in
opposite direction opposite direction
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ud* Up-down motions *Q_ud* Up-down motions
@ -73,6 +75,7 @@ N is used to indicate an optional count that can be given before the command.
given, otherwise it is the |%| command given, otherwise it is the |%| command
|gk| N gk up N screen lines (differs from "k" when line wraps) |gk| N gk up N screen lines (differs from "k" when line wraps)
|gj| N gj down N screen lines (differs from "j" when line wraps) |gj| N gj down N screen lines (differs from "j" when line wraps)
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_tm* Text object motions *Q_tm* Text object motions
@ -105,6 +108,7 @@ N is used to indicate an optional count that can be given before the command.
|]#| N ]# N times forward to unclosed "#else" or "#endif" |]#| N ]# N times forward to unclosed "#else" or "#endif"
|[star| N [* N times back to start of comment "/*" |[star| N [* N times back to start of comment "/*"
|]star| N ]* N times forward to end of comment "*/" |]star| N ]* N times forward to end of comment "*/"
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_pa* Pattern searches *Q_pa* Pattern searches
@ -168,6 +172,7 @@ N is used to indicate an optional count that can be given before the command.
b[+num] [num] identical to s[+num] above (mnemonic: begin) b[+num] [num] identical to s[+num] above (mnemonic: begin)
b[-num] [num] identical to s[-num] above (mnemonic: begin) b[-num] [num] identical to s[-num] above (mnemonic: begin)
;{search-command} execute {search-command} next ;{search-command} execute {search-command} next
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ma* Marks and motions *Q_ma* Marks and motions
@ -188,6 +193,7 @@ N is used to indicate an optional count that can be given before the command.
|CTRL-O| N CTRL-O go to Nth older position in jump list |CTRL-O| N CTRL-O go to Nth older position in jump list
|CTRL-I| N CTRL-I go to Nth newer position in jump list |CTRL-I| N CTRL-I go to Nth newer position in jump list
|:ju| :ju[mps] print the jump list |:ju| :ju[mps] print the jump list
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_vm* Various motions *Q_vm* Various motions
@ -202,6 +208,7 @@ N is used to indicate an optional count that can be given before the command.
|go| N go go to Nth byte in the buffer |go| N go go to Nth byte in the buffer
|:go| :[range]go[to] [off] go to [off] byte in the buffer |:go| :[range]go[to] [off] go to [off] byte in the buffer
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ta* Using tags *Q_ta* Using tags
@ -229,6 +236,7 @@ N is used to indicate an optional count that can be given before the command.
|:ptjump| :ptj[ump] like ":tjump" but show tag in preview window |:ptjump| :ptj[ump] like ":tjump" but show tag in preview window
|:pclose| :pc[lose] close tag preview window |:pclose| :pc[lose] close tag preview window
|CTRL-W_z| CTRL-W z close tag preview window |CTRL-W_z| CTRL-W z close tag preview window
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_sc* Scrolling *Q_sc* Scrolling
@ -247,6 +255,7 @@ These only work when 'wrap' is off:
|zl| N zl scroll screen N characters to the left |zl| N zl scroll screen N characters to the left
|zH| N zH scroll screen half a screenwidth to the right |zH| N zH scroll screen half a screenwidth to the right
|zL| N zL scroll screen half a screenwidth to the left |zL| N zL scroll screen half a screenwidth to the left
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_in* Inserting text *Q_in* Inserting text
@ -263,6 +272,7 @@ These only work when 'wrap' is off:
in Visual block mode: in Visual block mode:
|v_b_I| I insert the same text in front of all the selected lines |v_b_I| I insert the same text in front of all the selected lines
|v_b_A| A append the same text after all the selected lines |v_b_A| A append the same text after all the selected lines
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ai* Insert mode keys *Q_ai* Insert mode keys
@ -279,6 +289,7 @@ moving around:
|i_<S-Up>| shift-up/down one screenful backward/forward |i_<S-Up>| shift-up/down one screenful backward/forward
|i_<End>| <End> cursor after last character in the line |i_<End>| <End> cursor after last character in the line
|i_<Home>| <Home> cursor to first character in the line |i_<Home>| <Home> cursor to first character in the line
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ss* Special keys in Insert mode *Q_ss* Special keys in Insert mode
@ -313,6 +324,7 @@ moving around:
|i_0_CTRL-D| 0 CTRL-D delete all indent in the current line |i_0_CTRL-D| 0 CTRL-D delete all indent in the current line
|i_^_CTRL-D| ^ CTRL-D delete all indent in the current line, |i_^_CTRL-D| ^ CTRL-D delete all indent in the current line,
restore indent in next line restore indent in next line
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_di* Digraphs *Q_di* Digraphs
@ -325,12 +337,14 @@ In Insert or Command-line mode:
enter digraph enter digraph
|i_digraph| {char1} <BS> {char2} |i_digraph| {char1} <BS> {char2}
enter digraph if 'digraph' option set enter digraph if 'digraph' option set
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_si* Special inserts *Q_si* Special inserts
|:r| :r [file] insert the contents of [file] below the cursor |:r| :r [file] insert the contents of [file] below the cursor
|:r!| :r! {command} insert the standard output of {command} below the |:r!| :r! {command} insert the standard output of {command} below the
cursor cursor
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_de* Deleting text *Q_de* Deleting text
@ -346,6 +360,7 @@ In Insert or Command-line mode:
|gJ| N gJ like "J", but without inserting spaces |gJ| N gJ like "J", but without inserting spaces
|v_gJ| {visual}gJ like "{visual}J", but without inserting spaces |v_gJ| {visual}gJ like "{visual}J", but without inserting spaces
|:d| :[range]d [x] delete [range] lines [into register x] |:d| :[range]d [x] delete [range] lines [into register x]
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_cm* Copying and moving text *Q_cm* Copying and moving text
@ -363,6 +378,7 @@ In Insert or Command-line mode:
|[p| N [p like P, but adjust indent to current line |[p| N [p like P, but adjust indent to current line
|gp| N gp like p, but leave cursor after the new text |gp| N gp like p, but leave cursor after the new text
|gP| N gP like P, but leave cursor after the new text |gP| N gP like P, but leave cursor after the new text
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ch* Changing text *Q_ch* Changing text
@ -418,6 +434,7 @@ In Insert or Command-line mode:
left-align the lines in [range] (with [indent]) left-align the lines in [range] (with [indent])
|:ri| :[range]ri[ght] [width] |:ri| :[range]ri[ght] [width]
right-align the lines in [range] right-align the lines in [range]
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_co* Complex changes *Q_co* Complex changes
@ -444,6 +461,7 @@ In Insert or Command-line mode:
|:ret| :[range]ret[ab][!] [tabstop] |:ret| :[range]ret[ab][!] [tabstop]
set 'tabstop' to new value and adjust white space set 'tabstop' to new value and adjust white space
accordingly accordingly
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_vi* Visual mode *Q_vi* Visual mode
@ -457,6 +475,7 @@ In Insert or Command-line mode:
|v_v| v highlight characters or stop highlighting |v_v| v highlight characters or stop highlighting
|v_V| V highlight linewise or stop highlighting |v_V| V highlight linewise or stop highlighting
|v_CTRL-V| CTRL-V highlight blockwise or stop highlighting |v_CTRL-V| CTRL-V highlight blockwise or stop highlighting
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_to* Text objects (only in Visual mode or after an operator) *Q_to* Text objects (only in Visual mode or after an operator)
@ -509,6 +528,7 @@ In Insert or Command-line mode:
|:sl| :sl[eep] [sec] |:sl| :sl[eep] [sec]
don't do anything for [sec] seconds don't do anything for [sec] seconds
|gs| N gs goto Sleep for N seconds |gs| N gs goto Sleep for N seconds
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_km* Key mapping *Q_km* Key mapping
@ -556,6 +576,7 @@ In Insert or Command-line mode:
like ":mkvimrc", but store current files, like ":mkvimrc", but store current files,
windows, etc. too, to be able to continue windows, etc. too, to be able to continue
this session later this session later
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ab* Abbreviations *Q_ab* Abbreviations
@ -570,6 +591,7 @@ In Insert or Command-line mode:
|:abclear| :abc[lear] remove all abbreviations |:abclear| :abc[lear] remove all abbreviations
|:cabclear| :cabc[lear] remove all abbr's for Cmdline mode |:cabclear| :cabc[lear] remove all abbr's for Cmdline mode
|:iabclear| :iabc[lear] remove all abbr's for Insert mode |:iabclear| :iabc[lear] remove all abbr's for Insert mode
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_op* Options *Q_op* Options
@ -940,18 +962,21 @@ Short explanation of each option: *option-list*
'writeany' 'wa' write to file with no need for "!" override 'writeany' 'wa' write to file with no need for "!" override
'writebackup' 'wb' make a backup before overwriting a file 'writebackup' 'wb' make a backup before overwriting a file
'writedelay' 'wd' delay this many msec for each char (for debug) 'writedelay' 'wd' delay this many msec for each char (for debug)
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ur* Undo/Redo commands *Q_ur* Undo/Redo commands
|u| N u undo last N changes |u| N u undo last N changes
|CTRL-R| N CTRL-R redo last N undone changes |CTRL-R| N CTRL-R redo last N undone changes
|U| U restore last changed line |U| U restore last changed line
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_et* External commands *Q_et* External commands
|:!| :!{command} execute {command} with a shell |:!| :!{command} execute {command} with a shell
|K| K lookup keyword under the cursor with |K| K lookup keyword under the cursor with
'keywordprg' program (default: "man") 'keywordprg' program (default: "man")
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_qf* Quickfix commands *Q_qf* Quickfix commands
@ -975,6 +1000,7 @@ Short explanation of each option: *option-list*
error error
|:grep| :gr[ep] [args] execute 'grepprg' to find matches and jump to |:grep| :gr[ep] [args] execute 'grepprg' to find matches and jump to
the first one the first one
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_vc* Various commands *Q_vc* Various commands
@ -1000,6 +1026,7 @@ Short explanation of each option: *option-list*
unsaved changes or read-only files unsaved changes or read-only files
|:browse| :browse {command} open/read/write file, using a |:browse| :browse {command} open/read/write file, using a
file selection dialog file selection dialog
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ce* Command-line editing *Q_ce* Command-line editing
@ -1046,6 +1073,7 @@ Context-sensitive completion on the command-line:
to next match to next match
|c_CTRL-P| CTRL-P after 'wildchar' with multiple matches: go |c_CTRL-P| CTRL-P after 'wildchar' with multiple matches: go
to previous match to previous match
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ra* Ex ranges *Q_ra* Ex ranges
@ -1066,6 +1094,7 @@ Context-sensitive completion on the command-line:
(default: 1) (default: 1)
|:range| -[num] subtract [num] from the preceding line |:range| -[num] subtract [num] from the preceding line
number (default: 1) number (default: 1)
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ex* Special Ex characters *Q_ex* Special Ex characters
@ -1098,6 +1127,7 @@ Context-sensitive completion on the command-line:
|::r| :r root (extension removed) |::r| :r root (extension removed)
|::e| :e extension |::e| :e extension
|::s| :s/{pat}/{repl}/ substitute {pat} with {repl} |::s| :s/{pat}/{repl}/ substitute {pat} with {repl}
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_st* Starting Vim *Q_st* Starting Vim
@ -1134,6 +1164,7 @@ Context-sensitive completion on the command-line:
|--help| --help show list of arguments and exit |--help| --help show list of arguments and exit
|--version| --version show version info and exit |--version| --version show version info and exit
|--| - read file from stdin |--| - read file from stdin
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ed* Editing a file *Q_ed* Editing a file
@ -1153,6 +1184,7 @@ Context-sensitive completion on the command-line:
position position
|:file| :f[ile] {name} set the current file name to {name} |:file| :f[ile] {name} set the current file name to {name}
|:files| :files show alternate file names |:files| :files show alternate file names
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_fl* Using the argument list |argument-list| *Q_fl* Using the argument list |argument-list|
@ -1173,6 +1205,7 @@ Context-sensitive completion on the command-line:
|:Next| :N[ext] :sN[ext] edit previous file |:Next| :N[ext] :sN[ext] edit previous file
|:first| :fir[st] :sfir[st] edit first file |:first| :fir[st] :sfir[st] edit first file
|:last| :la[st] :sla[st] edit last file |:last| :la[st] :sla[st] edit last file
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_wq* Writing and quitting *Q_wq* Writing and quitting
@ -1210,6 +1243,7 @@ Context-sensitive completion on the command-line:
|:stop| :st[op][!] suspend Vim or start new shell; if 'aw' option |:stop| :st[op][!] suspend Vim or start new shell; if 'aw' option
is set and [!] not given write the buffer is set and [!] not given write the buffer
|CTRL-Z| CTRL-Z same as ":stop" |CTRL-Z| CTRL-Z same as ":stop"
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_ac* Automatic Commands *Q_ac* Automatic Commands
@ -1241,6 +1275,7 @@ Context-sensitive completion on the command-line:
with {pat} with {pat}
|:autocmd| :au! {event} {pat} {cmd} remove all autocommands for {event} |:autocmd| :au! {event} {pat} {cmd} remove all autocommands for {event}
with {pat} and enter new one with {pat} and enter new one
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_wi* Multi-window commands *Q_wi* Multi-window commands
@ -1286,6 +1321,7 @@ Context-sensitive completion on the command-line:
|CTRL-W_>| CTRL-W > increase current window width |CTRL-W_>| CTRL-W > increase current window width
|CTRL-W_bar| CTRL-W | set current window width (default: |CTRL-W_bar| CTRL-W | set current window width (default:
widest possible) widest possible)
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_bu* Buffer list commands *Q_bu* Buffer list commands
@ -1307,6 +1343,7 @@ Context-sensitive completion on the command-line:
|:bfirst| :bfirst :sbfirst to first arg/buf |:bfirst| :bfirst :sbfirst to first arg/buf
|:blast| :blast :sblast to last arg/buf |:blast| :blast :sblast to last arg/buf
|:bmodified| :[N]bmod [N] :[N]sbmod [N] to Nth modified buf |:bmodified| :[N]bmod [N] :[N]sbmod [N] to Nth modified buf
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_sy* Syntax Highlighting *Q_sy* Syntax Highlighting
@ -1333,6 +1370,7 @@ Context-sensitive completion on the command-line:
|:filetype| :filetype plugin indent on |:filetype| :filetype plugin indent on
switch on file type detection, with switch on file type detection, with
automatic indenting and settings automatic indenting and settings
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_gu* GUI commands *Q_gu* GUI commands
@ -1345,6 +1383,7 @@ Context-sensitive completion on the command-line:
add toolbar item, giving {rhs} add toolbar item, giving {rhs}
|:tmenu| :tmenu {mpath} {text} add tooltip to menu {mpath} |:tmenu| :tmenu {mpath} {text} add tooltip to menu {mpath}
|:unmenu| :unmenu {mpath} remove menu {mpath} |:unmenu| :unmenu {mpath} remove menu {mpath}
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*Q_fo* Folding *Q_fo* Folding

View File

@ -23,41 +23,38 @@ screen grid with a size of width × height cells. This is typically done by an
embedder at startup (see |ui-startup|), but UIs can also connect to a running embedder at startup (see |ui-startup|), but UIs can also connect to a running
Nvim instance and invoke nvim_ui_attach(). The `options` parameter is a map Nvim instance and invoke nvim_ui_attach(). The `options` parameter is a map
with these (optional) keys: with these (optional) keys:
*ui-rgb* *ui-rgb*
`rgb` Decides the color format. - `rgb` Decides the color format.
true: (default) 24-bit RGB colors - true: (default) 24-bit RGB colors
false: Terminal colors (8-bit, max 256) - false: Terminal colors (8-bit, max 256)
*ui-override* *ui-override*
`override` Decides how UI capabilities are resolved. - `override` Decides how UI capabilities are resolved.
true: Enable requested UI capabilities, even - true: Enable requested UI capabilities, even if not
if not supported by all connected UIs supported by all connected UIs (including |TUI|).
(including |TUI|). - false: (default) Disable UI capabilities not
false: (default) Disable UI capabilities not supported by all connected UIs (including TUI).
supported by all connected UIs
(including TUI).
*ui-ext-options* *ui-ext-options*
`ext_cmdline` Externalize the cmdline. |ui-cmdline| - `ext_cmdline` Externalize the cmdline. |ui-cmdline|
`ext_hlstate` Detailed highlight state. |ui-hlstate| - `ext_hlstate` Detailed highlight state. |ui-hlstate|
Sets `ext_linegrid` implicitly. Sets `ext_linegrid` implicitly.
`ext_linegrid` Line-based grid events. |ui-linegrid| - `ext_linegrid` Line-based grid events. |ui-linegrid|
Deactivates |ui-grid-old| implicitly. Deactivates |ui-grid-old| implicitly.
`ext_messages` Externalize messages. |ui-messages| - `ext_messages` Externalize messages. |ui-messages|
Sets `ext_linegrid` and `ext_cmdline` implicitly. Sets `ext_linegrid` and `ext_cmdline` implicitly.
`ext_multigrid` Per-window grid events. |ui-multigrid| - `ext_multigrid` Per-window grid events. |ui-multigrid|
Sets `ext_linegrid` implicitly. Sets `ext_linegrid` implicitly.
`ext_popupmenu` Externalize |popupmenu-completion| and - `ext_popupmenu` Externalize |popupmenu-completion| and
'wildmenu'. |ui-popupmenu| 'wildmenu'. |ui-popupmenu|
`ext_tabline` Externalize the tabline. |ui-tabline| - `ext_tabline` Externalize the tabline. |ui-tabline|
`ext_termcolors` Use external default colors. - `ext_termcolors` Use external default colors.
`term_name` Sets the name of the terminal 'term'. - `term_name` Sets the name of the terminal 'term'.
`term_colors` Sets the number of supported colors 't_Co'. - `term_colors` Sets the number of supported colors 't_Co'.
`term_background` Sets the default value of 'background'. - `term_background` Sets the default value of 'background'.
`stdin_fd` Read buffer from `fd` as if it was a stdin pipe - `stdin_fd` Read buffer from `fd` as if it was a stdin pipe
This option can only used by |--embed| ui, This option can only used by |--embed| ui,
see |ui-startup-stdin|. see |ui-startup-stdin|.
Specifying an unknown option is an error; UIs can check the |api-metadata| Specifying an unknown option is an error; UIs can check the |api-metadata|
`ui_options` key for supported options. `ui_options` key for supported options.
@ -164,13 +161,13 @@ Global Events *ui-global*
The following UI events are always emitted, and describe global state of The following UI events are always emitted, and describe global state of
the editor. the editor.
["set_title", title] ["set_title", title] ~
["set_icon", icon] ["set_icon", icon] ~
Set the window title, and icon (minimized) window title, respectively. Set the window title, and icon (minimized) window title, respectively.
In windowing systems not distinguishing between the two, "set_icon" In windowing systems not distinguishing between the two, "set_icon"
can be ignored. can be ignored.
["mode_info_set", cursor_style_enabled, mode_info] ["mode_info_set", cursor_style_enabled, mode_info] ~
`cursor_style_enabled` is a boolean indicating if the UI should set `cursor_style_enabled` is a boolean indicating if the UI should set
the cursor style. `mode_info` is a list of mode property maps. The the cursor style. `mode_info` is a list of mode property maps. The
current mode is given by the `mode_idx` field of the `mode_change` current mode is given by the `mode_idx` field of the `mode_change`
@ -197,21 +194,21 @@ the editor.
`hl_id`: Use `attr_id` instead. `hl_id`: Use `attr_id` instead.
`hl_lm`: Use `attr_id_lm` instead. `hl_lm`: Use `attr_id_lm` instead.
["option_set", name, value] ["option_set", name, value] ~
UI-related option changed, where `name` is one of: UI-related option changed, where `name` is one of:
'arabicshape' - 'arabicshape'
'ambiwidth' - 'ambiwidth'
'emoji' - 'emoji'
'guifont' - 'guifont'
'guifontwide' - 'guifontwide'
'linespace' - 'linespace'
'mousefocus' - 'mousefocus'
'mousemoveevent' - 'mousemoveevent'
'pumblend' - 'pumblend'
'showtabline' - 'showtabline'
'termguicolors' - 'termguicolors'
"ext_*" (all |ui-ext-options|) - "ext_*" (all |ui-ext-options|)
Triggered when the UI first connects to Nvim, and whenever an option Triggered when the UI first connects to Nvim, and whenever an option
is changed by the user or a plugin. is changed by the user or a plugin.
@ -224,7 +221,7 @@ the editor.
however a UI might still use such options when rendering raw text however a UI might still use such options when rendering raw text
sent from Nvim, like for |ui-cmdline|. sent from Nvim, like for |ui-cmdline|.
["mode_change", mode, mode_idx] ["mode_change", mode, mode_idx] ~
Editor mode changed. The `mode` parameter is a string representing Editor mode changed. The `mode` parameter is a string representing
the current mode. `mode_idx` is an index into the array emitted in the current mode. `mode_idx` is an index into the array emitted in
the `mode_info_set` event. UIs should change the cursor style the `mode_info_set` event. UIs should change the cursor style
@ -233,30 +230,30 @@ the editor.
instance more submodes and temporary states might be represented as instance more submodes and temporary states might be represented as
separate modes. separate modes.
["mouse_on"] ["mouse_on"] ~
["mouse_off"] ["mouse_off"] ~
'mouse' was enabled/disabled in the current editor mode. Useful for 'mouse' was enabled/disabled in the current editor mode. Useful for
a terminal UI, or embedding into an application where Nvim mouse would a terminal UI, or embedding into an application where Nvim mouse would
conflict with other usages of the mouse. Other UI:s may ignore this event. conflict with other usages of the mouse. Other UI:s may ignore this event.
["busy_start"] ["busy_start"] ~
["busy_stop"] ["busy_stop"] ~
Indicates to the UI that it must stop rendering the cursor. This event Indicates to the UI that it must stop rendering the cursor. This event
is misnamed and does not actually have anything to do with busyness. is misnamed and does not actually have anything to do with busyness.
["suspend"] ["suspend"] ~
|:suspend| command or |CTRL-Z| mapping is used. A terminal client (or |:suspend| command or |CTRL-Z| mapping is used. A terminal client (or
another client where it makes sense) could suspend itself. Other another client where it makes sense) could suspend itself. Other
clients can safely ignore it. clients can safely ignore it.
["update_menu"] ["update_menu"] ~
The menu mappings changed. The menu mappings changed.
["bell"] ["bell"] ~
["visual_bell"] ["visual_bell"] ~
Notify the user with an audible or visual bell, respectively. Notify the user with an audible or visual bell, respectively.
["flush"] ["flush"] ~
Nvim is done redrawing the screen. For an implementation that renders Nvim is done redrawing the screen. For an implementation that renders
to an internal buffer, this is the time to display the redrawn parts to an internal buffer, this is the time to display the redrawn parts
to the user. to the user.
@ -279,11 +276,11 @@ be created; to enable per-window grids, activate |ui-multigrid|.
Highlight attribute groups are predefined. UIs should maintain a table to map Highlight attribute groups are predefined. UIs should maintain a table to map
numerical highlight ids to the actual attributes. numerical highlight ids to the actual attributes.
["grid_resize", grid, width, height] ["grid_resize", grid, width, height] ~
Resize a `grid`. If `grid` wasn't seen by the client before, a new grid is Resize a `grid`. If `grid` wasn't seen by the client before, a new grid is
being created with this size. being created with this size.
["default_colors_set", rgb_fg, rgb_bg, rgb_sp, cterm_fg, cterm_bg] ["default_colors_set", rgb_fg, rgb_bg, rgb_sp, cterm_fg, cterm_bg] ~
The first three arguments set the default foreground, background and The first three arguments set the default foreground, background and
special colors respectively. `cterm_fg` and `cterm_bg` specifies the special colors respectively. `cterm_fg` and `cterm_bg` specifies the
default color codes to use in a 256-color terminal. default color codes to use in a 256-color terminal.
@ -300,7 +297,7 @@ numerical highlight ids to the actual attributes.
screen with changed background color itself. screen with changed background color itself.
*ui-event-hl_attr_define* *ui-event-hl_attr_define*
["hl_attr_define", id, rgb_attr, cterm_attr, info] ["hl_attr_define", id, rgb_attr, cterm_attr, info] ~
Add a highlight with `id` to the highlight table, with the Add a highlight with `id` to the highlight table, with the
attributes specified by the `rgb_attr` and `cterm_attr` dicts, with the attributes specified by the `rgb_attr` and `cterm_attr` dicts, with the
following (all optional) keys. following (all optional) keys.
@ -346,7 +343,7 @@ numerical highlight ids to the actual attributes.
`info` is an empty array by default, and will be used by the `info` is an empty array by default, and will be used by the
|ui-hlstate| extension explained below. |ui-hlstate| extension explained below.
["hl_group_set", name, hl_id] ["hl_group_set", name, hl_id] ~
The bulitin highlight group `name` was set to use the attributes `hl_id` The bulitin highlight group `name` was set to use the attributes `hl_id`
defined by a previous `hl_attr_define` call. This event is not needed defined by a previous `hl_attr_define` call. This event is not needed
to render the grids which use attribute ids directly, but is useful to render the grids which use attribute ids directly, but is useful
@ -355,7 +352,7 @@ numerical highlight ids to the actual attributes.
use the |hl-Pmenu| family of builtin highlights. use the |hl-Pmenu| family of builtin highlights.
*ui-event-grid_line* *ui-event-grid_line*
["grid_line", grid, row, col_start, cells] ["grid_line", grid, row, col_start, cells] ~
Redraw a continuous part of a `row` on a `grid`, starting at the column Redraw a continuous part of a `row` on a `grid`, starting at the column
`col_start`. `cells` is an array of arrays each with 1 to 3 items: `col_start`. `cells` is an array of arrays each with 1 to 3 items:
`[text(, hl_id, repeat)]` . `text` is the UTF-8 text that should be put in `[text(, hl_id, repeat)]` . `text` is the UTF-8 text that should be put in
@ -374,19 +371,19 @@ numerical highlight ids to the actual attributes.
enough to cover the remaining line, will be sent when the rest of the enough to cover the remaining line, will be sent when the rest of the
line should be cleared. line should be cleared.
["grid_clear", grid] ["grid_clear", grid] ~
Clear a `grid`. Clear a `grid`.
["grid_destroy", grid] ["grid_destroy", grid] ~
`grid` will not be used anymore and the UI can free any data associated `grid` will not be used anymore and the UI can free any data associated
with it. with it.
["grid_cursor_goto", grid, row, column] ["grid_cursor_goto", grid, row, column] ~
Makes `grid` the current grid and `row, column` the cursor position on this Makes `grid` the current grid and `row, column` the cursor position on this
grid. This event will be sent at most once in a `redraw` batch and grid. This event will be sent at most once in a `redraw` batch and
indicates the visible cursor position. indicates the visible cursor position.
["grid_scroll", grid, top, bot, left, right, rows, cols] ["grid_scroll", grid, top, bot, left, right, rows, cols] ~
Scroll a region of `grid`. This is semantically unrelated to editor Scroll a region of `grid`. This is semantically unrelated to editor
|scrolling|, rather this is an optimized way to say "copy these screen |scrolling|, rather this is an optimized way to say "copy these screen
cells". cells".
@ -439,30 +436,30 @@ Grid Events (cell-based) *ui-grid-old*
This is the legacy representation of the screen grid, emitted if |ui-linegrid| This is the legacy representation of the screen grid, emitted if |ui-linegrid|
is not active. New UIs should implement |ui-linegrid| instead. is not active. New UIs should implement |ui-linegrid| instead.
["resize", width, height] ["resize", width, height] ~
The grid is resized to `width` and `height` cells. The grid is resized to `width` and `height` cells.
["clear"] ["clear"] ~
Clear the grid. Clear the grid.
["eol_clear"] ["eol_clear"] ~
Clear from the cursor position to the end of the current line. Clear from the cursor position to the end of the current line.
["cursor_goto", row, col] ["cursor_goto", row, col] ~
Move the cursor to position (row, col). Currently, the same cursor is Move the cursor to position (row, col). Currently, the same cursor is
used to define the position for text insertion and the visible cursor. used to define the position for text insertion and the visible cursor.
However, only the last cursor position, after processing the entire However, only the last cursor position, after processing the entire
array in the "redraw" event, is intended to be a visible cursor array in the "redraw" event, is intended to be a visible cursor
position. position.
["update_fg", color] ["update_fg", color] ~
["update_bg", color] ["update_bg", color] ~
["update_sp", color] ["update_sp", color] ~
Set the default foreground, background and special colors Set the default foreground, background and special colors
respectively. respectively.
*ui-event-highlight_set* *ui-event-highlight_set*
["highlight_set", attrs] ["highlight_set", attrs] ~
Set the attributes that the next text put on the grid will have. Set the attributes that the next text put on the grid will have.
`attrs` is a dict with the keys below. Any absent key is reset `attrs` is a dict with the keys below. Any absent key is reset
to its default value. Color defaults are set by the `update_fg` etc to its default value. Color defaults are set by the `update_fg` etc
@ -482,18 +479,18 @@ is not active. New UIs should implement |ui-linegrid| instead.
`underdotted`: underdotted text. The dots have `special` color. `underdotted`: underdotted text. The dots have `special` color.
`underdashed`: underdashed text. The dashes have `special` color. `underdashed`: underdashed text. The dashes have `special` color.
["put", text] ["put", text] ~
The (utf-8 encoded) string `text` is put at the cursor position The (utf-8 encoded) string `text` is put at the cursor position
(and the cursor is advanced), with the highlights as set by the (and the cursor is advanced), with the highlights as set by the
last `highlight_set` update. last `highlight_set` update.
["set_scroll_region", top, bot, left, right] ["set_scroll_region", top, bot, left, right] ~
Define the scroll region used by `scroll` below. Define the scroll region used by `scroll` below.
Note: ranges are end-inclusive, which is inconsistent with API Note: ranges are end-inclusive, which is inconsistent with API
conventions. conventions.
["scroll", count] ["scroll", count] ~
Scroll the text in the scroll region. The diagrams below illustrate Scroll the text in the scroll region. The diagrams below illustrate
what will happen, depending on the scroll direction. "=" is used to what will happen, depending on the scroll direction. "=" is used to
represent the SR(scroll region) boundaries and "-" the moved rectangles. represent the SR(scroll region) boundaries and "-" the moved rectangles.
@ -588,29 +585,29 @@ A window can be hidden and redisplayed without its grid being deallocated.
This can happen multiple times for the same window, for instance when switching This can happen multiple times for the same window, for instance when switching
tabs. tabs.
["win_pos", grid, win, start_row, start_col, width, height] ["win_pos", grid, win, start_row, start_col, width, height] ~
Set the position and size of the grid in Nvim (i.e. the outer grid Set the position and size of the grid in Nvim (i.e. the outer grid
size). If the window was previously hidden, it should now be shown size). If the window was previously hidden, it should now be shown
again. again.
["win_float_pos", grid, win, anchor, anchor_grid, anchor_row, anchor_col, focusable] ["win_float_pos", grid, win, anchor, anchor_grid, anchor_row, anchor_col, focusable] ~
Display or reconfigure floating window `win`. The window should be Display or reconfigure floating window `win`. The window should be
displayed above another grid `anchor_grid` at the specified position displayed above another grid `anchor_grid` at the specified position
`anchor_row` and `anchor_col`. For the meaning of `anchor` and more `anchor_row` and `anchor_col`. For the meaning of `anchor` and more
details of positioning, see |nvim_open_win()|. details of positioning, see |nvim_open_win()|.
["win_external_pos", grid, win] ["win_external_pos", grid, win] ~
Display or reconfigure external window `win`. The window should be Display or reconfigure external window `win`. The window should be
displayed as a separate top-level window in the desktop environment, displayed as a separate top-level window in the desktop environment,
or something similar. or something similar.
["win_hide", grid] ["win_hide", grid] ~
Stop displaying the window. The window can be shown again later. Stop displaying the window. The window can be shown again later.
["win_close", grid] ["win_close", grid] ~
Close the window. Close the window.
["msg_set_pos", grid, row, scrolled, sep_char] ["msg_set_pos", grid, row, scrolled, sep_char] ~
Display messages on `grid`. The grid will be displayed at `row` on the Display messages on `grid`. The grid will be displayed at `row` on the
default grid (grid=1), covering the full column width. `scrolled` default grid (grid=1), covering the full column width. `scrolled`
indicates whether the message area has been scrolled to cover other indicates whether the message area has been scrolled to cover other
@ -621,13 +618,13 @@ tabs.
When |ui-messages| is active, no message grid is used, and this event When |ui-messages| is active, no message grid is used, and this event
will not be sent. will not be sent.
["win_viewport", grid, win, topline, botline, curline, curcol] ["win_viewport", grid, win, topline, botline, curline, curcol] ~
Indicates the range of buffer text displayed in the window, as well Indicates the range of buffer text displayed in the window, as well
as the cursor position in the buffer. All positions are zero-based. as the cursor position in the buffer. All positions are zero-based.
`botline` is set to one more than the line count of the buffer, if `botline` is set to one more than the line count of the buffer, if
there are filler lines past the end. there are filler lines past the end.
["win_extmark", grid, win, ns_id, mark_id, row, col] ["win_extmark", grid, win, ns_id, mark_id, row, col] ~
Updates the position of an extmark which is currently visible in a Updates the position of an extmark which is currently visible in a
window. Only emitted if the mark has the `ui_watched` attribute. window. Only emitted if the mark has the `ui_watched` attribute.
@ -639,7 +636,7 @@ Activated by the `ext_popupmenu` |ui-option|.
This UI extension delegates presentation of the |popupmenu-completion| and This UI extension delegates presentation of the |popupmenu-completion| and
command-line 'wildmenu'. command-line 'wildmenu'.
["popupmenu_show", items, selected, row, col, grid] ["popupmenu_show", items, selected, row, col, grid] ~
Show |popupmenu-completion|. `items` is an array of completion items Show |popupmenu-completion|. `items` is an array of completion items
to show; each item is an array of the form [word, kind, menu, info] as to show; each item is an array of the form [word, kind, menu, info] as
defined at |complete-items|, except that `word` is replaced by `abbr` defined at |complete-items|, except that `word` is replaced by `abbr`
@ -651,12 +648,12 @@ command-line 'wildmenu'.
set to -1 to indicate the popupmenu should be anchored to the external set to -1 to indicate the popupmenu should be anchored to the external
cmdline. Then `col` will be a byte position in the cmdline text. cmdline. Then `col` will be a byte position in the cmdline text.
["popupmenu_select", selected] ["popupmenu_select", selected] ~
Select an item in the current popupmenu. `selected` is a zero-based Select an item in the current popupmenu. `selected` is a zero-based
index into the array of items from the last popupmenu_show event, or index into the array of items from the last popupmenu_show event, or
-1 if no item is selected. -1 if no item is selected.
["popupmenu_hide"] ["popupmenu_hide"] ~
Hide the popupmenu. Hide the popupmenu.
============================================================================== ==============================================================================
@ -664,7 +661,7 @@ Tabline Events *ui-tabline*
Activated by the `ext_tabline` |ui-option|. Activated by the `ext_tabline` |ui-option|.
["tabline_update", curtab, tabs, curbuf, buffers] ["tabline_update", curtab, tabs, curbuf, buffers] ~
Tabline was updated. UIs should present this data in a custom tabline Tabline was updated. UIs should present this data in a custom tabline
widget. Note: options `curbuf` + `buffers` were added in API7. widget. Note: options `curbuf` + `buffers` were added in API7.
curtab: Current Tabpage curtab: Current Tabpage
@ -680,7 +677,7 @@ Activated by the `ext_cmdline` |ui-option|.
This UI extension delegates presentation of the |cmdline| (except 'wildmenu'). This UI extension delegates presentation of the |cmdline| (except 'wildmenu').
For command-line 'wildmenu' UI events, activate |ui-popupmenu|. For command-line 'wildmenu' UI events, activate |ui-popupmenu|.
["cmdline_show", content, pos, firstc, prompt, indent, level] ["cmdline_show", content, pos, firstc, prompt, indent, level] ~
content: List of [attrs, string] content: List of [attrs, string]
[[{}, "t"], [attrs, "est"], ...] [[{}, "t"], [attrs, "est"], ...]
@ -703,10 +700,10 @@ For command-line 'wildmenu' UI events, activate |ui-popupmenu|.
prompt has level 2. A command line invoked from the |cmdline-window| prompt has level 2. A command line invoked from the |cmdline-window|
has a higher level than than the edited command line. has a higher level than than the edited command line.
["cmdline_pos", pos, level] ["cmdline_pos", pos, level] ~
Change the cursor position in the cmdline. Change the cursor position in the cmdline.
["cmdline_special_char", c, shift, level] ["cmdline_special_char", c, shift, level] ~
Display a special char in the cmdline at the cursor position. This is Display a special char in the cmdline at the cursor position. This is
typically used to indicate a pending state, e.g. after |c_CTRL-V|. If typically used to indicate a pending state, e.g. after |c_CTRL-V|. If
`shift` is true the text after the cursor should be shifted, otherwise `shift` is true the text after the cursor should be shifted, otherwise
@ -714,10 +711,10 @@ For command-line 'wildmenu' UI events, activate |ui-popupmenu|.
Should be hidden at next cmdline_show. Should be hidden at next cmdline_show.
["cmdline_hide"] ["cmdline_hide"] ~
Hide the cmdline. Hide the cmdline.
["cmdline_block_show", lines] ["cmdline_block_show", lines] ~
Show a block of context to the current command line. For example if Show a block of context to the current command line. For example if
the user defines a |:function| interactively: > the user defines a |:function| interactively: >
:function Foo() :function Foo()
@ -727,10 +724,10 @@ For command-line 'wildmenu' UI events, activate |ui-popupmenu|.
`lines` is a list of lines of highlighted chunks, in the same form as `lines` is a list of lines of highlighted chunks, in the same form as
the "cmdline_show" `contents` parameter. the "cmdline_show" `contents` parameter.
["cmdline_block_append", line] ["cmdline_block_append", line] ~
Append a line at the end of the currently shown block. Append a line at the end of the currently shown block.
["cmdline_block_hide"] ["cmdline_block_hide"] ~
Hide the block. Hide the block.
============================================================================== ==============================================================================
@ -747,7 +744,7 @@ Nvim will not allocate screen space for the cmdline or messages, and
'cmdheight' will be forced zero. Cmdline state is emitted as |ui-cmdline| 'cmdheight' will be forced zero. Cmdline state is emitted as |ui-cmdline|
events, which the UI must handle. events, which the UI must handle.
["msg_show", kind, content, replace_last] ["msg_show", kind, content, replace_last] ~
Display a message to the user. Display a message to the user.
kind kind
@ -781,25 +778,25 @@ events, which the UI must handle.
true: Replace the message in the most-recent `msg_show` call, true: Replace the message in the most-recent `msg_show` call,
but any other visible message should still remain. but any other visible message should still remain.
["msg_clear"] ["msg_clear"] ~
Clear all messages currently displayed by "msg_show". (Messages sent Clear all messages currently displayed by "msg_show". (Messages sent
by other "msg_" events below will not be affected). by other "msg_" events below will not be affected).
["msg_showmode", content] ["msg_showmode", content] ~
Shows 'showmode' and |recording| messages. `content` has the same Shows 'showmode' and |recording| messages. `content` has the same
format as in "msg_show". This event is sent with empty `content` to format as in "msg_show". This event is sent with empty `content` to
hide the last message. hide the last message.
["msg_showcmd", content] ["msg_showcmd", content] ~
Shows 'showcmd' messages. `content` has the same format as in "msg_show". Shows 'showcmd' messages. `content` has the same format as in "msg_show".
This event is sent with empty `content` to hide the last message. This event is sent with empty `content` to hide the last message.
["msg_ruler", content] ["msg_ruler", content] ~
Used to display 'ruler' when there is no space for the ruler in a Used to display 'ruler' when there is no space for the ruler in a
statusline. `content` has the same format as in "msg_show". This event is statusline. `content` has the same format as in "msg_show". This event is
sent with empty `content` to hide the last message. sent with empty `content` to hide the last message.
["msg_history_show", entries] ["msg_history_show", entries] ~
Sent when |:messages| command is invoked. History is sent as a list of Sent when |:messages| command is invoked. History is sent as a list of
entries, where each entry is a `[kind, content]` tuple. entries, where each entry is a `[kind, content]` tuple.

View File

@ -907,8 +907,8 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers
return return
end end
--The active signature. If omitted or the value lies outside the range of --The active signature. If omitted or the value lies outside the range of
--`signatures` the value defaults to zero or is ignored if `signatures.length --`signatures` the value defaults to zero or is ignored if `signatures.length == 0`.
--=== 0`. Whenever possible implementors should make an active decision about --Whenever possible implementors should make an active decision about
--the active signature and shouldn't rely on a default value. --the active signature and shouldn't rely on a default value.
local contents = {} local contents = {}
local active_hl local active_hl

View File

@ -1,5 +1,7 @@
-- Converts Vim :help files to HTML. Validates |tag| links and document syntax (parser errors). -- Converts Vim :help files to HTML. Validates |tag| links and document syntax (parser errors).
-- --
-- NOTE: :helptags checks for duplicate tags, whereas this script checks _links_ (to tags).
--
-- USAGE (GENERATE HTML): -- USAGE (GENERATE HTML):
-- 1. Run `make helptags` first; this script depends on vim.fn.taglist(). -- 1. Run `make helptags` first; this script depends on vim.fn.taglist().
-- 2. nvim -V1 -es --clean +"lua require('scripts.gen_help_html').gen('./build/runtime/doc/', 'target/dir/')" -- 2. nvim -V1 -es --clean +"lua require('scripts.gen_help_html').gen('./build/runtime/doc/', 'target/dir/')"
@ -20,38 +22,19 @@
-- * visit_node() is the core function used by gen() to traverse the document tree and produce HTML. -- * visit_node() is the core function used by gen() to traverse the document tree and produce HTML.
-- * visit_validate() is the core function used by validate(). -- * visit_validate() is the core function used by validate().
-- * Files in `new_layout` will be generated with a "flow" layout instead of preformatted/fixed-width layout. -- * Files in `new_layout` will be generated with a "flow" layout instead of preformatted/fixed-width layout.
--
-- parser bugs:
-- * Should NOT be code_block:
-- tab:xy The 'x' is always used, then 'y' as many times as will
-- fit. Thus "tab:>-" displays:
-- >
-- >-
-- >--
-- etc.
--
-- tab:xyz The 'z' is always used, then 'x' is prepended, and
-- then 'y' is used as many times as will fit. Thus
-- "tab:<->" displays:
-- >
-- <>
-- <->
-- <-->
-- etc.
-- * Should NOT be a "headline". Perhaps a "table" (or just "line").
-- expr5 and expr6 *expr5* *expr6*
-- ---------------
-- expr6 + expr6 Number addition, |List| or |Blob| concatenation *expr-+*
-- expr6 - expr6 Number subtraction *expr--*
-- expr6 . expr6 String concatenation *expr-.*
-- expr6 .. expr6 String concatenation *expr-..*
local tagmap = nil local tagmap = nil
local helpfiles = nil local helpfiles = nil
local invalid_tags = {} local invalid_links = {}
local invalid_urls = {}
local invalid_spelling = {}
local spell_dict = {
Neovim = 'Nvim',
NeoVim = 'Nvim',
neovim = 'Nvim',
lua = 'Lua',
}
local commit = '?'
local api = vim.api
local M = {} local M = {}
-- These files are generated with "flow" layout (non fixed-width, wrapped text paragraphs). -- These files are generated with "flow" layout (non fixed-width, wrapped text paragraphs).
@ -60,16 +43,31 @@ local new_layout = {
['api.txt'] = true, ['api.txt'] = true,
['channel.txt'] = true, ['channel.txt'] = true,
['develop.txt'] = true, ['develop.txt'] = true,
['luaref.txt'] = true,
['nvim.txt'] = true, ['nvim.txt'] = true,
['pi_health.txt'] = true, ['pi_health.txt'] = true,
['provider.txt'] = true, ['provider.txt'] = true,
['ui.txt'] = true, ['ui.txt'] = true,
} }
-- TODO: treesitter gets stuck on these files... -- TODO: These known invalid |links| require an update to the relevant docs.
local exclude = { local exclude_invalid = {
['filetype.txt'] = true, ["'previewpopup'"] = "quickref.txt",
['usr_24.txt'] = true, ["'pvp'"] = "quickref.txt",
["'string'"] = "eval.txt",
Query = "treesitter.txt",
["eq?"] = "treesitter.txt",
["lsp-request"] = "lsp.txt",
matchit = "vim_diff.txt",
["matchit.txt"] = "help.txt",
["set!"] = "treesitter.txt",
["v:_null_blob"] = "builtin.txt",
["v:_null_dict"] = "builtin.txt",
["v:_null_list"] = "builtin.txt",
["v:_null_string"] = "builtin.txt",
["vim.lsp.buf_request()"] = "lsp.txt",
["vim.lsp.util.get_progress_messages()"] = "lsp.txt",
["vim.treesitter.start()"] = "treesitter.txt"
} }
local function tofile(fname, text) local function tofile(fname, text)
@ -83,10 +81,6 @@ local function tofile(fname, text)
end end
local function html_esc(s) local function html_esc(s)
if s:find('<a class="parse%-error"') then
-- HACK: don't escape HTML that we generated (for a parsing error).
return s
end
return s:gsub( return s:gsub(
'&', '&amp;'):gsub( '&', '&amp;'):gsub(
'<', '&lt;'):gsub( '<', '&lt;'):gsub(
@ -140,17 +134,15 @@ local function trim_bullet(s)
return s:gsub('^%s*[-*•]%s', '') return s:gsub('^%s*[-*•]%s', '')
end end
local function startswith_bullet(s)
return s:find('^%s*[-*•]%s')
end
-- Checks if a given line is a "noise" line that doesn't look good in HTML form. -- Checks if a given line is a "noise" line that doesn't look good in HTML form.
local function is_noise(line) local function is_noise(line, noise_lines)
return ( if (
line:find('Type .*gO.* to see the table of contents') -- First line is always noise.
(noise_lines ~= nil and vim.tbl_count(noise_lines) == 0)
or line:find('Type .*gO.* to see the table of contents')
-- Title line of traditional :help pages. -- Title line of traditional :help pages.
-- Example: "NVIM REFERENCE MANUAL by ..." -- Example: "NVIM REFERENCE MANUAL by ..."
or line:find('^%s*N?VIM REFERENCE MANUAL') or line:find([[^%s*N?VIM[ \t]*REFERENCE[ \t]*MANUAL]])
-- First line of traditional :help pages. -- First line of traditional :help pages.
-- Example: "*api.txt* Nvim" -- Example: "*api.txt* Nvim"
or line:find('%s*%*?[a-zA-Z]+%.txt%*?%s+N?[vV]im%s*$') or line:find('%s*%*?[a-zA-Z]+%.txt%*?%s+N?[vV]im%s*$')
@ -158,13 +150,19 @@ local function is_noise(line)
-- Example: "vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:" -- Example: "vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:"
or line:find('^%s*vi[m]%:.*ft=help') or line:find('^%s*vi[m]%:.*ft=help')
or line:find('^%s*vi[m]%:.*filetype=help') or line:find('^%s*vi[m]%:.*filetype=help')
) or line:find('[*>]local%-additions[*<]')
) then
-- table.insert(stats.noise_lines, getbuflinestr(root, opt.buf, 0))
table.insert(noise_lines or {}, line)
return true
end
return false
end end
-- Creates a github issue URL at vigoux/tree-sitter-vimdoc with prefilled content. -- Creates a github issue URL at neovim/tree-sitter-vimdoc with prefilled content.
local function get_bug_url_vimdoc(fname, to_fname, sample_text) local function get_bug_url_vimdoc(fname, to_fname, sample_text)
local this_url = string.format('https://neovim.io/doc/user/%s', vim.fs.basename(to_fname)) local this_url = string.format('https://neovim.io/doc/user/%s', vim.fs.basename(to_fname))
local bug_url = ('https://github.com/vigoux/tree-sitter-vimdoc/issues/new?labels=bug&title=parse+error%3A+' local bug_url = ('https://github.com/neovim/tree-sitter-vimdoc/issues/new?labels=bug&title=parse+error%3A+'
..vim.fs.basename(fname) ..vim.fs.basename(fname)
..'+&body=Found+%60tree-sitter-vimdoc%60+parse+error+at%3A+' ..'+&body=Found+%60tree-sitter-vimdoc%60+parse+error+at%3A+'
..this_url ..this_url
@ -238,31 +236,57 @@ local function getbuflinestr(node, bufnr, offset)
return table.concat(lines, '\n') return table.concat(lines, '\n')
end end
-- Gets the whitespace just before `node` from the raw buffer text. local function get_tagname(node, bufnr)
-- Needed for preformatted `old` lines.
local function getws(node, bufnr)
local line1, c1, line2, _ = node:range()
local raw = vim.fn.getbufline(bufnr, line1 + 1, line2 + 1)[1]
local text_before = raw:sub(1, c1)
local leading_ws = text_before:match('%s+$') or ''
return leading_ws
end
local function get_tagname(node, bufnr, link)
local node_name = (node.named and node:named()) and node:type() or nil
local node_text = vim.treesitter.get_node_text(node, bufnr) local node_text = vim.treesitter.get_node_text(node, bufnr)
local tag = ((node_name == 'option' and node_text) local tag = (node:type() == 'optionlink' or node:parent():type() == 'optionlink') and ("'%s'"):format(node_text) or node_text
or (link and node_text:gsub('^|', ''):gsub('|$', '') or node_text:gsub('^%*', ''):gsub('%*$', ''))) local helpfile = vim.fs.basename(tagmap[tag]) or nil -- "api.txt"
local helpfile = tag and vim.fs.basename(tagmap[tag]) or nil -- "api.txt"
local helppage = get_helppage(helpfile) -- "api.html" local helppage = get_helppage(helpfile) -- "api.html"
return helppage, tag return helppage, tag
end end
-- Returns true if the given invalid tagname is a false positive.
local function ignore_invalid(s)
-- Strings like |~/====| appear in various places and the parser thinks they are links, but they
-- are just table borders.
return not not (s:find('===') or exclude_invalid[s])
end
local function ignore_parse_error(s)
-- Ignore parse errors for unclosed codespan/optionlink/tag.
-- This is common in vimdocs and is treated as plaintext by :help.
return s:find("^[`'|*]")
end
local function has_ancestor(node, ancestor_name)
local p = node
while true do
p = p:parent()
if not p or p:type() == 'help_file' then
break
elseif p:type() == ancestor_name then
return true
end
end
return false
end
local function validate_link(node, bufnr, fname)
local helppage, tagname = get_tagname(node:child(1), bufnr, true)
if not has_ancestor(node, 'column_heading') and not node:has_error() and not tagmap[tagname] and not ignore_invalid(tagname) then
invalid_links[tagname] = vim.fs.basename(fname)
end
return helppage, tagname
end
-- Traverses the tree at `root` and checks that |tag| links point to valid helptags. -- Traverses the tree at `root` and checks that |tag| links point to valid helptags.
local function visit_validate(root, level, lang_tree, opt, stats) local function visit_validate(root, level, lang_tree, opt, stats)
level = level or 0 level = level or 0
local node_name = (root.named and root:named()) and root:type() or nil local node_name = (root.named and root:named()) and root:type() or nil
local toplevel = level < 1 local toplevel = level < 1
local function node_text(node)
return vim.treesitter.get_node_text(node or root, opt.buf)
end
local text = trim(node_text())
if root:child_count() > 0 then if root:child_count() > 0 then
for node, _ in root:iter_children() do for node, _ in root:iter_children() do
@ -273,15 +297,27 @@ local function visit_validate(root, level, lang_tree, opt, stats)
end end
if node_name == 'ERROR' then if node_name == 'ERROR' then
if ignore_parse_error(text) then
return
end
-- Store the raw text to give context to the bug report. -- Store the raw text to give context to the bug report.
local sample_text = not toplevel and getbuflinestr(root, opt.buf, 3) or '[top level!]' local sample_text = not toplevel and getbuflinestr(root, opt.buf, 3) or '[top level!]'
table.insert(stats.parse_errors, sample_text) table.insert(stats.parse_errors, sample_text)
elseif node_name == 'hotlink' or node_name == 'option' then elseif node_name == 'word' or node_name == 'uppercase_name' then
local _, tagname = get_tagname(root, opt.buf, true) if spell_dict[text] then
if not root:has_error() and not tagmap[tagname] then if not invalid_spelling[text] then
invalid_tags[tagname] = vim.fs.basename(opt.fname) invalid_spelling[text] = { vim.fs.basename(opt.fname) }
else
table.insert(invalid_spelling[text], vim.fs.basename(opt.fname))
end end
end end
elseif node_name == 'url' then
if text:find('http%:') then
invalid_urls[text] = vim.fs.basename(opt.fname)
end
elseif node_name == 'taglink' or node_name == 'optionlink' then
local _, _ = validate_link(root, opt.buf, opt.fname)
end
end end
-- Generates HTML from node `root` recursively. -- Generates HTML from node `root` recursively.
@ -297,19 +333,18 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
local parent = root:parent() and root:parent():type() or nil local parent = root:parent() and root:parent():type() or nil
local text = '' local text = ''
local toplevel = level < 1 local toplevel = level < 1
local function node_text() local function node_text(node)
return vim.treesitter.get_node_text(root, opt.buf) return vim.treesitter.get_node_text(node or root, opt.buf)
end end
if root:child_count() == 0 then if root:child_count() == 0 or node_name == 'ERROR' then
text = node_text() text = node_text()
else else
-- Process children and join them with whitespace. -- Process children and join them with whitespace.
for node, _ in root:iter_children() do for node, _ in root:iter_children() do
if node:named() then if node:named() then
local r = visit_node(node, level + 1, lang_tree, headings, opt, stats) local r = visit_node(node, level + 1, lang_tree, headings, opt, stats)
local ws = r == '' and '' or ((opt.old and (node:type() == 'word' or not node:named())) and getws(node, opt.buf) or ' ') text = string.format('%s%s', text, r)
text = string.format('%s%s%s', text, ws, r)
end end
end end
end end
@ -317,82 +352,112 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
if node_name == 'help_file' then -- root node if node_name == 'help_file' then -- root node
return text return text
elseif node_name == 'url' then
return ('<a href="%s">%s</a>'):format(trimmed, trimmed)
elseif node_name == 'word' or node_name == 'uppercase_name' then elseif node_name == 'word' or node_name == 'uppercase_name' then
if parent == 'headline' then
-- Start a new heading item, or update the current one.
local n = (prev == nil or #headings == 0) and #headings + 1 or #headings
headings[n] = string.format('%s%s', headings[n] and headings[n]..' ' or '', text)
end
return html_esc(text) return html_esc(text)
elseif node_name == 'headline' then elseif node_name == 'h1' or node_name == 'h2' or node_name == 'h3' then
return ('<a name="%s"></a><h2 class="help-heading">%s</h2>\n'):format(to_heading_tag(headings[#headings]), text) if is_noise(text, stats.noise_lines) then
return '' -- Discard common "noise" lines.
end
-- Remove "===" and tags from ToC text.
local hname = (node_text():gsub('%-%-%-%-+', ''):gsub('%=%=%=%=+', ''):gsub('%*.*%*', ''))
if node_name == 'h1' or #headings == 0 then
table.insert(headings, { name = hname, subheadings = {}, })
else
table.insert(headings[#headings].subheadings, { name = hname, subheadings = {}, })
end
local el = node_name == 'h1' and 'h2' or 'h3'
return ('<a name="%s"></a><%s class="help-heading">%s</%s>\n'):format(to_heading_tag(hname), el, text, el)
elseif node_name == 'column_heading' or node_name == 'column_name' then elseif node_name == 'column_heading' or node_name == 'column_name' then
return ('<h4>%s</h4>\n'):format(trimmed) if root:has_error() then
elseif node_name == 'line' then return text
-- TODO: remove these "sibling inspection" hacks once the parser provides structured info end
-- about paragraphs and listitems: https://github.com/vigoux/tree-sitter-vimdoc/issues/12 return ('<div class="help-column_heading">%s</div>'):format(trimmed)
local next_text = root:next_sibling() and vim.treesitter.get_node_text(root:next_sibling(), opt.buf) or '' elseif node_name == 'block' then
local li = startswith_bullet(text) -- Listitem? if is_blank(text) then
local next_li = startswith_bullet(next_text) -- Next is listitem? return ''
-- Close the paragraph/listitem if the next sibling is not a line.
local close = (next_ ~= 'line' or next_li or is_blank(next_text)) and '</div>\n' or ''
-- HACK: discard common "noise" lines.
if is_noise(text) then
table.insert(stats.noise_lines, getbuflinestr(root, opt.buf, 0))
return (opt.old or prev ~= 'line') and '' or close
end end
if opt.old then if opt.old then
-- XXX: Treat old docs as preformatted. Until those docs are "fixed" or we get better info -- XXX: Treat old docs as preformatted; random indentation is used for layout there.
-- from tree-sitter-vimdoc, this avoids broken layout for legacy docs. return ('<div class="old-help-para">%s</div>\n'):format(text)
return ('<div class="old-help-line">%s</div>\n'):format(text) end
return string.format('<div class="help-para">\n%s\n</div>\n', text)
elseif node_name == 'line' then
local sib = root:prev_sibling()
local sib_last = sib and sib:named_child(sib:named_child_count() - 1)
local in_li = false
-- XXX: parser bug: (codeblock) without terminating "<" consumes first char of the next (line). Recover it here.
local recovered = (sib_last and sib_last:type() == 'codeblock') and node_text(root:prev_sibling()):sub(-1) or ''
recovered = recovered == '<' and '' or html_esc(recovered)
-- XXX: see if we are currently "in" a listitem.
while sib ~= nil and not in_li do
in_li = (sib:type() == 'line_li')
sib = sib:prev_sibling()
end end
if li then -- Close the current listitem.
return string.format('<div class="help-item">%s%s', trim_bullet(expandtabs(text)), close) local close = (in_li and next_ ~= 'line') and '</div>' or ''
end
if prev ~= 'line' then -- Start a new paragraph. if is_blank(text) or is_noise(text, stats.noise_lines) then
return string.format('<div class="help-para">%s%s', expandtabs(text), close) return close -- Discard common "noise" lines.
end end
-- Continue in the current paragraph/listitem. local div = (root:child(0) and root:child(0):type() == 'column_heading') or close ~= ''
return string.format('%s%s', expandtabs(text), close) return string.format('%s%s%s%s', recovered, div and trim(text) or text, div and '' or '\n', close)
elseif node_name == 'hotlink' or node_name == 'option' then elseif node_name == 'line_li' then
local helppage, tagname = get_tagname(root, opt.buf, true) -- Close the listitem immediately if the next sibling is not a line.
if not root:has_error() and not tagmap[tagname] then local close = (next_ ~= 'line') and '</div>' or ''
invalid_tags[tagname] = vim.fs.basename(opt.fname) return string.format('<div class="help-li">%s %s', trim_bullet(text), close)
elseif node_name == 'taglink' or node_name == 'optionlink' then
if root:has_error() then
return text
end end
return ('<a href="%s#%s">%s</a>'):format(helppage, url_encode(tagname), html_esc(tagname)) local helppage, tagname = validate_link(root, opt.buf, opt.fname)
elseif node_name == 'backtick' then return (' <a href="%s#%s">%s</a>'):format(helppage, url_encode(tagname), html_esc(tagname))
return ('<code>%s</code>'):format(html_esc(text)) elseif node_name == 'codespan' then
if root:has_error() then
return text
end
return (' <code>%s</code>'):format(text)
elseif node_name == 'argument' then elseif node_name == 'argument' then
return ('<code>{%s}</code>'):format(html_esc(trimmed)) return (' <code>{%s}</code>'):format(trimmed)
elseif node_name == 'code_block' then elseif node_name == 'codeblock' then
return ('<pre>\n%s</pre>\n'):format(html_esc(trim_indent(trim_gt_lt(text)))) return ('<pre>%s</pre>'):format(html_esc(trim_indent(trim_gt_lt(text))))
elseif node_name == 'tag' then -- anchor elseif node_name == 'tag' then -- anchor
local _, tagname = get_tagname(root, opt.buf, false) if root:has_error() then
local s = ('<a name="%s"></a><span class="help-tag">%s</span>'):format(url_encode(tagname), trimmed) return text
if parent == 'headline' and prev ~= 'tag' then end
local in_heading = (parent == 'h1' or parent == 'h2')
local cssclass = (not in_heading and get_indent(node_text()) > 8) and 'help-tag-right' or 'help-tag'
local tagname = node_text(root:child(1))
if vim.tbl_count(stats.first_tags) < 2 then
-- First 2 tags in the doc will be anchored at the main heading.
table.insert(stats.first_tags, tagname)
return ''
end
local s = (' <a name="%s"></a><span class="%s">%s</span>'):format(url_encode(tagname), cssclass, trimmed)
if in_heading and prev ~= 'tag' then
-- Start the <span> container for tags in a heading. -- Start the <span> container for tags in a heading.
-- This makes "justify-content:space-between" right-align the tags. -- This makes "justify-content:space-between" right-align the tags.
-- <h2>foo bar<span>tag1 tag2</span></h2> -- <h2>foo bar<span>tag1 tag2</span></h2>
return string.format('<span class="help-heading-tags">%s', s) return string.format('<span class="help-heading-tags">%s', s)
elseif parent == 'headline' and next_ == nil then elseif in_heading and next_ == nil then
-- End the <span> container for tags in a heading. -- End the <span> container for tags in a heading.
return string.format('%s</span>', s) return string.format('%s</span>', s)
end end
return s return s
elseif node_name == 'ERROR' then elseif node_name == 'ERROR' then
if ignore_parse_error(trimmed) then
return text
end
-- Store the raw text to give context to the bug report. -- Store the raw text to give context to the bug report.
local sample_text = not toplevel and getbuflinestr(root, opt.buf, 3) or '[top level!]' local sample_text = not toplevel and getbuflinestr(root, opt.buf, 3) or '[top level!]'
table.insert(stats.parse_errors, sample_text) table.insert(stats.parse_errors, sample_text)
if prev == 'ERROR' then return ('<a class="parse-error" target="_blank" title="Parse error. Report to tree-sitter-vimdoc..." href="%s">%s</a>'):format(
-- Avoid trashing the text with cascading errors.
return trimmed, ('parse-error:"%s"'):format(node_text())
end
return ('<a class="parse-error" target="_blank" title="Parsing error. Report to tree-sitter-vimdoc..." href="%s">%s</a>'):format(
get_bug_url_vimdoc(opt.fname, opt.to_fname, sample_text), trimmed) get_bug_url_vimdoc(opt.fname, opt.to_fname, sample_text), trimmed)
else -- Unknown token. else -- Unknown token.
local sample_text = not toplevel and getbuflinestr(root, opt.buf, 3) or '[top level!]' local sample_text = not toplevel and getbuflinestr(root, opt.buf, 3) or '[top level!]'
@ -407,8 +472,7 @@ local function get_helpfiles(include)
for f, type in vim.fs.dir(dir) do for f, type in vim.fs.dir(dir) do
if (vim.endswith(f, '.txt') if (vim.endswith(f, '.txt')
and type == 'file' and type == 'file'
and (not include or vim.tbl_contains(include, f)) and (not include or vim.tbl_contains(include, f))) then
and (not exclude[f])) then
local fullpath = vim.fn.fnamemodify(('%s/%s'):format(dir, f), ':p') local fullpath = vim.fn.fnamemodify(('%s/%s'):format(dir, f), ':p')
table.insert(rv, fullpath) table.insert(rv, fullpath)
end end
@ -431,6 +495,13 @@ local function get_helptags(help_dir)
return m return m
end end
-- Use the help.so parser defined in the build, not whatever happens to be installed on the system.
local function ensure_runtimepath()
if not vim.o.runtimepath:find('build/lib/nvim/') then
vim.cmd[[set runtimepath^=./build/lib/nvim/]]
end
end
-- Opens `fname` in a buffer and gets a treesitter parser for the buffer contents. -- Opens `fname` in a buffer and gets a treesitter parser for the buffer contents.
-- --
-- @returns lang_tree, bufnr -- @returns lang_tree, bufnr
@ -438,7 +509,7 @@ local function parse_buf(fname)
local buf local buf
if type(fname) == 'string' then if type(fname) == 'string' then
vim.cmd('split '..vim.fn.fnameescape(fname)) -- Filename. vim.cmd('split '..vim.fn.fnameescape(fname)) -- Filename.
buf = api.nvim_get_current_buf() buf = vim.api.nvim_get_current_buf()
else else
buf = fname buf = fname
vim.cmd('sbuffer '..tostring(fname)) -- Buffer number. vim.cmd('sbuffer '..tostring(fname)) -- Buffer number.
@ -452,10 +523,9 @@ end
-- - checks that |tag| links point to valid helptags. -- - checks that |tag| links point to valid helptags.
-- - recursively counts parse errors ("ERROR" nodes) -- - recursively counts parse errors ("ERROR" nodes)
-- --
-- @returns { invalid_tags: number, parse_errors: number } -- @returns { invalid_links: number, parse_errors: number }
local function validate_one(fname) local function validate_one(fname)
local stats = { local stats = {
invalid_tags = {},
parse_errors = {}, parse_errors = {},
} }
local lang_tree, buf = parse_buf(fname) local lang_tree, buf = parse_buf(fname)
@ -464,10 +534,7 @@ local function validate_one(fname)
end end
lang_tree:destroy() lang_tree:destroy()
vim.cmd.close() vim.cmd.close()
return { return stats
invalid_tags = invalid_tags,
parse_errors = stats.parse_errors,
}
end end
-- Generates HTML from one :help file `fname` and writes the result to `to_fname`. -- Generates HTML from one :help file `fname` and writes the result to `to_fname`.
@ -477,13 +544,14 @@ end
-- @param old boolean Preformat paragraphs (for old :help files which are full of arbitrary whitespace) -- @param old boolean Preformat paragraphs (for old :help files which are full of arbitrary whitespace)
-- --
-- @returns html, stats -- @returns html, stats
local function gen_one(fname, to_fname, old) local function gen_one(fname, to_fname, old, commit)
local stats = { local stats = {
noise_lines = {}, noise_lines = {},
parse_errors = {}, parse_errors = {},
first_tags = {}, -- Track the first few tags in doc.
} }
local lang_tree, buf = parse_buf(fname) local lang_tree, buf = parse_buf(fname)
local headings = {} -- Headings (for ToC). local headings = {} -- Headings (for ToC). 2-dimensional: h1 contains h2/h3.
local title = to_titlecase(basename_noext(fname)) local title = to_titlecase(basename_noext(fname))
local html = ([[ local html = ([[
@ -556,7 +624,12 @@ local function gen_one(fname, to_fname, old)
</svg> </svg>
]] ]]
local main = ([[ local main = ''
for _, tree in ipairs(lang_tree:trees()) do
main = main .. (visit_node(tree:root(), 0, tree, headings, { buf = buf, old = old, fname = fname, to_fname = to_fname }, stats))
end
main = ([[
<header class="container"> <header class="container">
<nav class="navbar navbar-expand-lg"> <nav class="navbar navbar-expand-lg">
<div> <div>
@ -571,29 +644,37 @@ local function gen_one(fname, to_fname, old)
<div class="container golden-grid help-body"> <div class="container golden-grid help-body">
<div class="col-wide"> <div class="col-wide">
<h1>%s</h1> <a name="%s"></a><a name="%s"></a><h1>%s</h1>
<p> <p>
<i> <i>
Nvim help pages, updated <a href="https://github.com/neovim/neovim/blob/master/scripts/gen_help_html.lua">automatically</a> Nvim <code>:help</code> pages, <a href="https://github.com/neovim/neovim/blob/master/scripts/gen_help_html.lua">generated</a>
from <a href="https://github.com/neovim/neovim/blob/master/runtime/doc/%s">source</a>. from <a href="https://github.com/neovim/neovim/blob/master/runtime/doc/%s">source</a>
Parsing by <a href="https://github.com/vigoux/tree-sitter-vimdoc">tree-sitter-vimdoc</a>. using the <a href="https://github.com/neovim/tree-sitter-vimdoc">tree-sitter-vimdoc</a> parser.
</i> </i>
</p> </p>
]]):format(logo_svg, title, vim.fs.basename(fname)) <hr/>
for _, tree in ipairs(lang_tree:trees()) do %s
main = main .. (visit_node(tree:root(), 0, tree, headings, { buf = buf, old = old, fname = fname, to_fname = to_fname }, stats)) </div>
end ]]):format(logo_svg, stats.first_tags[1] or '', stats.first_tags[2] or '', title, vim.fs.basename(fname), main)
main = main .. '</div>\n'
local toc = [[ local toc = [[
<div class="col-narrow toc"> <div class="col-narrow toc">
<div><a href="index.html">Main</a></div> <div><a href="index.html">Main</a></div>
<div><a href="vimindex.html">Help index</a></div> <div><a href="vimindex.html">Commands index</a></div>
<div><a href="quickref.html">Quick reference</a></div> <div><a href="quickref.html">Quick reference</a></div>
<hr/> <hr/>
]] ]]
for _, heading in ipairs(headings) do
toc = toc .. ('<div><a href="#%s">%s</a></div>\n'):format(to_heading_tag(heading), heading) local n = 0 -- Count of all headings + subheadings.
for _, h1 in ipairs(headings) do n = n + 1 + #h1.subheadings end
for _, h1 in ipairs(headings) do
toc = toc .. ('<div class="help-toc-h1"><a href="#%s">%s</a>\n'):format(to_heading_tag(h1.name), h1.name)
if n < 30 or #headings < 10 then -- Show subheadings only if there aren't too many.
for _, h2 in ipairs(h1.subheadings) do
toc = toc .. ('<div class="help-toc-h2"><a href="#%s">%s</a></div>\n'):format(to_heading_tag(h2.name), h2.name)
end
end
toc = toc .. '</div>'
end end
toc = toc .. '</div>\n' toc = toc .. '</div>\n'
@ -604,7 +685,7 @@ local function gen_one(fname, to_fname, old)
<footer> <footer>
<div class="container flex"> <div class="container flex">
<div class="generator-stats"> <div class="generator-stats">
Generated on %s from <code>{%s}</code> Generated at %s from <code><a href="https://github.com/neovim/neovim/commit/%s">%s</a></code>
</div> </div>
<div class="generator-stats"> <div class="generator-stats">
parse_errors: %d %s | <span title="%s">noise_lines: %d</span> parse_errors: %d %s | <span title="%s">noise_lines: %d</span>
@ -612,7 +693,7 @@ local function gen_one(fname, to_fname, old)
<div> <div>
</footer> </footer>
]]):format( ]]):format(
os.date('%Y-%m-%d %H:%M:%S'), commit, #stats.parse_errors, bug_link, os.date('%Y-%m-%d %H:%M'), commit, commit:sub(1, 7), #stats.parse_errors, bug_link,
html_esc(table.concat(stats.noise_lines, '\n')), #stats.noise_lines) html_esc(table.concat(stats.noise_lines, '\n')), #stats.noise_lines)
html = ('%s%s%s</div>\n%s</body>\n</html>\n'):format( html = ('%s%s%s</div>\n%s</body>\n</html>\n'):format(
@ -624,12 +705,21 @@ end
local function gen_css(fname) local function gen_css(fname)
local css = [[ local css = [[
:root {
--code-color: #008B8B;
--tag-color: gray;
}
@media (min-width: 40em) { @media (min-width: 40em) {
.toc { .toc {
position: fixed; position: fixed;
left: 67%; left: 67%;
} }
} }
@media (prefers-color-scheme: dark) {
:root {
--code-color: cyan;
}
}
.toc { .toc {
/* max-width: 12rem; */ /* max-width: 12rem; */
} }
@ -641,8 +731,19 @@ local function gen_css(fname)
html { html {
scroll-behavior: auto; scroll-behavior: auto;
} }
h1, h2, h3, h4 { body {
font-size: 18px;
line-height: 1.5;
}
h1, h2, h3, h4, h5 {
font-family: sans-serif; font-family: sans-serif;
border-bottom: 1px solid gray;
}
h3, h4, h5 {
border-bottom-style: dashed;
}
.help-column_heading {
color: var(--code-color);
} }
.help-body { .help-body {
padding-bottom: 2em; padding-bottom: 2em;
@ -650,7 +751,8 @@ local function gen_css(fname)
.help-line { .help-line {
/* font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; */ /* font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; */
} }
.help-item { .help-li {
white-space: normal;
display: list-item; display: list-item;
margin-left: 1.5rem; /* padding-left: 1rem; */ margin-left: 1.5rem; /* padding-left: 1rem; */
} }
@ -658,11 +760,13 @@ local function gen_css(fname)
padding-top: 10px; padding-top: 10px;
padding-bottom: 10px; padding-bottom: 10px;
} }
.old-help-line { .old-help-para {
padding-top: 10px;
padding-bottom: 10px;
/* Tabs are used for alignment in old docs, so we must match Vim's 8-char expectation. */ /* Tabs are used for alignment in old docs, so we must match Vim's 8-char expectation. */
tab-size: 8; tab-size: 8;
white-space: pre; white-space: pre;
font-size: .875em; font-size: 16px;
font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
} }
a.help-tag, a.help-tag:focus, a.help-tag:hover { a.help-tag, a.help-tag:focus, a.help-tag:hover {
@ -670,7 +774,13 @@ local function gen_css(fname)
text-decoration: none; text-decoration: none;
} }
.help-tag { .help-tag {
color: gray; color: var(--tag-color);
}
/* Tag pseudo-header common in :help docs. */
.help-tag-right {
color: var(--tag-color);
display: block;
text-align: right;
} }
h1 .help-tag, h2 .help-tag { h1 .help-tag, h2 .help-tag {
font-size: smaller; font-size: smaller;
@ -683,7 +793,12 @@ local function gen_css(fname)
} }
/* The (right-aligned) "tags" part of a section heading. */ /* The (right-aligned) "tags" part of a section heading. */
.help-heading-tags { .help-heading-tags {
margin-left: 10px; margin-right: 10px;
}
.help-toc-h1 {
}
.help-toc-h2 {
margin-left: 1em;
} }
.parse-error { .parse-error {
background-color: red; background-color: red;
@ -692,15 +807,19 @@ local function gen_css(fname)
color: black; color: black;
background-color: yellow; background-color: yellow;
} }
code {
color: var(--code-color);
font-size: 16px;
}
pre { pre {
/* Tabs are used in code_blocks only for indentation, not alignment, so we can aggressively shrink them. */ /* Tabs are used in codeblocks only for indentation, not alignment, so we can aggressively shrink them. */
tab-size: 2; tab-size: 2;
white-space: pre; white-space: pre;
line-height: 1.1; /* Important for ascii art. */
overflow: visible; overflow: visible;
/* font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; */ /* font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; */
/* font-size: 14px; */ font-size: 16px;
/* border: 0px; */ margin-top: 10px;
/* margin: 0px; */
} }
pre:hover, pre:hover,
.help-heading:hover { .help-heading:hover {
@ -735,12 +854,11 @@ function M._test()
return ok(expected == actual, expected, actual) return ok(expected == actual, expected, actual)
end end
eq(119, #helpfiles)
ok(vim.tbl_count(tagmap) > 3000, '>3000', vim.tbl_count(tagmap)) ok(vim.tbl_count(tagmap) > 3000, '>3000', vim.tbl_count(tagmap))
ok(vim.endswith(tagmap['vim.diagnostic.set()'], 'diagnostic.txt'), tagmap['vim.diagnostic.set()'], 'diagnostic.txt') ok(vim.endswith(tagmap['vim.diagnostic.set()'], 'diagnostic.txt'), tagmap['vim.diagnostic.set()'], 'diagnostic.txt')
ok(vim.endswith(tagmap['%:s'], 'cmdline.txt'), tagmap['%:s'], 'cmdline.txt') ok(vim.endswith(tagmap['%:s'], 'cmdline.txt'), tagmap['%:s'], 'cmdline.txt')
ok(is_noise([[vim:tw=78:isk=!-~,^*,^\|,^\":ts=8:noet:ft=help:norl:]])) ok(is_noise([[vim:tw=78:isk=!-~,^*,^\|,^\":ts=8:noet:ft=help:norl:]]))
ok(is_noise([[ VIM REFERENCE MANUAL by Abe Lincoln ]])) ok(is_noise([[ NVIM REFERENCE MANUAL by Thiago de Arruda ]]))
ok(not is_noise([[vim:tw=78]])) ok(not is_noise([[vim:tw=78]]))
eq(0, get_indent('a')) eq(0, get_indent('a'))
@ -763,14 +881,16 @@ end
--- @param include table|nil Process only these filenames. Example: {'api.txt', 'autocmd.txt', 'channel.txt'} --- @param include table|nil Process only these filenames. Example: {'api.txt', 'autocmd.txt', 'channel.txt'}
--- ---
--- @returns info dict --- @returns info dict
function M.gen(help_dir, to_dir, include) function M.gen(help_dir, to_dir, include, commit)
vim.validate{ vim.validate{
help_dir={help_dir, function(d) return vim.fn.isdirectory(d) == 1 end, 'valid directory'}, help_dir={help_dir, function(d) return vim.fn.isdirectory(d) == 1 end, 'valid directory'},
to_dir={to_dir, 's'}, to_dir={to_dir, 's'},
include={include, 't', true}, include={include, 't', true},
commit={commit, 's', true},
} }
local err_count = 0 local err_count = 0
ensure_runtimepath()
tagmap = get_helptags(help_dir) tagmap = get_helptags(help_dir)
helpfiles = get_helpfiles(include) helpfiles = get_helpfiles(include)
@ -781,19 +901,19 @@ function M.gen(help_dir, to_dir, include)
for _, f in ipairs(helpfiles) do for _, f in ipairs(helpfiles) do
local helpfile = vim.fs.basename(f) local helpfile = vim.fs.basename(f)
local to_fname = ('%s/%s'):format(to_dir, get_helppage(helpfile)) local to_fname = ('%s/%s'):format(to_dir, get_helppage(helpfile))
local html, stats = gen_one(f, to_fname, not new_layout[helpfile]) local html, stats = gen_one(f, to_fname, not new_layout[helpfile], commit or '?')
tofile(to_fname, html) tofile(to_fname, html)
print(('generated (%-4s errors): %-15s => %s'):format(#stats.parse_errors, helpfile, vim.fs.basename(to_fname))) print(('generated (%-4s errors): %-15s => %s'):format(#stats.parse_errors, helpfile, vim.fs.basename(to_fname)))
err_count = err_count + #stats.parse_errors err_count = err_count + #stats.parse_errors
end end
print(('generated %d html pages'):format(#helpfiles)) print(('generated %d html pages'):format(#helpfiles))
print(('total errors: %d'):format(err_count)) print(('total errors: %d'):format(err_count))
print(('invalid tags:\n%s'):format(vim.inspect(invalid_tags))) print(('invalid tags:\n%s'):format(vim.inspect(invalid_links)))
return { return {
helpfiles = helpfiles, helpfiles = helpfiles,
err_count = err_count, err_count = err_count,
invalid_tags = invalid_tags, invalid_links = invalid_links,
} }
end end
@ -810,6 +930,7 @@ function M.validate(help_dir, include)
include={include, 't', true}, include={include, 't', true},
} }
local err_count = 0 local err_count = 0
ensure_runtimepath()
tagmap = get_helptags(help_dir) tagmap = get_helptags(help_dir)
helpfiles = get_helpfiles(include) helpfiles = get_helpfiles(include)
@ -821,9 +942,11 @@ function M.validate(help_dir, include)
end end
return { return {
helpfiles = helpfiles, helpfiles = #helpfiles,
err_count = err_count, err_count = err_count,
invalid_tags = invalid_tags, invalid_links = invalid_links,
invalid_urls = invalid_urls,
invalid_spelling = invalid_spelling,
} }
end end

View File

@ -354,7 +354,9 @@ describe('startup', function()
local function pack_clear(cmd) local function pack_clear(cmd)
-- add packages after config dir in rtp but before config/after -- add packages after config dir in rtp but before config/after
clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}} clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'},
args_rm={'runtimepath'},
}
end end

View File

@ -29,6 +29,7 @@ local module = {
} }
local start_dir = lfs.currentdir() local start_dir = lfs.currentdir()
local runtime_set = 'set runtimepath^=./build/lib/nvim/'
module.nvim_prog = ( module.nvim_prog = (
os.getenv('NVIM_PRG') os.getenv('NVIM_PRG')
or global_helpers.test_build_dir .. '/bin/nvim' or global_helpers.test_build_dir .. '/bin/nvim'
@ -40,6 +41,8 @@ module.nvim_set = (
..' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid') ..' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid')
module.nvim_argv = { module.nvim_argv = {
module.nvim_prog, '-u', 'NONE', '-i', 'NONE', module.nvim_prog, '-u', 'NONE', '-i', 'NONE',
-- XXX: find treesitter parsers.
'--cmd', runtime_set,
'--cmd', module.nvim_set, '--cmd', module.nvim_set,
'--cmd', 'mapclear', '--cmd', 'mapclear',
'--cmd', 'mapclear!', '--cmd', 'mapclear!',
@ -345,14 +348,17 @@ end
-- Removes Nvim startup args from `args` matching items in `args_rm`. -- Removes Nvim startup args from `args` matching items in `args_rm`.
-- --
-- "-u", "-i", "--cmd" are treated specially: their "values" are also removed. -- - Special case: "-u", "-i", "--cmd" are treated specially: their "values" are also removed.
-- - Special case: "runtimepath" will remove only { '--cmd', 'set runtimepath^=…', }
--
-- Example: -- Example:
-- args={'--headless', '-u', 'NONE'} -- args={'--headless', '-u', 'NONE'}
-- args_rm={'--cmd', '-u'} -- args_rm={'--cmd', '-u'}
-- Result: -- Result:
-- {'--headless'} -- {'--headless'}
-- --
-- All cases are removed. -- All matching cases are removed.
--
-- Example: -- Example:
-- args={'--cmd', 'foo', '-N', '--cmd', 'bar'} -- args={'--cmd', 'foo', '-N', '--cmd', 'bar'}
-- args_rm={'--cmd', '-u'} -- args_rm={'--cmd', '-u'}
@ -373,6 +379,9 @@ local function remove_args(args, args_rm)
last = '' last = ''
elseif tbl_contains(args_rm, arg) then elseif tbl_contains(args_rm, arg) then
last = arg last = arg
elseif arg == runtime_set and tbl_contains(args_rm, 'runtimepath') then
table.remove(new_args) -- Remove the preceding "--cmd".
last = ''
else else
table.insert(new_args, arg) table.insert(new_args, arg)
end end

View File

@ -12,29 +12,26 @@ describe(':help docs', function()
before_each(clear) before_each(clear)
it('validate', function() it('validate', function()
-- If this test fails, try these steps (in order): -- If this test fails, try these steps (in order):
-- 1. Try to fix/cleanup the :help docs, especially Nvim-owned :help docs. -- 1. Fix/cleanup the :help docs.
-- 2. Try to fix the parser: https://github.com/vigoux/tree-sitter-vimdoc -- 2. Fix the parser: https://github.com/neovim/tree-sitter-vimdoc
-- 3. File a parser bug, and adjust the tolerance of this test in the meantime. -- 3. File a parser bug, and adjust the tolerance of this test in the meantime.
local rv = exec_lua([[return require('scripts.gen_help_html').validate('./build/runtime/doc')]]) local rv = exec_lua([[return require('scripts.gen_help_html').validate('./build/runtime/doc')]])
-- Check that we actually found helpfiles.
ok(rv.helpfiles > 100, '>100 :help files', rv.helpfiles)
-- Check that parse errors did not increase wildly. -- Check that parse errors did not increase wildly.
-- TODO: yes, there are currently 24k+ parser errors. -- TODO: Fix all parse errors in :help files.
-- WIP: https://github.com/vigoux/tree-sitter-vimdoc/pull/16 ok(rv.err_count < 1300, '<1300 parse errors', rv.err_count)
ok(rv.err_count < 24000, '<24000', rv.err_count) eq({}, rv.invalid_links, exec_lua([[return 'found invalid :help tag links:\n'..vim.inspect(...)]], rv.invalid_links))
-- TODO: should be eq(0, …)
ok(exec_lua('return vim.tbl_count(...)', rv.invalid_tags) < 538, '<538',
exec_lua('return vim.inspect(...)', rv.invalid_tags))
end) end)
it('gen_help_html.lua generates HTML', function() it('gen_help_html.lua generates HTML', function()
-- Test: -- 1. Test that gen_help_html.lua actually works.
-- 1. Check that parse errors did not increase wildly. Because we explicitly test only a few -- 2. Test that parse errors did not increase wildly. Because we explicitly test only a few
-- :help files, we can be more precise about the tolerances here. -- :help files, we can be precise about the tolerances here.
-- 2. exercise gen_help_html.lua, check that it actually works.
-- 3. check that its tree-sitter-vimdoc dependency is working.
local tmpdir = exec_lua('return vim.fs.dirname(vim.fn.tempname())') local tmpdir = exec_lua('return vim.fs.dirname(vim.fn.tempname())')
-- Because gen() is slow (1 min), this test is limited to a few files. -- Because gen() is slow (~30s), this test is limited to a few files.
local rv = exec_lua([[ local rv = exec_lua([[
local to_dir = ... local to_dir = ...
return require('scripts.gen_help_html').gen( return require('scripts.gen_help_html').gen(
@ -46,9 +43,7 @@ describe(':help docs', function()
tmpdir tmpdir
) )
eq(4, #rv.helpfiles) eq(4, #rv.helpfiles)
ok(rv.err_count < 700, '<700', rv.err_count) ok(rv.err_count < 16, '<16 parse errors', rv.err_count)
-- TODO: should be eq(0, …) eq({}, rv.invalid_links, exec_lua([[return 'found invalid :help tag links:\n'..vim.inspect(...)]], rv.invalid_links))
ok(exec_lua('return vim.tbl_count(...)', rv.invalid_tags) <= 32, '<=32',
exec_lua('return vim.inspect(...)', rv.invalid_tags))
end) end)
end) end)

View File

@ -220,7 +220,9 @@ describe('startup defaults', function()
end) end)
it("'packpath'", function() it("'packpath'", function()
clear() clear{
args_rm={'runtimepath'},
}
-- Defaults to &runtimepath. -- Defaults to &runtimepath.
eq(meths.get_option('runtimepath'), meths.get_option('packpath')) eq(meths.get_option('runtimepath'), meths.get_option('packpath'))
@ -332,7 +334,9 @@ describe('XDG defaults', function()
describe('with too long XDG variables', function() describe('with too long XDG variables', function()
before_each(function() before_each(function()
clear({env={ clear({
args_rm={'runtimepath'},
env={
XDG_CONFIG_HOME=(root_path .. ('/x'):rep(4096)), XDG_CONFIG_HOME=(root_path .. ('/x'):rep(4096)),
XDG_CONFIG_DIRS=(root_path .. ('/a'):rep(2048) XDG_CONFIG_DIRS=(root_path .. ('/a'):rep(2048)
.. env_sep.. root_path .. ('/b'):rep(2048) .. env_sep.. root_path .. ('/b'):rep(2048)
@ -405,7 +409,9 @@ describe('XDG defaults', function()
describe('with XDG variables that can be expanded', function() describe('with XDG variables that can be expanded', function()
before_each(function() before_each(function()
clear({env={ clear({
args_rm={'runtimepath'},
env={
XDG_CONFIG_HOME='$XDG_DATA_HOME', XDG_CONFIG_HOME='$XDG_DATA_HOME',
XDG_CONFIG_DIRS='$XDG_DATA_DIRS', XDG_CONFIG_DIRS='$XDG_DATA_DIRS',
XDG_DATA_HOME='$XDG_CONFIG_HOME', XDG_DATA_HOME='$XDG_CONFIG_HOME',
@ -478,7 +484,9 @@ describe('XDG defaults', function()
describe('with commas', function() describe('with commas', function()
before_each(function() before_each(function()
clear({env={ clear({
args_rm={'runtimepath'},
env={
XDG_CONFIG_HOME=', , ,', XDG_CONFIG_HOME=', , ,',
XDG_CONFIG_DIRS=',-,-,' .. env_sep .. '-,-,-', XDG_CONFIG_DIRS=',-,-,' .. env_sep .. '-,-,-',
XDG_DATA_HOME=',=,=,', XDG_DATA_HOME=',=,=,',