fix(docs): make lines not overflow in vim docs

Problem: Some lines in the generated vim doc are overflowing, not
correctly wrapped at 78 characters. This happens when docs body contains
several consecutive 'inline' elements generated by doxygen.

Solution: Take into account the current column offset of the last line,
and prepend some padding before doc_wrap().
This commit is contained in:
Jongwook Choi 2024-01-04 11:09:13 -05:00 committed by Lewis Russell
parent d54156ed08
commit f40df63bdc
7 changed files with 122 additions and 68 deletions

View File

@ -1277,7 +1277,8 @@ nvim_paste({data}, {crlf}, {phase}) *nvim_paste()*
• {data} Multiline input. May be binary (containing NUL bytes).
• {crlf} Also break lines at CR and CRLF.
• {phase} -1: paste in a single call (i.e. without streaming). To
"stream" a paste, call `nvim_paste` sequentially with these `phase` values:
"stream" a paste, call `nvim_paste` sequentially
with these `phase` values:
• 1: starts the paste (exactly once)
• 2: continues the paste (zero or more times)
• 3: ends the paste (exactly once)
@ -2095,7 +2096,8 @@ nvim_buf_attach({buffer}, {send_buffer}, {*opts}) *nvim_buf_attach()*
will be `nvim_buf_changedtick_event`. Not for Lua
callbacks.
• {opts} Optional parameters.
• on_lines: Lua callback invoked on change. Return `true` to detach. Args:
• on_lines: Lua callback invoked on change. Return `true` to
detach. Args:
• the string "lines"
• buffer handle
• b:changedtick
@ -2108,7 +2110,8 @@ nvim_buf_attach({buffer}, {send_buffer}, {*opts}) *nvim_buf_attach()*
• on_bytes: Lua callback invoked on change. This
callback receives more granular information about the
change compared to on_lines. Return `true` to detach. Args:
change compared to on_lines. Return `true` to
detach. Args:
• the string "bytes"
• buffer handle
• b:changedtick
@ -2704,7 +2707,8 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts})
wrapped lines.
• hl_mode : control how highlights are combined with the
highlights of the text. Currently only affects virt_text
highlights, but might affect `hl_group` in later versions.
highlights, but might affect `hl_group` in
later versions.
• "replace": only show the virt_text color. This is the
default.
• "combine": combine with background text color.
@ -3141,8 +3145,8 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
• height: Window height (in character cells). Minimum of 1.
• bufpos: Places float relative to buffer text (only when
relative="win"). Takes a tuple of zero-indexed [line,
column]. `row` and `col` if given are applied relative to this position, else they
default to:
column]. `row` and `col` if given are
applied relative to this position, else they default to:
• `row=1` and `col=0` if `anchor` is "NW" or "NE"
• `row=0` and `col=0` if `anchor` is "SW" or "SE" (thus
like a tooltip near the buffer text).
@ -3157,8 +3161,9 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
• external: GUI should display the window as an external
top-level window. Currently accepts no other positioning
configuration together with this.
• zindex: Stacking order. floats with higher `zindex` go on top on floats with lower indices. Must be larger
than zero. The following screen elements have hard-coded
• zindex: Stacking order. floats with higher `zindex` go on
top on floats with lower indices. Must be larger than
zero. The following screen elements have hard-coded
z-indices:
• 100: insert completion popupmenu
• 200: message scrollback
@ -3351,7 +3356,8 @@ nvim_clear_autocmds({*opts}) *nvim_clear_autocmds()*
• NOTE: Cannot be used with {pattern}
• group: (string|int) The augroup name or id.
• NOTE: If not passed, will only delete autocmds not in any group.
• NOTE: If not passed, will only delete autocmds not in any
group.
nvim_create_augroup({name}, {*opts}) *nvim_create_augroup()*
Create or get an autocommand group |autocmd-groups|.
@ -3375,7 +3381,9 @@ nvim_create_augroup({name}, {*opts}) *nvim_create_augroup()*
• |autocmd-groups|
nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()*
Creates an |autocommand| event handler, defined by `callback` (Lua function or Vimscript function name string) or `command` (Ex command string).
Creates an |autocommand| event handler, defined by `callback` (Lua
function or Vimscript function name string) or `command` (Ex command
string).
Example using Lua callback: >lua
vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {

View File

@ -541,7 +541,9 @@ get({bufnr}, {opts}) *vim.diagnostic.get()*
• severity: See |diagnostic-severity|.
Return: ~
Diagnostic [] table A list of diagnostic items |diagnostic-structure|. Keys `bufnr` , `end_lnum` , `end_col` , and `severity` are guaranteed to be present.
Diagnostic [] table A list of diagnostic items |diagnostic-structure|.
Keys `bufnr` , `end_lnum` , `end_col` , and `severity` are
guaranteed to be present.
get_namespace({namespace}) *vim.diagnostic.get_namespace()*
Get namespace metadata.
@ -634,8 +636,8 @@ hide({namespace}, {bufnr}) *vim.diagnostic.hide()*
|vim.diagnostic.disable()|.
Parameters: ~
• {namespace} (integer|nil) Diagnostic namespace. When omitted, hide diagnostics from all
namespaces.
• {namespace} (integer|nil) Diagnostic namespace. When omitted, hide
diagnostics from all namespaces.
• {bufnr} (integer|nil) Buffer number, or 0 for current buffer.
When omitted, hide diagnostics in all buffers.
@ -644,9 +646,9 @@ is_disabled({bufnr}, {namespace}) *vim.diagnostic.is_disabled()*
Parameters: ~
• {bufnr} (integer|nil) Buffer number, or 0 for current buffer.
• {namespace} (integer|nil) Diagnostic namespace. When omitted, checks if all diagnostics are
disabled in {bufnr}. Otherwise, only checks if
diagnostics from {namespace} are disabled.
• {namespace} (integer|nil) Diagnostic namespace. When omitted, checks
if all diagnostics are disabled in {bufnr}. Otherwise,
only checks if diagnostics from {namespace} are disabled.
Return: ~
(boolean)
@ -746,8 +748,8 @@ reset({namespace}, {bufnr}) *vim.diagnostic.reset()*
re-displayed, use |vim.diagnostic.hide()|.
Parameters: ~
• {namespace} (integer|nil) Diagnostic namespace. When omitted, remove diagnostics from all
namespaces.
• {namespace} (integer|nil) Diagnostic namespace. When omitted, remove
diagnostics from all namespaces.
• {bufnr} (integer|nil) Remove diagnostics for the given buffer.
When omitted, diagnostics are removed for all buffers.
@ -795,8 +797,8 @@ show({namespace}, {bufnr}, {diagnostics}, {opts})
Display diagnostics for the given namespace and buffer.
Parameters: ~
• {namespace} (integer|nil) Diagnostic namespace. When omitted, show diagnostics from all
namespaces.
• {namespace} (integer|nil) Diagnostic namespace. When omitted, show
diagnostics from all namespaces.
• {bufnr} (integer|nil) Buffer number, or 0 for current buffer.
When omitted, show diagnostics in all buffers.
• {diagnostics} (table|nil) The diagnostics to display. When omitted,

View File

@ -1128,7 +1128,8 @@ code_action({options}) *vim.lsp.buf.code_action()*
Parameters: ~
• {options} (table|nil) Optional table which holds the following
optional fields:
• context: (table|nil) Corresponds to `CodeActionContext` of the LSP specification:
• context: (table|nil) Corresponds to `CodeActionContext` of
the LSP specification:
• diagnostics (table|nil): LSP `Diagnostic[]`. Inferred
from the current position if not provided.
• only (table|nil): List of LSP `CodeActionKind`s used to
@ -1510,7 +1511,8 @@ get({filter}) *vim.lsp.inlay_hint.get()*
• range (lsp.Range?)
Return: ~
vim.lsp.inlay_hint.get.ret [] Each list item is a table with the following fields:
vim.lsp.inlay_hint.get.ret [] Each list item is a table with the
following fields:
• bufnr (integer)
• client_id (integer)
• inlay_hint (lsp.InlayHint)
@ -2090,8 +2092,9 @@ connect({host}, {port}) *vim.lsp.rpc.connect()*
• {port} (integer) port to connect to
Return: ~
fun(dispatchers: vim.lsp.rpc.Dispatchers ): vim.lsp.rpc.PublicClient function intended to be passed to |vim.lsp.start_client()| or
|vim.lsp.start()| on the field cmd
fun(dispatchers: vim.lsp.rpc.Dispatchers ): vim.lsp.rpc.PublicClient function
intended to be passed to |vim.lsp.start_client()| or |vim.lsp.start()|
on the field cmd
*vim.lsp.rpc.domain_socket_connect()*
domain_socket_connect({pipe_path})
@ -2104,7 +2107,8 @@ domain_socket_connect({pipe_path})
the named pipe (Windows) to connect to
Return: ~
fun(dispatchers: vim.lsp.rpc.Dispatchers ): vim.lsp.rpc.PublicClient::function intended to be passed to
fun(dispatchers: vim.lsp.rpc.Dispatchers ):
vim.lsp.rpc.PublicClient::function intended to be passed to
|vim.lsp.start_client()| or |vim.lsp.start()| on the field cmd
format_rpc_error({err}) *vim.lsp.rpc.format_rpc_error()*

View File

@ -680,8 +680,10 @@ vim.regex:match_line({bufnr}, {line_idx}, {start}, {end_})
vim.regex:match_str({str}) *regex:match_str()*
Match the string against the regex. If the string should match the regex
precisely, surround the regex with `^` and `$` . If there was a match, the byte indices for the beginning and end of the
match are returned. When there is no match, `nil` is returned. Because any integer is "truthy", `regex:match_str()` can be directly used as a condition in an if-statement.
precisely, surround the regex with `^` and `$` . If there was a match, the
byte indices for the beginning and end of the match are returned. When
there is no match, `nil` is returned. Because any integer is "truthy", `regex:match_str()` can
be directly used as a condition in an if-statement.
Parameters: ~
• {str} (string)
@ -713,9 +715,9 @@ vim.diff({a}, {b}, {opts}) *vim.diff()*
• {a} (string) First string to compare
• {b} (string) Second string to compare
• {opts} table<string,any> Optional parameters:
• `on_hunk` (callback): Invoked for each hunk in the diff. Return a
negative number to cancel the callback for any remaining
hunks. Args:
• `on_hunk` (callback): Invoked for each hunk in the diff.
Return a negative number to cancel the callback for any
remaining hunks. Args:
• `start_a` (integer): Start line of hunk in {a}.
• `count_a` (integer): Hunk size in {a}.
• `start_b` (integer): Start line of hunk in {b}.
@ -858,7 +860,8 @@ vim.spell.check({str}) *vim.spell.check()*
• {str} (string)
Return: ~
`{[1]: string, [2]: string, [3]: string}[]` List of tuples with three items:
`{[1]: string, [2]: string, [3]: string}[]` List of tuples with three
items:
• The badly spelled word.
• The type of the spelling error: "bad" spelling mistake "rare" rare
word "local" word only valid in another region "caps" word should
@ -1581,7 +1584,8 @@ vim.deprecate({name}, {alternative}, {version}, {plugin}, {backtrace})
Parameters: ~
• {name} string Deprecated feature (function, API, etc.).
• {alternative} (string|nil) Suggested alternative feature.
• {version} string Version when the deprecated function will be removed.
• {version} string Version when the deprecated function will be
removed.
• {plugin} string|nil Name of the plugin that owns the deprecated
feature. Defaults to "Nvim".
• {backtrace} boolean|nil Prints backtrace. Defaults to true.
@ -1692,7 +1696,8 @@ vim.paste({lines}, {phase}) *vim.paste()*
• {lines} string[] # |readfile()|-style list of lines to paste.
|channel-lines|
• {phase} paste_phase -1: "non-streaming" paste: the call contains all
lines. If paste is "streamed", `phase` indicates the stream state:
lines. If paste is "streamed", `phase` indicates
the stream state:
• 1: starts the paste (exactly once)
• 2: continues the paste (zero or more times)
• 3: ends the paste (exactly once)
@ -1896,7 +1901,8 @@ vim.show_pos({bufnr}, {row}, {col}, {filter}) *vim.show_pos()*
vim.deep_equal({a}, {b}) *vim.deep_equal()*
Deep compare values for equality
Tables are compared recursively unless they both provide the `eq` metamethod. All other types are compared using the equality `==` operator.
Tables are compared recursively unless they both provide the `eq` metamethod.
All other types are compared using the equality `==` operator.
Parameters: ~
• {a} any First value
@ -2276,7 +2282,8 @@ vim.tbl_get({o}, {...}) *vim.tbl_get()*
any Nested value indexed by key (if it exists), else nil
vim.tbl_isarray({t}) *vim.tbl_isarray()*
Tests if `t` is an "array": a table indexed only by integers (potentially non-contiguous).
Tests if `t` is an "array": a table indexed only by integers (potentially
non-contiguous).
If the indexes start from 1 and are contiguous then the array is also a
list. |vim.tbl_islist()|
@ -2307,8 +2314,8 @@ vim.tbl_isempty({t}) *vim.tbl_isempty()*
• https://github.com/premake/premake-core/blob/master/src/base/table.lua
vim.tbl_islist({t}) *vim.tbl_islist()*
Tests if `t` is a "list": a table indexed only by contiguous integers starting from 1 (what |lua-length| calls a "regular
array").
Tests if `t` is a "list": a table indexed only by contiguous integers
starting from 1 (what |lua-length| calls a "regular array").
Empty table `{}` is a list, unless it was created by |vim.empty_dict()| or
returned as a dict-like |API| or Vimscript result, for example from
@ -3150,7 +3157,8 @@ vim.version.cmp({v1}, {v2}) *vim.version.cmp()*
(integer) -1 if `v1 < v2`, 0 if `v1 == v2`, 1 if `v1 > v2`.
vim.version.eq({v1}, {v2}) *vim.version.eq()*
Returns `true` if the given versions are equal. See |vim.version.cmp()| for usage.
Returns `true` if the given versions are equal. See |vim.version.cmp()|
for usage.
Parameters: ~
• {v1} Version|number[]
@ -3204,7 +3212,8 @@ vim.version.parse({version}, {opts}) *vim.version.parse()*
"1.0", "0-x", "tmux 3.2a" into valid versions.
Return: ~
(table|nil) parsed_version Version object or `nil` if input is invalid.
(table|nil) parsed_version Version object or `nil` if input is
invalid.
See also: ~
• # https://semver.org/spec/v2.0.0.html
@ -3762,7 +3771,8 @@ vim.snippet.exit() *vim.snippet.exit()*
Exits the current snippet.
vim.snippet.expand({input}) *vim.snippet.expand()*
Expands the given snippet text. Refer to https://microsoft.github.io/language-server-protocol/specification/#snippet_syntax for the specification of valid input.
Expands the given snippet text. Refer to https://microsoft.github.io/language-server-protocol/specification/#snippet_syntax for
the specification of valid input.
Tabstops are highlighted with hl-SnippetTabstop.

View File

@ -936,7 +936,8 @@ lint({buf}, {opts}) *vim.treesitter.query.lint()*
The found diagnostics are reported using |diagnostic-api|. By default, the
parser used for verification is determined by the containing folder of the
query file, e.g., if the path ends in `/lua/highlights.scm` , the parser for the `lua` language will be used.
query file, e.g., if the path ends in `/lua/highlights.scm` , the parser
for the `lua` language will be used.
Parameters: ~
• {buf} (integer) Buffer handle
@ -969,8 +970,9 @@ parse({lang}, {query}) *vim.treesitter.query.parse()*
Parse {query} as a string. (If the query is in a file, the caller should
read the contents into a string before calling).
Returns a `Query` (see |lua-treesitter-query|) object which can be used to search nodes in
the syntax tree for the patterns defined in {query} using `iter_*` methods below.
Returns a `Query` (see |lua-treesitter-query|) object which can be used to
search nodes in the syntax tree for the patterns defined in {query} using `iter_*` methods
below.
Exposes `info` and `captures` with additional context about {query}.
• `captures` contains the list of unique capture names defined in {query}.
@ -1078,7 +1080,8 @@ inject other languages, recursively. For example a Lua buffer containing
some Vimscript commands needs multiple parsers to fully understand its
contents.
To create a LanguageTree (parser object) for a given buffer and language, use: >lua
To create a LanguageTree (parser object) for a given buffer and language,
use: >lua
local parser = vim.treesitter.get_parser(bufnr, lang)
<
@ -1136,9 +1139,9 @@ LanguageTree:for_each_tree({fn}) *LanguageTree:for_each_tree()*
• {fn} fun(tree: TSTree, ltree: LanguageTree)
LanguageTree:included_regions() *LanguageTree:included_regions()*
Gets the set of included regions managed by this LanguageTree . This can be different from the regions set by injection query, because a
partial |LanguageTree:parse()| drops the regions outside the requested
range.
Gets the set of included regions managed by this LanguageTree . This can
be different from the regions set by injection query, because a partial
|LanguageTree:parse()| drops the regions outside the requested range.
Return: ~
table<integer, Range6[]>
@ -1150,8 +1153,9 @@ LanguageTree:invalidate({reload}) *LanguageTree:invalidate()*
• {reload} (boolean|nil)
LanguageTree:is_valid({exclude_children}) *LanguageTree:is_valid()*
Returns whether this LanguageTree is valid, i.e., |LanguageTree:trees()| reflects the latest state of the
source. If invalid, user should call |LanguageTree:parse()|.
Returns whether this LanguageTree is valid, i.e., |LanguageTree:trees()|
reflects the latest state of the source. If invalid, user should call
|LanguageTree:parse()|.
Parameters: ~
• {exclude_children} (boolean|nil) whether to ignore the validity of
@ -1213,7 +1217,8 @@ LanguageTree:register_cbs({cbs}, {recursive})
Parameters: ~
• {cbs} (table) An |nvim_buf_attach()|-like table argument with
the following handlers:
• `on_bytes` : see |nvim_buf_attach()|, but this will be called after the parsers callback.
• `on_bytes` : see |nvim_buf_attach()|, but this will be
called after the parsers callback.
• `on_changedtree` : a callback that will be called every
time the tree has syntactical changes. It will be
passed two arguments: a table of the ranges (as node
@ -1248,7 +1253,8 @@ LanguageTree:tree_for_range({range}, {opts})
LanguageTree:trees() *LanguageTree:trees()*
Returns all trees of the regions parsed by this parser. Does not include
child languages. The result is list-like if
• this LanguageTree is the root, in which case the result is empty or a singleton list; or
• this LanguageTree is the root, in which case the result is empty or a
singleton list; or
• the root LanguageTree is fully parsed.
Return: ~

View File

@ -155,7 +155,8 @@ function vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start
--- will be `nvim_buf_changedtick_event`. Not for Lua
--- callbacks.
--- @param opts vim.api.keyset.buf_attach Optional parameters.
--- • on_lines: Lua callback invoked on change. Return `true` to detach. Args:
--- • on_lines: Lua callback invoked on change. Return `true` to
--- detach. Args:
--- • the string "lines"
--- • buffer handle
--- • b:changedtick
@ -168,7 +169,8 @@ function vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start
---
--- • on_bytes: Lua callback invoked on change. This
--- callback receives more granular information about the
--- change compared to on_lines. Return `true` to detach. Args:
--- change compared to on_lines. Return `true` to
--- detach. Args:
--- • the string "bytes"
--- • buffer handle
--- • b:changedtick
@ -530,7 +532,8 @@ function vim.api.nvim_buf_line_count(buffer) end
--- wrapped lines.
--- • hl_mode : control how highlights are combined with the
--- highlights of the text. Currently only affects virt_text
--- highlights, but might affect `hl_group` in later versions.
--- highlights, but might affect `hl_group` in
--- later versions.
--- • "replace": only show the virt_text color. This is the
--- default.
--- • "combine": combine with background text color.
@ -740,7 +743,8 @@ function vim.api.nvim_chan_send(chan, data) end
--- • NOTE: Cannot be used with {pattern}
---
--- • group: (string|int) The augroup name or id.
--- • NOTE: If not passed, will only delete autocmds not in any group.
--- • NOTE: If not passed, will only delete autocmds not in any
--- group.
function vim.api.nvim_clear_autocmds(opts) end
--- Executes an Ex command.
@ -808,7 +812,9 @@ function vim.api.nvim_complete_set(index, opts) end
--- @return integer
function vim.api.nvim_create_augroup(name, opts) end
--- Creates an `autocommand` event handler, defined by `callback` (Lua function or Vimscript function name string) or `command` (Ex command string).
--- Creates an `autocommand` event handler, defined by `callback` (Lua
--- function or Vimscript function name string) or `command` (Ex command
--- string).
--- Example using Lua callback:
---
--- ```lua
@ -1525,8 +1531,8 @@ function vim.api.nvim_open_term(buffer, opts) end
--- • height: Window height (in character cells). Minimum of 1.
--- • bufpos: Places float relative to buffer text (only when
--- relative="win"). Takes a tuple of zero-indexed [line,
--- column]. `row` and `col` if given are applied relative to this position, else they
--- default to:
--- column]. `row` and `col` if given are
--- applied relative to this position, else they default to:
--- • `row=1` and `col=0` if `anchor` is "NW" or "NE"
--- • `row=0` and `col=0` if `anchor` is "SW" or "SE" (thus
--- like a tooltip near the buffer text).
@ -1541,8 +1547,9 @@ function vim.api.nvim_open_term(buffer, opts) end
--- • external: GUI should display the window as an external
--- top-level window. Currently accepts no other positioning
--- configuration together with this.
--- • zindex: Stacking order. floats with higher `zindex` go on top on floats with lower indices. Must be larger
--- than zero. The following screen elements have hard-coded
--- • zindex: Stacking order. floats with higher `zindex` go on
--- top on floats with lower indices. Must be larger than
--- zero. The following screen elements have hard-coded
--- z-indices:
--- • 100: insert completion popupmenu
--- • 200: message scrollback
@ -1661,7 +1668,8 @@ function vim.api.nvim_parse_expression(expr, flags, highlight) end
--- @param data string Multiline input. May be binary (containing NUL bytes).
--- @param crlf boolean Also break lines at CR and CRLF.
--- @param phase integer -1: paste in a single call (i.e. without streaming). To
--- "stream" a paste, call `nvim_paste` sequentially with these `phase` values:
--- "stream" a paste, call `nvim_paste` sequentially
--- with these `phase` values:
--- • 1: starts the paste (exactly once)
--- • 2: continues the paste (zero or more times)
--- • 3: ends the paste (exactly once)

View File

@ -34,7 +34,7 @@ The generated :help text for each function is formatted as follows:
- Each function documentation is separated by a single line.
"""
from __future__ import annotations
from __future__ import annotations # PEP-563, python 3.7+
import argparse
import collections
@ -47,9 +47,12 @@ import subprocess
import sys
import textwrap
from pathlib import Path
from typing import Any, Callable, Dict, List, Literal, Tuple
from typing import Any, Callable, Dict, List, Tuple
from xml.dom import minidom
if sys.version_info >= (3, 8):
from typing import Literal
import msgpack
Element = minidom.Element
@ -576,7 +579,7 @@ def is_inline(n):
return True
def doc_wrap(text, prefix='', width=70, func=False, indent=None):
def doc_wrap(text, prefix='', width=70, func=False, indent=None) -> str:
"""Wraps text to `width`.
First line is prefixed with `prefix`, subsequent lines are aligned.
@ -651,13 +654,19 @@ def update_params_map(parent, ret_map, width=text_width - indentation):
return ret_map
def render_node(n, text, prefix='', indent='', width=text_width - indentation,
fmt_vimhelp=False):
def render_node(n: Element, text: str, prefix='', *,
indent: str = '',
width: int = (text_width - indentation),
fmt_vimhelp: bool = False):
"""Renders a node as Vim help text, recursively traversing all descendants."""
def ind(s):
return s if fmt_vimhelp else ''
# Get the current column offset from the last line of `text`
# (needed to appropriately wrap multiple and contiguous inline elements)
col_offset: int = len_lastline(text)
text = ''
# space_preceding = (len(text) > 0 and ' ' == text[-1][-1])
# text += (int(not space_preceding) * ' ')
@ -682,7 +691,14 @@ def render_node(n, text, prefix='', indent='', width=text_width - indentation,
text += '\n{}\n<'.format(textwrap.indent(o, ' ' * 4))
elif is_inline(n):
text = doc_wrap(get_text(n), prefix=prefix, indent=indent, width=width)
o = get_text(n).strip()
if o:
DEL = chr(127) # a dummy character to pad for proper line wrap
assert len(DEL) == 1
dummy_padding = DEL * max(0, col_offset - len(prefix))
text += doc_wrap(dummy_padding + o,
prefix=prefix, indent=indent, width=width
).replace(DEL, "")
elif n.nodeName == 'verbatim':
# TODO: currently we don't use this. The "[verbatim]" hint is there as
# a reminder that we must decide how to format this if we do use it.