gen_vimdoc.py: render nested lists, etc [ci skip]

- render_node() is now the main rendering function: it traverses a node
  and builds the Vim help text recursively.
- render_para() is weird and ugly, it is the entry-point for rendering
  the help text for one docstring'd function.
This commit is contained in:
Justin M. Keyes 2019-03-03 15:01:16 +01:00
parent eeb19a346a
commit bec4066033
2 changed files with 479 additions and 323 deletions

View File

@ -293,6 +293,9 @@ nvim_get_hl_by_name({name}, {rgb}) *nvim_get_hl_by_name()*
Return: ~
Highlight definition map
See also: ~
nvim_get_hl_by_id
nvim_get_hl_by_id({hl_id}, {rgb}) *nvim_get_hl_by_id()*
Gets a highlight definition by id. |hlID()|
@ -303,6 +306,9 @@ nvim_get_hl_by_id({hl_id}, {rgb}) *nvim_get_hl_by_id()*
Return: ~
Highlight definition map
See also: ~
nvim_get_hl_by_name
nvim_feedkeys({keys}, {mode}, {escape_csi}) *nvim_feedkeys()*
Sends input-keys to Nvim, subject to various quirks controlled
by `mode` flags. This is a blocking call, unlike
@ -316,6 +322,10 @@ nvim_feedkeys({keys}, {mode}, {escape_csi}) *nvim_feedkeys()*
{escape_csi} If true, escape K_SPECIAL/CSI bytes in
`keys`
See also: ~
feedkeys()
vim_strsave_escape_csi
nvim_input({keys}) *nvim_input()*
Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a
low-level input buffer and the call is non-blocking (input is
@ -326,7 +336,6 @@ nvim_input({keys}) *nvim_input()*
Note:
|keycodes| like <CR> are translated, so "<" is special. To
input a literal "<", send <LT>.
Note:
For mouse events use |nvim_input_mouse()|. The pseudokey
form "<LeftMouse><col,row>" is deprecated since
@ -346,9 +355,8 @@ nvim_input({keys}) *nvim_input()*
nvim_input_mouse({button}, {action}, {modifier}, {grid}, {row}, {col})
Send mouse event from GUI.
The call is non-blocking. It doesn't wait on any resulting
action, but queues the event to be processed soon by the event
loop.
Non-blocking: does not wait on any result, but queues the
event to be processed soon by the event loop.
Note:
Currently this doesn't support "scripting" multiple mouse
@ -392,6 +400,10 @@ nvim_replace_termcodes({str}, {from_part}, {do_lt}, {special})
{special} Replace |keycodes|, e.g. <CR> becomes a "\n"
char.
See also: ~
replace_termcodes
cpoptions
nvim_command_output({command}) *nvim_command_output()*
Executes an ex-command and returns its (non-error) output.
Shell |:!| output is not captured.
@ -575,11 +587,14 @@ nvim_err_writeln({str}) *nvim_err_writeln()*
Parameters: ~
{str} Message
See also: ~
nvim_err_write()
nvim_list_bufs() *nvim_list_bufs()*
Gets the current list of buffer handles
Includes unlisted (unloaded/deleted) buffers, like `:ls!`. Use
|nvim_buf_is_loaded()| to check if a buffer is loaded.
Includes unlisted (unloaded/deleted) buffers, like `:ls!` .
Use |nvim_buf_is_loaded()| to check if a buffer is loaded.
Return: ~
List of buffer handles
@ -618,13 +633,16 @@ nvim_create_buf({listed}, {scratch}) *nvim_create_buf()*
Creates a new, empty, unnamed buffer.
Parameters: ~
{listed} Controls 'buflisted'
{listed} Sets 'buflisted'
{scratch} Creates a "throwaway" |scratch-buffer| for
temporary work (always 'nomodified')
Return: ~
Buffer handle, or 0 on error
See also: ~
buf_open_scratch
nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
Open a new window.
@ -639,51 +657,6 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
Exactly one of `external` and `relative` must be specified.
Parameters: ~
{buffer} handle of buffer to be displayed in the window
{enter} whether the window should be entered (made the
current window)
{config} Dictionary for the window configuration accepts
these keys:
`relative`: If set, the window becomes a
floating window. The window will be placed with
row,col coordinates relative to one of the
following:
"editor" the global editor grid
"win" a window. Use `win` to specify window id,
or current window will be used by default.
"cursor" the cursor position in current window.
`win`: when using `relative='win'`, window id of the window
where the position is defined.
`anchor`: the corner of the float that the row,col
position defines
"NW" north-west (default)
"NE" north-east
"SW" south-west
"SE" south-east
`focusable`: Whether window can be focused by wincmds and
mouse events. Defaults to true. Even if set to false,
the window can still be entered using
|nvim_set_current_win()| API call.
`height`: Window height in character cells. Minimum of 1.
`width`: Window width in character cells. Minimum of 2.
`row`: row position. Screen cell height are used as unit.
Can be floating point.
`col`: column position. Screen cell width is used as
unit. Can be floating point.
`external`: GUI should display the window as an external
top-level window. Currently accepts no other
positioning configuration together with this.
With editor positioning row=0, col=0 refers to the top-left
corner of the screen-grid and row=Lines-1, Columns-1 refers to
the bottom-right corner. Floating point values are allowed,
@ -698,9 +671,49 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
should not be used to specify arbitrary WM screen positions.
Parameters: ~
{buffer} handle of buffer to be displayed in the window
{enter} whether the window should be entered (made the
current window)
{config} Dictionary for the window configuration accepts
these keys:
- `relative` : If set, the window becomes a floating
window. The window will be placed with row,col
coordinates relative to one of the following:
- "editor" the global editor grid
- "win" a window. Use `win` to specify a
window id, or the current window will be
used by default. "cursor" the cursor
position in current window.
- `win` : When using relative='win', window id
of the window where the position is defined.
- `anchor` : The corner of the float that the row,col
position defines:
- "NW" north-west (default)
- "NE" north-east
- "SW" south-west
- "SE" south-east
- `height` : window height (in character cells).
Minimum of 1.
- `width` : window width (in character cells).
Minimum of 2.
- `row` : row position. Screen cell height are
used as unit. Can be floating point.
- `col` : column position. Screen cell width is
used as unit. Can be floating point.
- `focusable` : Whether window can be focused by
wincmds and mouse events. Defaults to true.
Even if set to false, the window can still be
entered using |nvim_set_current_win()| API
call.
- `external` : GUI should display the window as
an external top-level window. Currently
accepts no other positioning configuration
together with this.
Return: ~
the window handle or 0 when error
Window handle, or 0 on error
nvim_list_tabpages() *nvim_list_tabpages()*
Gets the current list of tabpage handles.
@ -808,86 +821,87 @@ nvim_get_api_info() *nvim_get_api_info()*
*nvim_set_client_info()*
nvim_set_client_info({name}, {version}, {type}, {methods},
{attributes})
Identify the client for nvim. Can be called more than once,
but subsequent calls will remove earlier info, which should be
resent if it is still valid. (This could happen if a library
first identifies the channel, and a plugin using that library
later overrides that info)
Identifies the client. Can be called more than once;
subsequent calls remove earlier info, which should be included
by the caller if it is still valid. (E.g. if a library first
identifies the channel, then a plugin using that library later
overrides that info)
Parameters: ~
{name} short name for the connected client
{version} Dictionary describing the version, with the
following possible keys (all optional)
"major" major version (defaults to 0 if not
set, for no release yet) "minor" minor
version "patch" patch number "prerelease"
string describing a prerelease, like "dev"
or "beta1" "commit" hash or similar
identifier of commit
{type} Must be one of the following values. A
client library should use "remote" if the
library user hasn't specified other value.
"remote" remote client that connected to
nvim. "ui" gui frontend "embedder"
application using nvim as a component, for
instance IDE/editor implementing a vim mode.
"host" plugin host, typically started by
nvim "plugin" single plugin, started by
{name} Short name for the connected client
{version} Dictionary describing the version, with
these (optional) keys:
- "major" major version (defaults to 0 if
not set, for no release yet)
- "minor" minor version
- "patch" patch number
- "prerelease" string describing a
prerelease, like "dev" or "beta1"
- "commit" hash or similar identifier of
commit
{type} Must be one of the following values. Client
libraries should default to "remote" unless
overridden by the user.
- "remote" remote client connected to Nvim.
- "ui" gui frontend
- "embedder" application using Nvim as a
component (for example, IDE/editor
implementing a vim mode).
- "host" plugin host, typically started by
nvim
- "plugin" single plugin, started by nvim
{methods} Builtin methods in the client. For a host,
this does not include plugin methods which
will be discovered later. The key should be
the method name, the values are dicts with
the following (optional) keys: "async" if
true, send as a notification. If false or
unspecified, use a blocking request "nargs"
Number of arguments. Could be a single
integer or an array two integers, minimum
and maximum inclusive. Further keys might be
added in later versions of nvim and unknown
keys are thus ignored. Clients must only use
keys defined in this or later versions of
nvim!
{attributes} Informal attributes describing the client.
Clients might define their own keys, but the
following are suggested: "website" Website
of client (for instance github repository)
"license" Informal description of the
license, such as "Apache 2", "GPLv3" or
"MIT" "logo" URI or path to image,
preferably small logo or icon. .png or .svg
format is preferred.
these (optional) keys (more keys may be
added in future versions of Nvim, thus
unknown keys are ignored. Clients must only
use keys defined in this or later versions
of Nvim):
- "async" if true, send as a notification.
If false or unspecified, use a blocking
request
- "nargs" Number of arguments. Could be a
single integer or an array of two
integers, minimum and maximum inclusive.
{attributes} Arbitrary string:string map of informal
client properties. Suggested keys:
- "website": Client homepage URL (e.g.
GitHub repository)
- "license": License description ("Apache
2", "GPLv3", "MIT", …)
- "logo": URI or path to image, preferably
small logo or icon. .png or .svg format is
preferred.
nvim_get_chan_info({chan}) *nvim_get_chan_info()*
Get information about a channel.
Return: ~
a Dictionary, describing a channel with the following
keys:
Dictionary describing a channel, with these keys:
- "stream" the stream underlying the channel
- "stdio" stdin and stdout of this Nvim instance
- "stderr" stderr of this Nvim instance
- "socket" TCP/IP socket or named pipe
- "job" job with communication over its stdio
`stream`: the stream underlying the channel:
"stdio" stdin and stdout of this Nvim instance.
"stderr" stderr of this Nvim instance.
"socket" TCP/IP socket or named pipe.
"job" job with communication over its stdio.
- "mode" how data received on the channel is interpreted
- "bytes" send and receive raw bytes
- "terminal" a |terminal| instance interprets ASCII
sequences
- "rpc" |RPC| communication on the channel is active
`mode`: how data received on the channel is interpreted:
"bytes" send and recieve raw bytes.
"terminal" a |terminal| instance interprets ASCII sequences
"rpc" |RPC| communication on the channel is active
`pty`: Name of pseudoterminal, if one is used (optional).
- "pty" Name of pseudoterminal, if one is used (optional).
On a POSIX system, this will be a device path like
/dev/pts/1. Even if the name is unknown, the key will
still be present to indicate a pty is used. This is
currently the case when using winpty on windows.
`buffer`: buffer with connected |terminal|
instance (optional).
`client`: information about the client on the other end of
the RPC channel, if it has added it using
|nvim_set_client_info()| (optional).
- "buffer" buffer with connected |terminal| instance
(optional)
- "client" information about the client on the other end
of the RPC channel, if it has added it using
|nvim_set_client_info()|. (optional)
nvim_list_chans() *nvim_list_chans()*
Get information about all open channels.
@ -902,9 +916,9 @@ nvim_call_atomic({calls}) *nvim_call_atomic()*
This has two main usages:
1. To perform several requests from an async context
atomically, i.e. without interleaving redraws, RPC requests
from other clients, or user interactions (however API methods
may trigger autocommands or event processing which have such
side-effects, e.g. |:sleep| may wake timers).
from other clients, or user interactions (however API
methods may trigger autocommands or event processing which
have such side-effects, e.g. |:sleep| may wake timers).
2. To minimize RPC overhead (roundtrips) of a sequence of many
requests.
@ -914,13 +928,13 @@ nvim_call_atomic({calls}) *nvim_call_atomic()*
and an array of arguments.
Return: ~
an array with two elements. The first is an array of
return values. The second is NIL if all calls succeeded.
If a call resulted in an error, it is a three-element
array with the zero-based index of the call which resulted
in an error, the error type and the error message. If an
error occurred, the values from all preceding calls will
still be returned.
Array of two elements. The first is an array of return
values. The second is NIL if all calls succeeded. If a
call resulted in an error, it is a three-element array
with the zero-based index of the call which resulted in an
error, the error type and the error message. If an error
occurred, the values from all preceding calls will still
be returned.
*nvim_parse_expression()*
nvim_parse_expression({expr}, {flags}, {highlight})
@ -930,20 +944,24 @@ nvim_parse_expression({expr}, {flags}, {highlight})
{async}
Parameters: ~
{expr} Expression to parse. Is always treated as a
{expr} Expression to parse. Always treated as a
single line.
{flags} Flags: - "m" if multiple expressions in a
row are allowed (only the first one will be
parsed), - "E" if EOC tokens are not allowed
{flags} Flags:
- "m" if multiple expressions in a row are
allowed (only the first one will be
parsed),
- "E" if EOC tokens are not allowed
(determines whether they will stop parsing
process or be recognized as an
operator/space, though also yielding an
error). - "l" when needing to start parsing
with lvalues for ":let" or ":for". Common
flag sets: - "m" to parse like for ":echo". -
"E" to parse like for "<C-r>=". - empty
string for ":call". - "lm" to parse for
":let".
error).
- "l" when needing to start parsing with
lvalues for ":let" or ":for". Common flag
sets:
- "m" to parse like for ":echo".
- "E" to parse like for "<C-r>=".
- empty string for ":call".
- "lm" to parse for ":let".
{highlight} If true, return value will also include
"highlight" key containing array of 4-tuples
(arrays) (Integer, Integer, Integer, String),
@ -954,51 +972,66 @@ nvim_parse_expression({expr}, {flags}, {highlight})
[start_col, end_col)).
Return: ~
AST: top-level dictionary with these keys: "error":
Dictionary with error, present only if parser saw some
error. Contains the following keys: "message": String,
error message in printf format, translated. Must contain
exactly one "%.*s". "arg": String, error message argument.
"len": Amount of bytes successfully parsed. With flags
- AST: top-level dictionary with these keys:
- "error": Dictionary with error, present only if parser
saw some error. Contains the following keys:
- "message": String, error message in printf format,
translated. Must contain exactly one "%.*s".
- "arg": String, error message argument.
- "len": Amount of bytes successfully parsed. With flags
equal to "" that should be equal to the length of expr
string. @note: “Sucessfully parsed” here means
“participated in AST creation”, not “till the first
error”. "ast": AST, either nil or a dictionary with these
keys: "type": node type, one of the value names from
ExprASTNodeType stringified without "kExprNode" prefix.
"start": a pair [line, column] describing where node is
“started” where "line" is always 0 (will not be 0 if you
will be using nvim_parse_viml() on e.g. ":let", but that
is not present yet). Both elements are Integers. "len":
“length” of the node. This and "start" are there for
debugging purposes primary (debugging parser and providing
debug information). "children": a list of nodes described
in top/"ast". There always is zero, one or two children,
key will not be present if node has no children. Maximum
number of children may be found in node_maxchildren array.
Local values (present only for certain nodes): "scope": a
single Integer, specifies scope for "Option" and
"PlainIdentifier" nodes. For "Option" it is one of
ExprOptScope values, for "PlainIdentifier" it is one of
ExprVarScope values. "ident": identifier (without scope,
if any), present for "Option", "PlainIdentifier",
"PlainKey" and "Environment" nodes. "name": Integer,
register name (one character) or -1. Only present for
"Register" nodes. "cmp_type": String, comparison type, one
of the value names from ExprComparisonType, stringified
without "kExprCmp" prefix. Only present for "Comparison"
nodes. "ccs_strategy": String, case comparison strategy,
one of the value names from ExprCaseCompareStrategy,
stringified without "kCCStrategy" prefix. Only present for
"Comparison" nodes. "augmentation": String, augmentation
type for "Assignment" nodes. Is either an empty string,
"Add", "Subtract" or "Concat" for "=", "+=", "-=" or ".="
respectively. "invert": Boolean, true if result of
comparison needs to be inverted. Only present for
"Comparison" nodes. "ivalue": Integer, integer value for
"Integer" nodes. "fvalue": Float, floating-point value for
"Float" nodes. "svalue": String, value for
"SingleQuotedString" and "DoubleQuotedString" nodes.
string. (“Sucessfully parsed” here means “participated
in AST creation”, not “till the first error”.)
- "ast": AST, either nil or a dictionary with these
keys:
- "type": node type, one of the value names from
ExprASTNodeType stringified without "kExprNode"
prefix.
- "start": a pair [line, column] describing where node
is "started" where "line" is always 0 (will not be 0
if you will be using nvim_parse_viml() on e.g.
":let", but that is not present yet). Both elements
are Integers.
- "len": “length” of the node. This and "start" are
there for debugging purposes primary (debugging
parser and providing debug information).
- "children": a list of nodes described in top/"ast".
There always is zero, one or two children, key will
not be present if node has no children. Maximum
number of children may be found in node_maxchildren
array.
- Local values (present only for certain nodes):
- "scope": a single Integer, specifies scope for
"Option" and "PlainIdentifier" nodes. For "Option" it
is one of ExprOptScope values, for "PlainIdentifier"
it is one of ExprVarScope values.
- "ident": identifier (without scope, if any), present
for "Option", "PlainIdentifier", "PlainKey" and
"Environment" nodes.
- "name": Integer, register name (one character) or -1.
Only present for "Register" nodes.
- "cmp_type": String, comparison type, one of the value
names from ExprComparisonType, stringified without
"kExprCmp" prefix. Only present for "Comparison"
nodes.
- "ccs_strategy": String, case comparison strategy, one
of the value names from ExprCaseCompareStrategy,
stringified without "kCCStrategy" prefix. Only present
for "Comparison" nodes.
- "augmentation": String, augmentation type for
"Assignment" nodes. Is either an empty string, "Add",
"Subtract" or "Concat" for "=", "+=", "-=" or ".="
respectively.
- "invert": Boolean, true if result of comparison needs
to be inverted. Only present for "Comparison" nodes.
- "ivalue": Integer, integer value for "Integer" nodes.
- "fvalue": Float, floating-point value for "Float"
nodes.
- "svalue": String, value for "SingleQuotedString" and
"DoubleQuotedString" nodes.
nvim__id({obj}) *nvim__id()*
Returns object given as argument.
@ -1058,14 +1091,13 @@ nvim_list_uis() *nvim_list_uis()*
Gets a list of dictionaries representing attached UIs.
Return: ~
Array of UI dictionaries. Each dictionary has the
following keys:
`height`: requested height of the UI
`width`: requested width of the UI
`rgb`: whether the UI uses rgb colors
(false implies cterm colors)
`ext_...`: Requested UI extensions, see |ui-options|
`chan`: Channel id of remote UI (not present for TUI)
Array of UI dictionaries, each with these keys:
- "height" requested height of the UI
- "width" requested width of the UI
- "rgb" whether the UI uses rgb colors (false implies
cterm colors)
- "ext_..." Requested UI extensions, see |ui-options|
- "chan" Channel id of remote UI (not present for TUI)
nvim_get_proc_children({pid}) *nvim_get_proc_children()*
Gets the immediate children of process `pid` .
@ -1123,7 +1155,7 @@ nvim_buf_line_count({buffer}) *nvim_buf_line_count()*
Gets the buffer line count
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
Return: ~
Line count, or 0 for unloaded buffer. |api-buffer|
@ -1132,7 +1164,7 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
Activate updates from this buffer to the current channel.
Parameters: ~
{buffer} The buffer handle
{buffer} Buffer handle, or 0 for current buffer
{send_buffer} Set to true if the initial notification
should contain the whole buffer. If so, the
first notification will be a
@ -1144,14 +1176,14 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
Return: ~
False when updates couldn't be enabled because the buffer
isn't loaded or optscontained an invalid key; otherwise
isn't loaded or `opts` contained an invalid key; otherwise
True.
nvim_buf_detach({buffer}) *nvim_buf_detach()*
Deactivate updates from this buffer to the current channel.
Parameters: ~
{buffer} The buffer handle
{buffer} Buffer handle, or 0 for current buffer
Return: ~
False when updates couldn't be disabled because the buffer
@ -1169,7 +1201,7 @@ nvim_buf_get_lines({buffer}, {start}, {end}, {strict_indexing})
unless `strict_indexing` is set.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{start} First line index
{end} Last line index (exclusive)
{strict_indexing} Whether out-of-bounds should be an
@ -1196,7 +1228,7 @@ nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing},
unless `strict_indexing` is set.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{start} First line index
{end} Last line index (exclusive)
{strict_indexing} Whether out-of-bounds should be an
@ -1216,7 +1248,7 @@ nvim_buf_get_offset({buffer}, {index}) *nvim_buf_get_offset()*
Returns -1 for unloaded buffer.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{index} Line index
Return: ~
@ -1226,7 +1258,7 @@ nvim_buf_get_var({buffer}, {name}) *nvim_buf_get_var()*
Gets a buffer-scoped (b:) variable.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{name} Variable name
Return: ~
@ -1236,17 +1268,17 @@ nvim_buf_get_changedtick({buffer}) *nvim_buf_get_changedtick()*
Gets a changed tick of a buffer
Parameters: ~
{buffer} Buffer handle.
{buffer} Buffer handle, or 0 for current buffer
Return: ~
b:changedtickvalue.
`b:changedtick` value.
nvim_buf_get_keymap({buffer}, {mode}) *nvim_buf_get_keymap()*
Gets a list of buffer-local |mapping| definitions.
Parameters: ~
{mode} Mode short-name ("n", "i", "v", ...)
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
Return: ~
Array of maparg()-like dictionaries describing mappings.
@ -1256,7 +1288,7 @@ nvim_buf_get_commands({buffer}, {opts}) *nvim_buf_get_commands()*
Gets a map of buffer-local |user-commands|.
Parameters: ~
{buffer} Buffer handle.
{buffer} Buffer handle, or 0 for current buffer
{opts} Optional parameters. Currently not used.
Return: ~
@ -1266,7 +1298,7 @@ nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()*
Sets a buffer-scoped (b:) variable
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{name} Variable name
{value} Variable value
@ -1274,14 +1306,14 @@ nvim_buf_del_var({buffer}, {name}) *nvim_buf_del_var()*
Removes a buffer-scoped (b:) variable
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{name} Variable name
nvim_buf_get_option({buffer}, {name}) *nvim_buf_get_option()*
Gets a buffer option value
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{name} Option name
Return: ~
@ -1292,7 +1324,7 @@ nvim_buf_set_option({buffer}, {name}, {value}) *nvim_buf_set_option()*
option (only works if there's a global fallback)
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{name} Option name
{value} Option value
@ -1300,7 +1332,7 @@ nvim_buf_get_name({buffer}) *nvim_buf_get_name()*
Gets the full file name for the buffer
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
Return: ~
Buffer name
@ -1309,7 +1341,7 @@ nvim_buf_set_name({buffer}, {name}) *nvim_buf_set_name()*
Sets the full file name for a buffer
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{name} Buffer name
nvim_buf_is_loaded({buffer}) *nvim_buf_is_loaded()*
@ -1317,7 +1349,7 @@ nvim_buf_is_loaded({buffer}) *nvim_buf_is_loaded()*
more info about unloaded buffers.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
Return: ~
true if the buffer is valid and loaded, false otherwise.
@ -1330,7 +1362,7 @@ nvim_buf_is_valid({buffer}) *nvim_buf_is_valid()*
|api-buffer| for more info about unloaded buffers.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
Return: ~
true if the buffer is valid, false otherwise.
@ -1340,7 +1372,7 @@ nvim_buf_get_mark({buffer}, {name}) *nvim_buf_get_mark()*
named mark
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{name} Mark name
Return: ~
@ -1374,7 +1406,7 @@ nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line},
|nvim_create_namespace| to create a new empty namespace.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{ns_id} namespace to use or -1 for ungrouped
highlight
{hl_group} Name of the highlight group to use
@ -1396,7 +1428,7 @@ nvim_buf_clear_namespace({buffer}, {ns_id}, {line_start}, {line_end})
to line_start and line_end respectively.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{ns_id} Namespace to clear, or -1 to clear all
namespaces.
{line_start} Start of range of lines to clear
@ -1427,7 +1459,7 @@ nvim_buf_set_virtual_text({buffer}, {ns_id}, {line}, {chunks}, {opts})
returned.
Parameters: ~
{buffer} Buffer handle
{buffer} Buffer handle, or 0 for current buffer
{ns_id} Namespace to use or 0 to create a namespace, or
-1 for a ungrouped annotation
{line} Line to annotate with virtual text
@ -1636,9 +1668,6 @@ nvim_win_close({window}, {force}) *nvim_win_close()*
buffer will become hidden, even if 'hidden' is
not set.
Return: ~
Window number
==============================================================================
Tabpage Functions *api-tabpage*
@ -1650,7 +1679,7 @@ nvim_tabpage_list_wins({tabpage}) *nvim_tabpage_list_wins()*
{tabpage} Tabpage
Return: ~
List of windows in tabpage
List of windows in `tabpage`
nvim_tabpage_get_var({tabpage}, {name}) *nvim_tabpage_get_var()*
Gets a tab-scoped (t:) variable

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Parses Doxygen XML output to generate Neovim's API documentation.
"""Generates Nvim help docs from C docstrings, by parsing Doxygen XML.
This would be easier using lxml and XSLT, but:
@ -35,6 +35,8 @@ import sys
import shutil
import textwrap
import subprocess
import collections
import pprint
from xml.dom import minidom
@ -42,6 +44,10 @@ if sys.version_info[0] < 3:
print("use Python 3")
sys.exit(1)
DEBUG = ('DEBUG' in os.environ)
INCLUDE_C_DECL = ('INCLUDE_C_DECL' in os.environ)
INCLUDE_DEPRECATED = ('INCLUDE_DEPRECATED' in os.environ)
doc_filename = 'api.txt'
# String used to find the start of the generated part of the doc.
section_start_token = '*api-global*'
@ -83,6 +89,12 @@ seen_funcs = set()
# deprecated functions.
xrefs = set()
def debug_this(s, n):
o = n if isinstance(n, str) else n.toprettyxml(indent=' ', newl='\n')
name = '' if isinstance(n, str) else n.nodeName
if s in o:
raise RuntimeError('xxx: {}\n{}'.format(name, o))
# XML Parsing Utilities {{{
def find_first(parent, name):
@ -123,6 +135,10 @@ def clean_lines(text):
return re.sub(r'\A\n\s*\n*|\n\s*\n*\Z', '', re.sub(r'(\n\s*\n+)+', '\n\n', text))
def is_blank(text):
return '' == clean_lines(text)
def get_text(parent):
"""Combine all text in a node."""
if parent.nodeType == parent.TEXT_NODE:
@ -137,16 +153,43 @@ def get_text(parent):
return out
def doc_wrap(text, prefix='', width=70, func=False):
# Gets the length of the last line in `text`, excluding newline ("\n") char.
def len_lastline(text):
lastnl = text.rfind('\n')
if -1 == lastnl:
return len(text)
if '\n' == text[-1]:
return lastnl - (1+ text.rfind('\n', 0, lastnl))
return len(text) - (1 + lastnl)
def len_lastline_withoutindent(text, indent):
n = len_lastline(text)
return (n - len(indent)) if n > len(indent) else 0
# Returns True if node `n` contains only inline (not block-level) elements.
def is_inline(n):
for c in n.childNodes:
if c.nodeType != c.TEXT_NODE and c.nodeName != 'computeroutput':
return False
if not is_inline(c):
return False
return True
def doc_wrap(text, prefix='', width=70, func=False, indent=None):
"""Wraps text to `width`.
The first line is prefixed with `prefix`, and subsequent lines are aligned.
First line is prefixed with `prefix`, subsequent lines are aligned.
If `func` is True, only wrap at commas.
"""
if not width:
# return prefix + text
return text
indent_space = ' ' * len(prefix)
# Whitespace used to indent all lines except the first line.
indent = ' ' * len(prefix) if indent is None else indent
indent_only = (prefix == '' and indent is not None)
if func:
lines = [prefix]
@ -154,27 +197,37 @@ def doc_wrap(text, prefix='', width=70, func=False):
if part[-1] not in ');':
part += ', '
if len(lines[-1]) + len(part) > width:
lines.append(indent_space)
lines.append(indent)
lines[-1] += part
return '\n'.join(x.rstrip() for x in lines).rstrip()
# XXX: Dummy prefix to force TextWrapper() to wrap the first line.
if indent_only:
prefix = indent
tw = textwrap.TextWrapper(break_long_words = False,
break_on_hyphens = False,
width=width,
initial_indent=prefix,
subsequent_indent=indent_space)
return '\n'.join(tw.wrap(text.strip()))
subsequent_indent=indent)
result = '\n'.join(tw.wrap(text.strip()))
# XXX: Remove the dummy prefix.
if indent_only:
result = result[len(indent):]
return result
def parse_params(parent, width=62):
"""Parse Doxygen `parameterlist`."""
def render_params(parent, width=62):
"""Renders Doxygen <parameterlist> tag as Vim help text."""
name_length = 0
items = []
for child in parent.childNodes:
if child.nodeType == child.TEXT_NODE:
for node in parent.childNodes:
if node.nodeType == node.TEXT_NODE:
continue
name_node = find_first(child, 'parametername')
name_node = find_first(node, 'parametername')
if name_node.getAttribute('direction') == 'out':
continue
@ -184,79 +237,152 @@ def parse_params(parent, width=62):
name = '{%s}' % name
name_length = max(name_length, len(name) + 2)
items.append((name.strip(), node))
out = ''
for name, node in items:
name = ' {}'.format(name.ljust(name_length))
desc = ''
desc_node = get_child(child, 'parameterdescription')
desc_node = get_child(node, 'parameterdescription')
if desc_node:
desc = parse_parblock(desc_node, width=None)
items.append((name.strip(), desc.strip()))
desc = parse_parblock(desc_node, width=width,
indent=(' ' * len(name)))
out = 'Parameters: ~\n'
for name, desc in items:
name = ' %s' % name.ljust(name_length)
out += doc_wrap(desc, prefix=name, width=width) + '\n'
return out.strip()
out += '{}{}\n'.format(name, desc)
return out.rstrip()
# Renders a node as Vim help text, recursively traversing all descendants.
def render_node(n, text, prefix='', indent='', width=62):
text = ''
# space_preceding = (len(text) > 0 and ' ' == text[-1][-1])
# text += (int(not space_preceding) * ' ')
def parse_para(parent, width=62):
"""Parse doxygen `para` tag.
I assume <para> is a paragraph block or "a block of text". It can contain
text nodes, or other tags.
"""
line = ''
lines = []
for child in parent.childNodes:
if child.nodeType == child.TEXT_NODE:
line += child.data
elif child.nodeName == 'computeroutput':
line += '`%s`' % get_text(child)
if n.nodeType == n.TEXT_NODE:
# `prefix` is NOT sent to doc_wrap, it was already handled by now.
text += doc_wrap(n.data, indent=indent, width=width)
elif n.nodeName == 'computeroutput':
text += ' `{}` '.format(get_text(n))
elif is_inline(n):
for c in n.childNodes:
text += render_node(c, text)
text = doc_wrap(text, indent=indent, width=width)
elif n.nodeName == 'verbatim':
# TODO: currently we don't use this. The "[verbatim]" hint is there as
# a reminder that we must decide how to format this if we do use it.
text += ' [verbatim] {}'.format(get_text(n))
elif n.nodeName == 'listitem':
for c in n.childNodes:
text += indent + prefix + render_node(c, text, indent=indent+(' ' * len(prefix)), width=width)
elif n.nodeName == 'para':
for c in n.childNodes:
text += render_node(c, text, indent=indent, width=width)
if is_inline(n):
text = doc_wrap(text, indent=indent, width=width)
elif n.nodeName == 'itemizedlist':
for c in n.childNodes:
text += '{}\n'.format(render_node(c, text, prefix='- ',
indent=indent, width=width))
elif n.nodeName == 'orderedlist':
i = 1
for c in n.childNodes:
if is_blank(get_text(c)):
text += '\n'
continue
text += '{}\n'.format(render_node(c, text, prefix='{}. '.format(i),
indent=indent, width=width))
i = i + 1
elif n.nodeName == 'simplesect' and 'note' == n.getAttribute('kind'):
text += 'Note:\n '
for c in n.childNodes:
text += render_node(c, text, indent=' ', width=width)
text += '\n'
elif n.nodeName == 'simplesect' and 'warning' == n.getAttribute('kind'):
text += 'Warning:\n '
for c in n.childNodes:
text += render_node(c, text, indent=' ', width=width)
text += '\n'
elif (n.nodeName == 'simplesect'
and n.getAttribute('kind') in ('return', 'see')):
text += ' '
for c in n.childNodes:
text += render_node(c, text, indent=' ', width=width)
else:
if line:
lines.append(doc_wrap(line, width=width))
line = ''
raise RuntimeError('unhandled node type: {}\n{}'.format(
n.nodeName, n.toprettyxml(indent=' ', newl='\n')))
return text
def render_para(parent, indent='', width=62):
"""Renders Doxygen <para> containing arbitrary nodes.
NB: Blank lines in a docstring manifest as <para> tags.
"""
if is_inline(parent):
return clean_lines(doc_wrap(render_node(parent, ''),
indent=indent, width=width).strip())
# Ordered dict of ordered lists.
groups = collections.OrderedDict([
('params', []),
('return', []),
('seealso', []),
('xrefs', []),
])
# Gather nodes into groups. Mostly this is because we want "parameterlist"
# nodes to appear together.
text = ''
kind = ''
last = ''
for child in parent.childNodes:
if child.nodeName == 'parameterlist':
lines.append(parse_params(child, width=width))
groups['params'].append(child)
elif child.nodeName == 'xrefsect':
groups['xrefs'].append(child)
elif child.nodeName == 'simplesect':
last = kind
kind = child.getAttribute('kind')
if kind == 'return' or (kind == 'note' and last == 'return'):
groups['return'].append(child)
elif kind == 'see':
groups['seealso'].append(child)
elif kind in ('note', 'warning'):
text += render_node(child, text, indent=indent, width=width)
else:
raise RuntimeError('unhandled simplesect: {}\n{}'.format(
child.nodeName, child.toprettyxml(indent=' ', newl='\n')))
else:
text += render_node(child, text, indent=indent, width=width)
chunks = [text]
# Generate text from the gathered items.
if len(groups['params']) > 0:
chunks.append('\nParameters: ~')
for child in groups['params']:
chunks.append(render_params(child, width=width))
if len(groups['return']) > 0:
chunks.append('\nReturn: ~')
for child in groups['return']:
chunks.append(render_node(child, chunks[-1][-1], indent=indent, width=width))
if len(groups['seealso']) > 0:
chunks.append('\nSee also: ~')
for child in groups['seealso']:
chunks.append(render_node(child, chunks[-1][-1], indent=indent, width=width))
for child in groups['xrefs']:
title = get_text(get_child(child, 'xreftitle'))
xrefs.add(title)
xrefdesc = parse_para(get_child(child, 'xrefdescription'))
lines.append(doc_wrap(xrefdesc, prefix='%s: ' % title,
xrefdesc = render_para(get_child(child, 'xrefdescription'), width=width)
chunks.append(doc_wrap(xrefdesc, prefix='{}: '.format(title),
width=width) + '\n')
elif child.nodeName == 'simplesect':
kind = child.getAttribute('kind')
if kind == 'note':
lines.append('Note:')
lines.append(doc_wrap(parse_para(child),
prefix=' ',
width=width))
elif kind == 'return':
lines.append('%s: ~' % kind.title())
lines.append(doc_wrap(parse_para(child),
prefix=' ',
width=width))
else:
lines.append(get_text(child))
if line:
lines.append(doc_wrap(line, width=width))
return clean_lines('\n'.join(lines).strip())
return clean_lines('\n'.join(chunks).strip())
def parse_parblock(parent, width=62):
"""Parses a nested block of `para` tags.
Named after the \parblock command, but not directly related.
"""
def parse_parblock(parent, prefix='', width=62, indent=''):
"""Renders a nested block of <para> tags as Vim help text."""
paragraphs = []
for child in parent.childNodes:
if child.nodeType == child.TEXT_NODE:
paragraphs.append(doc_wrap(child.data, width=width))
elif child.nodeName == 'para':
paragraphs.append(parse_para(child, width=width))
else:
paragraphs.append(doc_wrap(get_text(child), width=width))
paragraphs.append(render_para(child, width=width, indent=indent))
paragraphs.append('')
return clean_lines('\n'.join(paragraphs).strip())
# }}}
@ -292,7 +418,7 @@ def parse_source_xml(filename):
if return_type.startswith(('ArrayOf', 'DictionaryOf')):
parts = return_type.strip('_').split('_')
return_type = '%s(%s)' % (parts[0], ', '.join(parts[1:]))
return_type = '{}({})'.format(parts[0], ', '.join(parts[1:]))
name = get_text(get_child(member, 'name'))
@ -306,37 +432,37 @@ def parse_source_xml(filename):
annotations = filter(None, map(lambda x: annotation_map.get(x),
annotations.split()))
vimtag = '*%s()*' % name
args = []
vimtag = '*{}()*'.format(name)
params = []
type_length = 0
for param in get_children(member, 'param'):
arg_type = get_text(get_child(param, 'type')).strip()
arg_name = ''
param_type = get_text(get_child(param, 'type')).strip()
param_name = ''
declname = get_child(param, 'declname')
if declname:
arg_name = get_text(declname).strip()
param_name = get_text(declname).strip()
if arg_name in param_exclude:
if param_name in param_exclude:
continue
if arg_type.endswith('*'):
arg_type = arg_type.strip('* ')
arg_name = '*' + arg_name
type_length = max(type_length, len(arg_type))
args.append((arg_type, arg_name))
if param_type.endswith('*'):
param_type = param_type.strip('* ')
param_name = '*' + param_name
type_length = max(type_length, len(param_type))
params.append((param_type, param_name))
c_args = []
for arg_type, arg_name in args:
for param_type, param_name in params:
c_args.append(' ' + (
'%s %s' % (arg_type.ljust(type_length), arg_name)).strip())
'%s %s' % (param_type.ljust(type_length), param_name)).strip())
c_decl = textwrap.indent('%s %s(\n%s\n);' % (return_type, name,
',\n'.join(c_args)),
' ')
prefix = '%s(' % name
suffix = '%s)' % ', '.join('{%s}' % a[1] for a in args
suffix = '%s)' % ', '.join('{%s}' % a[1] for a in params
if a[0] not in ('void', 'Error'))
# Minimum 8 chars between signature and vimtag
@ -354,7 +480,7 @@ def parse_source_xml(filename):
desc = find_first(member, 'detaileddescription')
if desc:
doc = parse_parblock(desc)
if 'DEBUG' in os.environ:
if DEBUG:
print(textwrap.indent(
re.sub(r'\n\s*\n+', '\n',
desc.toprettyxml(indent=' ', newl='\n')), ' ' * 16))
@ -372,7 +498,7 @@ def parse_source_xml(filename):
else:
doc = doc[:i] + annotations + '\n\n' + doc[i:]
if 'INCLUDE_C_DECL' in os.environ:
if INCLUDE_C_DECL:
doc += '\n\nC Declaration: ~\n>\n'
doc += c_decl
doc += '\n<'
@ -464,7 +590,7 @@ def gen_docs(config):
if functions:
doc += '\n\n' + functions
if 'INCLUDE_DEPRECATED' in os.environ and deprecated:
if INCLUDE_DEPRECATED and deprecated:
doc += '\n\n\nDeprecated %s Functions: ~\n\n' % name
doc += deprecated
@ -551,6 +677,7 @@ XML_PROGRAMLISTING = NO
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
MARKDOWN_SUPPORT = YES
'''
# }}}