diff --git a/.github/MAINTAINERS b/.github/MAINTAINERS index 19a65c0c4e..b5e2bc6910 100644 --- a/.github/MAINTAINERS +++ b/.github/MAINTAINERS @@ -431,6 +431,7 @@ runtime/lang/menu_ru_ru.koi8-r.vim @RestorerZ runtime/lang/menu_ru_ru.utf-8.vim @RestorerZ runtime/pack/dist/opt/cfilter/plugin/cfilter.vim @yegappan runtime/pack/dist/opt/comment/ @habamax +runtime/pack/dist/opt/helptoc/ @kennypete runtime/pack/dist/opt/matchit/ @chrisbra runtime/pack/dist/opt/nohlsearch/ @habamax runtime/plugin/manpager.vim @Konfekt diff --git a/Filelist b/Filelist index a7a937c018..17ec8df2fd 100644 --- a/Filelist +++ b/Filelist @@ -808,6 +808,8 @@ RT_ALL = \ runtime/pack/dist/opt/editorconfig/ftdetect/editorconfig.vim \ runtime/pack/dist/opt/editorconfig/plugin/editorconfig.vim \ runtime/pack/dist/opt/helptoc/autoload/helptoc.vim \ + runtime/pack/dist/opt/helptoc/doc/helptoc.txt \ + runtime/pack/dist/opt/helptoc/doc/tags \ runtime/pack/dist/opt/helptoc/plugin/helptoc.vim \ runtime/pack/dist/opt/hlyank/plugin/hlyank.vim \ runtime/pack/dist/opt/justify/plugin/justify.vim \ diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt index 647c35ad2a..4e08d90592 100644 --- a/runtime/doc/helphelp.txt +++ b/runtime/doc/helphelp.txt @@ -1,4 +1,4 @@ -*helphelp.txt* For Vim version 9.1. Last change: 2025 Apr 21 +*helphelp.txt* For Vim version 9.1. Last change: 2025 May 04 VIM REFERENCE MANUAL by Bram Moolenaar @@ -287,9 +287,11 @@ The latter supports the following normal commands: > | select first entry | select last entry -The plugin can also provide a table of contents in man pages, markdown files, -and terminal buffers. In the latter, the entries will be the past executed -shell commands. To find those, the following pattern is used: > +The plugin can also provide a table of contents in buffers of the following +filetypes: asciidoc, html, man, markdown, tex, vim, and xhtml. In addition +it also provide a table of contents for a terminal buffer, which produces +entries that are the past executed shell commands. To find those, by default, +the following pattern is used: > ^\w\+@\w\+:\f\+\$\s @@ -303,6 +305,9 @@ Tip: After inserting a pattern to look for with the `/` command, if you press instead of , you can then get more context for each remaining entry by pressing `J` or `K`. +Refer |helptoc.vim| for more details about helptoc, particularly about using +it with filetypes other than help, and configuring its options. + ============================================================================== 2. Translated help files *help-translated* diff --git a/runtime/pack/dist/opt/helptoc/autoload/helptoc.vim b/runtime/pack/dist/opt/helptoc/autoload/helptoc.vim index c0d86a4e63..a22d4bafd3 100644 --- a/runtime/pack/dist/opt/helptoc/autoload/helptoc.vim +++ b/runtime/pack/dist/opt/helptoc/autoload/helptoc.vim @@ -1,24 +1,71 @@ vim9script noclear - # Config {{{1 +# g:helptoc {{{2 +# Create the g:helptoc dict (used to specify the shell_prompt and other +# options) when it does not exist +g:helptoc = exists('g:helptoc') ? g:helptoc : {} -var SHELL_PROMPT: string = '' +# Set the initial shell_prompt pattern matching a default bash prompt +g:helptoc.shell_prompt = get(g:helptoc, 'shell_prompt', '^\w\+@\w\+:\f\+\$\s') + +# Track the prior prompt (used to reset b:toc if 'shell_prompt' changes) +g:helptoc.prior_shell_prompt = g:helptoc.shell_prompt def UpdateUserSettings() #{{{2 - var new_prompt: string = g: - ->get('helptoc', {}) - ->get('shell_prompt', '^\w\+@\w\+:\f\+\$\s') - if new_prompt != SHELL_PROMPT - SHELL_PROMPT = new_prompt + + if g:helptoc.shell_prompt != g:helptoc.prior_shell_prompt # invalidate cache: user config has changed unlet! b:toc + # reset the prior prompt to the new prompt + g:helptoc.prior_shell_prompt = g:helptoc.shell_prompt endif + + # helptoc popup presentation options{{{ + # Enable users to choose whether, in toc and help text popups, to have: + # - border (default [], which is a border, so is usually wanted) + # - borderchars (default single box drawing; use [] for Vim's defaults) + # - borderhighlight (default [], but a user may prefer something else) + # - close (default 'none'; mouse users may prefer 'button') + # - drag (default true, which is a popup_menu's default) + # - scrollbar (default false; for long tocs/HELP_TEXT true may be better) + # For example, in a Vim9 script .vimrc, these settings will produce tocs + # with borders that have the same highlight group as the inactive + # statusline, a scrollbar, and an 'X' close button: + # g:helptoc.popup_borderchars = get(g:helptoc, 'popup_borderchars', [' ']) + # g:helptoc.popup_borderhighlight = get(g:helptoc, + # 'popup_borderhighlight', ['StatusLineNC']) + # g:helptoc.popup_close = get(g:helptoc, 'popup_close', 'button') + # g:helptoc.popup_scrollbar = get(g:helptoc, 'popup_scrollbar', true) + # }}} + g:helptoc.popup_border = get(g:helptoc, 'popup_border', []) + g:helptoc.popup_borderchars = get(g:helptoc, 'popup_borderchars', + ['─', '│', '─', '│', '┌', '┐', '┘', '└']) + g:helptoc.popup_borderhighlight = get(g:helptoc, 'popup_borderhighlight', + []) + g:helptoc.popup_drag = get(g:helptoc, 'popup_drag', true) + g:helptoc.popup_close = get(g:helptoc, 'popup_close', 'none') + g:helptoc.popup_scrollbar = get(g:helptoc, 'popup_scrollbar', false) + # For sanitized tocs, allow the user to specify the level indicator + g:helptoc.level_indicator = get(g:helptoc, 'level_indicator', '| ') enddef UpdateUserSettings() -# Init {{{1 +# Syntax {{{1 +# Used by sanitized tocs (asciidoc, html, markdown, tex, vim, and xhtml) +def SanitizedTocSyntax(): void + silent execute "syntax match helptocLevel _^\\(" .. + g:helptoc.level_indicator .. "\\)*_ contained" + silent execute "syntax region helptocText start=_^\\(" .. + g:helptoc.level_indicator .. "\\)*_ end=_$_ contains=helptocLevel" + highlight link helptocText Normal + highlight link helptocLevel NonText +enddef + +# Init {{{1 +# Constants {{{2 +# HELP_TEXT {{{3 const HELP_TEXT: list =<< trim END normal commands in help window ────────────────────────────── @@ -73,38 +120,108 @@ const HELP_TEXT: list =<< trim END more context for each remaining entry by pressing J or K END +# UPTOINC_H {{{3 +const UPTOINC_H: string = '\v\c^%(%([<][^h][^>]*[>])|\s)*[<]h' + +# MATCH_ENTRY {{{3 const MATCH_ENTRY: dict> = { + help: {}, - man: { - 1: (line: string, _): bool => line =~ '^\S', - 2: (line: string, _): bool => line =~ '^\%( \{3\}\)\=\S', - 3: (line: string, _): bool => line =~ '^\s\+\(\%(+\|-\)\S\+,\s\+\)*\%(+\|-\)\S\+', + # For asciidoc, these patterns should match: + # https://docs.asciidoctor.org/asciidoc/latest/sections/titles-and-levels/ + asciidoc: { + 1: (l: string, _): bool => l =~ '\v^%(\=|#)\s', + 2: (l: string, _): bool => l =~ '\v^%(\={2}|#{2})\s', + 3: (l: string, _): bool => l =~ '\v^%(\={3}|#{3})\s', + 4: (l: string, _): bool => l =~ '\v^%(\={4}|#{4})\s', + 5: (l: string, _): bool => l =~ '\v^%(\={5}|#{5})\s', + 6: (l: string, _): bool => l =~ '\v^%(\={6}|#{6})\s', }, + html: { + 1: (l: string, _): bool => l =~ $"{UPTOINC_H}1", + 2: (l: string, _): bool => l =~ $"{UPTOINC_H}2", + 3: (l: string, _): bool => l =~ $"{UPTOINC_H}3", + 4: (l: string, _): bool => l =~ $"{UPTOINC_H}4", + 5: (l: string, _): bool => l =~ $"{UPTOINC_H}5", + 6: (l: string, _): bool => l =~ $"{UPTOINC_H}6", + }, + + man: { + 1: (l: string, _): bool => l =~ '^\S', + 2: (l: string, _): bool => l =~ '\v^%( {3})=\S', + 3: (l: string, _): bool => l =~ '\v^\s+%(%(\+|-)\S+,\s+)*(\+|-)\S+' + }, + + # For markdown, these patterns should match: + # https://spec.commonmark.org/0.31.2/#atx-headings and + # https://spec.commonmark.org/0.31.2/#setext-headings markdown: { - 1: (line: string, nextline: string): bool => - (line =~ '^#[^#]' || nextline =~ '^=\+$') && line =~ '\w', - 2: (line: string, nextline: string): bool => - (line =~ '^##[^#]' || nextline =~ '^-\+$') && line =~ '\w', - 3: (line: string, _): bool => line =~ '^###[^#]', - 4: (line: string, _): bool => line =~ '^####[^#]', - 5: (line: string, _): bool => line =~ '^#####[^#]', - 6: (line: string, _): bool => line =~ '^######[^#]', + 1: (l: string, nextline: string): bool => + (l =~ '\v^ {0,3}#%(\s|$)' || nextline =~ '\v^ {0,3}\=+$') && + l =~ '\S', + 2: (l: string, nextline: string): bool => + (l =~ '\v^ {0,3}##%(\s|$)' || nextline =~ '\v^ {0,3}-+$') && + l =~ '\S', + 3: (l: string, _): bool => l =~ '\v {0,3}#{3}%(\s|$)', + 4: (l: string, _): bool => l =~ '\v {0,3}#{4}%(\s|$)', + 5: (l: string, _): bool => l =~ '\v {0,3}#{5}%(\s|$)', + 6: (l: string, _): bool => l =~ '\v {0,3}#{6}%(\s|$)', }, terminal: { - 1: (line: string, _): bool => line =~ SHELL_PROMPT, + 1: (l: string, _): bool => l =~ g:helptoc.shell_prompt + }, + + # For LaTeX, this should meet + # https://mirrors.rit.edu/CTAN/info/latex2e-help-texinfo/latex2e.pdf + # including: + # para 6.3: + # \section{Heading} + # \section[Alternative ToC Heading]{Heading} + # para 25.1.2: + # \section*{Not for the TOC heading} + # \addcontentsline{toc}{section}{Alternative ToC Heading} + tex: { + 1: (l: string, _): bool => l =~ '^[\\]\(\%(part\|chapter\)' .. + '\%([\u005B{]\)\|addcontentsline{toc}{\%(part\|chapter\)\)', + 2: (l: string, _): bool => l =~ '^[\\]\%(section' .. + '\%([\u005B{]\)\|addcontentsline{toc}{section}\)', + 3: (l: string, _): bool => l =~ '^[\\]\%(subsection' .. + '\%([\u005B{]\)\|addcontentsline{toc}{subsection}\)', + 4: (l: string, _): bool => l =~ '^[\\]\%(subsubsection' .. + '\%([\u005B{]\)\|addcontentsline{toc}{subsubsection}\)', + }, + + vim: { + 1: (l: string, _): bool => l =~ '\v\{{3}1', + 2: (l: string, _): bool => l =~ '\v\{{3}2', + 3: (l: string, _): bool => l =~ '\v\{{3}3', + 4: (l: string, _): bool => l =~ '\v\{{3}4', + 5: (l: string, _): bool => l =~ '\v\{{3}5', + 6: (l: string, _): bool => l =~ '\v\{{3}6', + }, + + xhtml: { + 1: (l: string, _): bool => l =~ $"{UPTOINC_H}1", + 2: (l: string, _): bool => l =~ $"{UPTOINC_H}2", + 3: (l: string, _): bool => l =~ $"{UPTOINC_H}3", + 4: (l: string, _): bool => l =~ $"{UPTOINC_H}4", + 5: (l: string, _): bool => l =~ $"{UPTOINC_H}5", + 6: (l: string, _): bool => l =~ $"{UPTOINC_H}6", } } +# HELP_RULERS {{{3 const HELP_RULERS: dict = { '=': '^=\{40,}$', '-': '^-\{40,}', } const HELP_RULER: string = HELP_RULERS->values()->join('\|') -# the regex is copied from the help syntax plugin +# HELP_TAG {{{3 +# The regex is copied from the help syntax plugin const HELP_TAG: string = '\*[#-)!+-~]\+\*\%(\s\|$\)\@=' # Adapted from `$VIMRUNTIME/syntax/help.vim`.{{{ @@ -113,13 +230,15 @@ const HELP_TAG: string = '\*[#-)!+-~]\+\*\%(\s\|$\)\@=' # # ^[-A-Z .][-A-Z0-9 .()_]*\ze\(\s\+\*\|$\) # -# Allowing a space or a hyphen at the start can give false positives, and is +# Allowing a space or a hyphen at the start can give false positives, and is # useless, so we don't allow them. #}}} + +# HELP_HEADLINE {{{3 const HELP_HEADLINE: string = '^\C[A-Z.][-A-Z0-9 .()_]*\%(\s\+\*+\@!\|$\)' # ^--^ # To prevent some false positives under `:help feature-list`. - +# Others {{{2 var lvls: dict def InitHelpLvls() lvls = { @@ -133,7 +252,6 @@ def InitHelpLvls() } enddef -const AUGROUP: string = 'HelpToc' var fuzzy_entries: list> var help_winid: number var print_entry: bool @@ -141,11 +259,11 @@ var selected_entry_match: number # Interface {{{1 export def Open() #{{{2 - var type: string = GetType() - if !MATCH_ENTRY->has_key(type) + g:helptoc.type = GetType() + if !MATCH_ENTRY->has_key(g:helptoc.type) return endif - if type == 'terminal' && win_gettype() == 'popup' + if g:helptoc.type == 'terminal' && win_gettype() == 'popup' # trying to deal with a popup menu on top of a popup terminal seems # too tricky for now echomsg 'does not work in a popup window; only in a regular window' @@ -158,7 +276,7 @@ export def Open() #{{{2 if exists('b:toc') && &filetype != 'man' if b:toc.changedtick != b:changedtick # in a terminal buffer, `b:changedtick` does not change - || type == 'terminal' && line('$') > b:toc.linecount + || g:helptoc.type == 'terminal' && line('$') > b:toc.linecount unlet! b:toc endif endif @@ -187,66 +305,257 @@ export def Open() #{{{2 line: winpos[0], col: winpos[1] + width - 1, pos: 'topright', - scrollbar: false, - highlight: type == 'terminal' ? 'Terminal' : 'Normal', - border: [], - borderchars: ['─', '│', '─', '│', '┌', '┐', '┘', '└'], + highlight: g:helptoc.type == 'terminal' ? 'Terminal' : 'Normal', minheight: height, maxheight: height, minwidth: b:toc.width, maxwidth: b:toc.width, filter: Filter, callback: Callback, + border: g:helptoc.popup_border, + borderchars: g:helptoc.popup_borderchars, + borderhighlight: g:helptoc.popup_borderhighlight, + close: g:helptoc.popup_close, + drag: g:helptoc.popup_drag, + scrollbar: g:helptoc.popup_scrollbar, }) - Win_execute(winid, [$'ownsyntax {&filetype}', '&l:conceallevel = 3']) + # Specify filetypes using sanitized toc syntax{{{ + # Those filetypes have a normalized toc structure. The top level is + # unprefixed and levels 2 to 6 are prefixed, by default, with a vertical + # line and space for each level below 1: + # Level 1 + # | Level 2 + # ... + # | | | | | Level 6 }}} + final SanitizedTocSyntaxTypes: list = + ['asciidoc', 'html', 'markdown', 'tex', 'vim', 'xhtml'] + if index(SanitizedTocSyntaxTypes, g:helptoc.type) != -1 + # Specified types' toc popups use a common syntax + Win_execute(winid, 'SanitizedTocSyntax()') + else + # Other types' toc popups use the same syntax as the buffer itself + Win_execute(winid, [$'ownsyntax {&filetype}', '&l:conceallevel = 3']) + endif # In a help file, we might reduce some noisy tags to a trailing asterisk. # Hide those. - if type == 'help' + if g:helptoc.type == 'help' matchadd('Conceal', '\*$', 0, -1, {window: winid}) endif SelectNearestEntryFromCursor(winid) - # can't set the title before jumping to the relevant line, otherwise the + # Can't set the title before jumping to the relevant line, otherwise the # indicator in the title might be wrong SetTitle(winid) enddef -#}}}1 + # Core {{{1 def SetToc() #{{{2 - var toc: dict = {entries: []} - var type: string = GetType() + # Lambdas: + # CHARACTER_REFERENCES_TO_CHARACTERS {{{3 + # These are used for AsciiDoc, Markdown, and [X]HTML, all of which allow + # for decimal, hexadecimal, and XML predefined entities. + # Decimal character references: e.g., § to § + # Hexadecimal character references: e.g., § to § + # XML predefined entities to chars: e.g., < to < + # All HTML5 named character references could be handled, though is that + # warranted for the few that may appear in a toc entry, especially when + # they are often mnemonic? Future: A common Vim dict/enum could be useful? + const CHARACTER_REFERENCES_TO_CHARACTERS = (text: string): string => + text->substitute('\v\�*([1-9]\d{0,6});', + '\=nr2char(str2nr(submatch(1), 10), 1)', 'g') + ->substitute('\c\v\�*([1-9a-f][[:xdigit:]]{1,5});', + '\=nr2char(str2nr(submatch(1), 16), 1)', 'g') + ->substitute('\C&', '\="\u0026"', 'g') + ->substitute('\C'', "\u0027", 'g') + ->substitute('\C>', "\u003E", 'g') + ->substitute('\C<', "\u003C", 'g') + ->substitute('\C"', "\u0022", 'g') + + # SANITIZE_ASCIIDOC {{{3 + # 1 - Substitute the = or # heading markup with the level indicator + # 2 - Substitute XML predefined, dec, and hex char refs in the entry + # AsciiDoc recommends only using named char refs defined in XML: + # https://docs.asciidoctor.org/asciidoc/latest/subs/replacements/ + const SANITIZE_ASCIIDOC = (text: string): string => + text->substitute('\v^(\={1,6}|#{1,6})\s+', + '\=repeat(g:helptoc.level_indicator, len(submatch(1)) - 1)', '') + ->CHARACTER_REFERENCES_TO_CHARACTERS() + + # SANITIZE_HTML {{{3 + # 1 - Remove any leading spaces or tabs + # 2 - Remove any + # 3 - Remove any + # 4 - Remove any leading tags (and any blanks) other than

+ # 7 - Remove trailing content following the + # 8 - Remove the

, , , etc. + # 11 - Substitute XML predefined, dec and hex character references + const SANITIZE_HTML = (text: string): string => + text->substitute('^\s*', '', '') + ->substitute('[<]!--.\{-}--[>]', '', 'g') + ->substitute('[<]?[^?]\+?[>]', '', 'g') + ->substitute('\v%([<][^Hh][^1-6]?[^>][>])*\s*', '', '') + ->substitute('^\s\+', '', '') + ->substitute('\v[<][Hh]([1-6])\s*[/][>].*', + '\=repeat(g:helptoc.level_indicator, ' .. + 'str2nr(submatch(1)) - 1) ' .. + '.. "[Empty heading " .. submatch(1) .. "]"', '') + ->substitute('[<][/][Hh][1-6][>].*$', '', '') + ->substitute('[<][Hh]1[^>]*[>]', '', '') + ->substitute('\v[<][Hh]([2-6])[^>]*[>]', + '\=repeat(g:helptoc.level_indicator, ' .. + 'str2nr(submatch(1)) - 1)', '') + ->substitute('[<][/]\?[[:alpha:]][^>]*[>]', '', 'g') + ->CHARACTER_REFERENCES_TO_CHARACTERS() + + # SANITIZE_MARKDOWN #{{{3 + # 1 - Hyperlink incl image, e.g. [![Vim The editor](xxx)](\uri), to Vim... + # 2 - Hyperlink [text](/uri) to text + # 3 - Substitute the # ATX heading markup with the level indicator/level + # The omitted markup reflects CommonMark Spec: + # https://spec.commonmark.org/0.31.2/#atx-headings + # 4 - Substitute decimal, hexadecimal, and XML predefined char refs + const SANITIZE_MARKDOWN = (text: string): string => + text->substitute('\v[\u005B]![\u005B]([^\u005D]+)[\u005D]' + .. '[(][^)]+[)][\u005D][(][^)]+[)]', '\1', '') + ->substitute('\v[\u005B]([^\u005D]+)[\u005D][(][^)]+[)]', + '\1', '') + ->substitute('\v^ {0,3}(#{1,6})\s*', + '\=repeat(g:helptoc.level_indicator, len(submatch(1)) - 1)', + '') + ->CHARACTER_REFERENCES_TO_CHARACTERS() + + # SANITIZE_TERMINAL {{{3 + # Omit the prompt, which may be very long and otherwise just adds clutter + const SANITIZE_TERMINAL = (text: string): string => + text->substitute('^' .. g:helptoc.shell_prompt, '', '') + + # SANITIZE_TEX #{{{3 + # 1 - Use any [toc-title] overrides to move its content into the + # {heading} instead of the (non-ToC) heading's text + # 2 - Replace \part{ or \addcontentsline{toc}{part} with '[PART] ' + # 3 - Omit \chapter{ or \addcontentsline{toc}{chapter} + # 4 - Omit \section{ or \addcontentsline{toc}{section} + # 5 - Omit \subsection{ or \addcontentsline{toc}{subsection} + # 6 - Omit \subsubsection{ or \addcontentsline{toc}{subsubsection} + # 7 - Omit the trailing } + # 8 - Unescape common escaped characters &%$_#{}~^\ + const SANITIZE_TEX = (text: string): string => + text->substitute('\v^[\\](part|chapter|%(sub){0,2}section)' .. + '[\u005B]([^\u005D]+).*', '\\\1{\2}', '') + ->substitute('^[\\]\(part\|addcontentsline{toc}{part}\){', + '[PART] ', '') + ->substitute('^[\\]\(chapter\|addcontentsline{toc}{chapter}\){', + '', '') + ->substitute('^[\\]\(section\|addcontentsline{toc}{section}\){', + '\=g:helptoc.level_indicator', '') + ->substitute('^[\\]\(subsection\|' .. + 'addcontentsline{toc}{subsection}\){', + '\=repeat(g:helptoc.level_indicator, 2)', '') + ->substitute('^[\\]\(subsubsection\|' .. + 'addcontentsline{toc}{subsubsection}\){', + '\=repeat(g:helptoc.level_indicator, 3)', '') + ->substitute('}[^}]*$', '', '') + ->substitute('\\\([&%$_#{}~\\^]\)', '\1', 'g') + + # SANITIZE_VIM {{{3 + # #1 - Omit leading Vim9 script # or vimscript " markers and blanks + # #2 - Omit numbered 3x { markers + const SANITIZE_VIM = (text: string): string => + text->substitute('\v^[#[:blank:]"]*(.+)\ze[{]{3}([1-6])', + '\=submatch(2) == "1" ? submatch(1) : ' .. + 'repeat(g:helptoc.level_indicator, str2nr(submatch(2)) - 1)' .. + ' .. submatch(1)', 'g') + ->substitute('[#[:blank:]"]*{\{3}[1-6]', '', '') + #}}}3 + + final toc: dict = {entries: []} toc.changedtick = b:changedtick if !toc->has_key('width') toc.width = 0 endif # We cache the toc in `b:toc` to get better performance.{{{ # - # Without caching, when we press `H`, `L`, `H`, `L`, ... quickly for a few + # Without caching, when we press `H`, `L`, `H`, `L`, ... quickly for a few # seconds, there is some lag if we then try to move with `j` and `k`. # This can only be perceived in big man pages like with `:Man ffmpeg-all`. #}}} b:toc = toc - if type == 'help' + if g:helptoc.type == 'help' SetTocHelp() return endif - if type == 'terminal' + if g:helptoc.type == 'terminal' b:toc.linecount = line('$') endif var curline: string = getline(1) var nextline: string var lvl_and_test: list> = MATCH_ENTRY - ->get(type, {}) + ->get(g:helptoc.type, {}) ->items() - ->sort((l: list, ll: list): number => l[0]->str2nr() - ll[0]->str2nr()) + ->sort((l: list, ll: list): number => + l[0]->str2nr() - ll[0]->str2nr()) + var skip_next: bool = false + + # Non-help headings processing for lnum: number in range(1, line('$')) + if skip_next + skip_next = false + curline = nextline + continue + endif + nextline = getline(lnum + 1) + + # Special handling for markdown filetype using setext headings + if g:helptoc.type == 'markdown' + # Check for setext formatted headings (= or - underlined) + if nextline =~ '^\s\{0,3}=\+$' && curline =~ '\S' + # Level 1 heading (one or more =, up to three spaces preceding) + b:toc.entries->add({ + lnum: lnum, + lvl: 1, + text: SANITIZE_MARKDOWN('# ' .. trim(curline)), + }) + skip_next = true + curline = nextline + continue + elseif nextline =~ '^\s\{0,3}-\+$' && curline =~ '\S' + # Level 2 heading (one or more -, up to three spaces preceding) + b:toc.entries->add({ + lnum: lnum, + lvl: 2, + text: SANITIZE_MARKDOWN('## ' .. trim(curline)), + }) + skip_next = true + curline = nextline + continue + endif + endif + + # Regular processing for markdown ATX-style headings + other filetypes for [lvl: string, IsEntry: func: bool] in lvl_and_test if IsEntry(curline, nextline) + if g:helptoc.type == 'asciidoc' + curline = curline->SANITIZE_ASCIIDOC() + elseif g:helptoc.type == 'html' || g:helptoc.type == 'xhtml' + curline = curline->SANITIZE_HTML() + elseif g:helptoc.type == 'markdown' + curline = curline->SANITIZE_MARKDOWN() + elseif g:helptoc.type == 'terminal' + curline = curline->SANITIZE_TERMINAL() + elseif g:helptoc.type == 'tex' + curline = curline->SANITIZE_TEX() + elseif g:helptoc.type == 'vim' + curline = curline->SANITIZE_VIM() + endif b:toc.entries->add({ lnum: lnum, lvl: lvl->str2nr(), @@ -281,9 +590,9 @@ def SetTocHelp() #{{{2 if main_ruler != '' && curline =~ main_ruler last_numbered_entry = 0 - # The information gathered in `lvls` might not be applicable to all - # the main sections of a help file. Let's reset it whenever we find - # a ruler. + # The information gathered in `lvls` might not be applicable to + # all the main sections of a help file. Let's reset it whenever + # we find a ruler. InitHelpLvls() endif @@ -304,7 +613,7 @@ def SetTocHelp() #{{{2 # 1. if prevline =~ '^\d\+\.\s' - # let's assume that the start of a main entry is always followed by an + # Let's assume that the start of a main entry is always followed by an # empty line, or a line starting with a tag && (curline =~ '^>\=\s*$' || curline =~ $'^\s*{HELP_TAG}') # ignore a numbered line in a list @@ -337,7 +646,8 @@ def SetTocHelp() #{{{2 if curline =~ HELP_HEADLINE && curline !~ '^CTRL-' && prevline->IsSpecialHelpLine() - && (nextline->IsSpecialHelpLine() || nextline =~ '^\s*(\|^\t\|^N[oO][tT][eE]:') + && (nextline ->IsSpecialHelpLine() + || nextline =~ '^\s*(\|^\t\|^N[oO][tT][eE]:') AddEntryInTocHelp('HEADLINE', lnum, curline) endif @@ -411,7 +721,8 @@ def SetTocHelp() #{{{2 ->min() for entry: dict in b:toc.entries entry.text = entry.text - ->substitute('^\s*', () => repeat(' ', (entry.lvl - min_lvl) * 3), '') + ->substitute('^\s*', () => + repeat(' ', (entry.lvl - min_lvl) * 3), '') endfor enddef @@ -455,29 +766,30 @@ def AddEntryInTocHelp(type: string, lnum: number, line: string) #{{{2 # Ignore noisy tags.{{{ # - # 14. Linking groups *:hi-link* *:highlight-link* *E412* *E413* - # ^----------------------------------------^ - # ^\s*\d\+\.\%(\d\+\.\=\)*\s\+.\{-}\zs\*.* + # 14. Linking groups *:hi-link* *:highlight-link* *E412* *E413* + # ^----------------------------------------^ + # ^\s*\d\+\.\%(\d\+\.\=\)*\s\+.\{-}\zs\*.* # --- # - # We don't use conceal because then, `matchfuzzypos()` could match concealed - # characters, which would be confusing. + # We don't use conceal because then, `matchfuzzypos()` could match + # concealed characters, which would be confusing. #}}} - # MAKING YOUR OWN SYNTAX FILES *mysyntaxfile* - # ^------------^ - # ^\s*[A-Z].\{-}\*\zs.* + # MAKING YOUR OWN SYNTAX FILES *mysyntaxfile* + # ^------------^ + # ^\s*[A-Z].\{-}\*\zs.* # var after_HEADLINE: string = '^\s*[A-Z].\{-}\*\zs.*' - # 14. Linking groups *:hi-link* *:highlight-link* *E412* *E413* - # ^----------------------------------------^ - # ^\s*\d\+\.\%(\d\+\.\=\)*\s\+.\{-}\*\zs.* + # 14. Linking groups *:hi-link* *:highlight-link* *E412* *E413* + # ^----------------------------------------^ + # ^\s*\d\+\.\%(\d\+\.\=\)*\s\+.\{-}\*\zs.* var after_numbered: string = '^\s*\d\+\.\%(\d\+\.\=\)*\s\+.\{-}\*\zs.*' - # 01.3 Using the Vim tutor *tutor* *vimtutor* - # ^----------------^ + # 01.3 Using the Vim tutor *tutor* *vimtutor* + # ^----------------^ var after_numbered_tutor: string = '^\*\d\+\.\%(\d\+\.\=\)*.\{-}\t\*\zs.*' - var noisy_tags: string = $'{after_HEADLINE}\|{after_numbered}\|{after_numbered_tutor}' + var noisy_tags: string = + $'{after_HEADLINE}\|{after_numbered}\|{after_numbered_tutor}' text = text->substitute(noisy_tags, '', '') - # We don't remove the trailing asterisk, because the help syntax plugin + # We don't remove the trailing asterisk, because the help syntax plugin # might need it to highlight some headlines. b:toc.entries->add({ @@ -498,7 +810,7 @@ enddef def Popup_settext(winid: number, entries: list>) #{{{2 var text: list - # When we fuzzy search the toc, the dictionaries in `entries` contain a + # When we fuzzy search the toc, the dictionaries in `entries` contain a # `props` key, to highlight each matched character individually. # We don't want to process those dictionaries further. # The processing should already have been done by the caller. @@ -544,7 +856,8 @@ def SelectNearestEntryFromCursor(winid: number) #{{{2 var lnum: number = line('.') var firstline: number = b:toc.entries ->copy() - ->filter((_, line: dict): bool => line.lvl <= b:toc.curlvl && line.lnum <= lnum) + ->filter((_, line: dict): bool => + line.lvl <= b:toc.curlvl && line.lnum <= lnum) ->len() if firstline == 0 return @@ -599,8 +912,8 @@ def Filter(winid: number, key: string): bool #{{{2 if key == 'J' || key == 'K' var lnum: number = GetBufLnum(winid) execute $'normal! 0{lnum}zt' - # install a match in the regular buffer to highlight the position of - # the entry in the latter + # Install a match in the regular buffer to highlight the position + # of the entry in the latter MatchDelete() selected_entry_match = matchaddpos('IncSearch', [lnum], 0, -1) endif @@ -665,41 +978,44 @@ def Filter(winid: number, key: string): bool #{{{2 return true elseif key == '/' - # This is probably what the user expect if they've started a first fuzzy - # search, press Escape, then start a new one. + # This is probably what the user expects if they've started a first + # fuzzy search, press Escape, then start a new one. DisplayNonFuzzyToc(winid) [{ - group: AUGROUP, + group: 'HelpToc', event: 'CmdlineChanged', pattern: '@', cmd: $'FuzzySearch({winid})', replace: true, }, { - group: AUGROUP, + group: 'HelpToc', event: 'CmdlineLeave', pattern: '@', cmd: 'TearDown()', replace: true, }]->autocmd_add() - # Need to evaluate `winid` right now with an `eval`'ed and `execute()`'ed heredoc because:{{{ + # Need to evaluate `winid` right now{{{ + # with an `eval`'ed and `execute()`'ed heredoc because: # - # - the mappings can only access the script-local namespace - # - `winid` is in the function namespace; not in the script-local one + # - the mappings can only access the script-local namespace + # - `winid` is in the function namespace; not in the script-local one #}}} var input_mappings: list =<< trim eval END - cnoremap Filter({winid}, 'j') - cnoremap Filter({winid}, 'k') - cnoremap Filter({winid}, 'j') - cnoremap Filter({winid}, 'k') + cnoremap Filter({winid}, 'j') + cnoremap Filter({winid}, 'k') + cnoremap Filter({winid}, 'j') + cnoremap Filter({winid}, 'k') END input_mappings->execute() var look_for: string try popup_setoptions(winid, {mapping: true}) - look_for = input('look for: ', '', $'custom,{Complete->string()}') | redraw | echo '' + look_for = input('look for: ', '', $'custom,{Complete->string()}') + | redraw + | echo '' catch /Vim:Interrupt/ TearDown() finally @@ -718,9 +1034,9 @@ def FuzzySearch(winid: number) #{{{2 return endif - # We match against *all* entries; not just the currently visible ones. - # Rationale: If we use a (fuzzy) search, we're probably lost. We don't know - # where the info is. + # We match against *all* entries; not just the currently visible ones. + # Rationale: If we use a (fuzzy) search, we're probably lost. We don't + # know where the info is. var matches: list> = b:toc.entries ->copy() ->matchfuzzypos(look_for, {key: 'text'}) @@ -764,7 +1080,7 @@ def PrintEntry(winid: number) #{{{2 enddef def CollapseOrExpand(winid: number, key: string) #{{{2 - # Must be saved before we reset the popup contents, so we can + # Must be saved before we reset the popup contents, so we can # automatically select the least unexpected entry in the updated popup. var buf_lnum: number = GetBufLnum(winid) @@ -798,11 +1114,11 @@ def CollapseOrExpand(winid: number, key: string) #{{{2 endwhile endif - # update the popup contents + # Update the popup contents var toc_entries: list> = GetTocEntries() Popup_settext(winid, toc_entries) - # Try to select the same entry; if it's no longer visible, select its + # Try to select the same entry; if it's no longer visible, select its # direct parent. var toc_lnum: number = 0 for entry: dict in toc_entries @@ -834,6 +1150,8 @@ def Callback(winid: number, choice: number) #{{{2 if choice == -1 fuzzy_entries = null_list return + elseif choice == -2 # Button X is clicked (when close: 'button') + return endif var lnum: number = GetTocEntries() @@ -851,36 +1169,38 @@ def Callback(winid: number, choice: number) #{{{2 enddef def ToggleHelp(menu_winid: number) #{{{2 + # Show/hide HELP_TEXT in a second popup when '?' is typed{{{ + # (when a helptoc popup is open). A scrollbar on this popup makes sense + # because it is very long and, even if it's not used for scrolling, works + # well as an indicator of how far through the HELP_TEXT popup you are. }}} if help_winid == 0 var height: number = [HELP_TEXT->len(), winheight(0) * 2 / 3]->min() var longest_line: number = HELP_TEXT ->copy() ->map((_, line: string) => line->strcharlen()) ->max() - var width: number = [longest_line, winwidth(0) * 2 / 3]->min() - var pos: dict = popup_getpos(menu_winid) - var [line: number, col: number] = [pos.line, pos.col] - --col + var width: number = [longest_line, winwidth(0) - 4]->min() var zindex: number = popup_getoptions(menu_winid).zindex ++zindex help_winid = HELP_TEXT->popup_create({ - line: line, - col: col, - pos: 'topright', + pos: 'center', minheight: height, maxheight: height, minwidth: width, maxwidth: width, - border: [], - borderchars: ['─', '│', '─', '│', '┌', '┐', '┘', '└'], highlight: &buftype == 'terminal' ? 'Terminal' : 'Normal', - scrollbar: false, zindex: zindex, + border: g:helptoc.popup_border, + borderchars: g:helptoc.popup_borderchars, + borderhighlight: g:helptoc.popup_borderhighlight, + close: g:helptoc.popup_close, + scrollbar: true, }) setwinvar(help_winid, '&cursorline', true) setwinvar(help_winid, '&linebreak', true) - matchadd('Special', '^<\S\+\|^\S\{,2} \@=', 0, -1, {window: help_winid}) + matchadd('Special', '^<\S\+\|^\S\{,2} \@=', 0, -1, + {window: help_winid}) matchadd('Number', '\d\+', 0, -1, {window: help_winid}) for lnum: number in HELP_TEXT->len()->range() if HELP_TEXT[lnum] =~ '^─\+$' @@ -898,23 +1218,22 @@ def ToggleHelp(menu_winid: number) #{{{2 enddef def Win_execute(winid: number, cmd: any) #{{{2 -# wrapper around `win_execute()` to enforce a redraw, which might be necessary +# wrapper around `win_execute()` to enforce a redraw, which might be necessary # whenever we change the cursor position win_execute(winid, cmd) redraw enddef def TearDown() #{{{2 - autocmd_delete([{group: AUGROUP}]) + autocmd_delete([{group: 'HelpToc'}]) cunmap cunmap cunmap cunmap enddef -#}}}1 # Util {{{1 def GetType(): string #{{{2 - return &buftype == 'terminal' ? 'terminal' : &filetype + return &buftype == 'terminal' ? 'terminal' : &filetype enddef def GetTocEntries(): list> #{{{2 @@ -944,10 +1263,12 @@ enddef def Complete(..._): string #{{{2 return b:toc.entries ->copy() - ->map((_, entry: dict) => entry.text->trim(' ~')->substitute('*', '', 'g')) + ->map((_, entry: dict) => + entry.text->trim(' ~')->substitute('*', '', 'g')) ->filter((_, text: string): bool => text =~ '^[-a-zA-Z0-9_() ]\+$') ->sort() ->uniq() ->join("\n") -enddef - +enddef #}}}2 +#}}}1 +# vim:et:ft=vim:fdm=marker: diff --git a/runtime/pack/dist/opt/helptoc/doc/helptoc.txt b/runtime/pack/dist/opt/helptoc/doc/helptoc.txt new file mode 100644 index 0000000000..4bd87e6258 --- /dev/null +++ b/runtime/pack/dist/opt/helptoc/doc/helptoc.txt @@ -0,0 +1,349 @@ +*helptoc.txt* For Vim version 9.1. Last change: 2025 May 04 + + + VIM REFERENCE MANUAL + +Interactive table of contents for help buffers and several other filetypes + +============================================================================== + + +1. OVERVIEW *HelpToc-overview* + +The helptoc.vim plugin provides one command, :HelpToc, which generates a +hierarchical table of contents in a popup window, which is based on the +structure of a Vim buffer. It was designed initially for help buffers, +but it also works with buffers of the following types: + - asciidoc + - html + - man + - markdown + - terminal + - tex + - vim Note: only with numbered fold markers, e.g. {{{1 + - xhtml + +1.1 The :HelpToc command *HelpToc-:HelpToc* + +The :HelpToc command takes no arguments and it cannot be executed from an +unsupported filetype. Also, it cannot be used to generate a table of contents +for an inactive buffer. + +For most buffers of the supported types, :HelpToc may be entered directly +in Vim's |Command-line-mode|. How to use it from Vim's |Terminal-Job| mode is +explained in |HelpToc-terminal-buftype|. + +You may choose to map :HelpToc to keys making it easier to use. These are +examples of what could be used: > + + nnoremap ht HelpToc + tnoremap HelpToc +< + +2. DETAILS *HelpToc-details* + +When the :HelpToc command is executed from an active buffer of a supported +type, a popup window is produced. The window contains a hierarchical and +interactive table of contents. The entries are based on the "headings" in +the buffer. + +Jumping to an entry's position in the buffer can be achieved by pressing +enter on the applicable entry. Navigation, and other commands applicable to +the popup window, such as expanding and contracting levels, fuzzy searching, +and jumping to the previous or next entry (leaving the table of contents +itself displayed, using J and K), is provided at |help-TOC|, so that is not +reproduced in this help file. + + +3. TYPES *HelpToc-types* + +Some filetypes have more predictable structures than others. For example, +markdown and asciidoc make the identification of headings (aside from edge +cases, such as when in quotes) straightforward. Some filetypes do not have +such obvious or reliable headings/levels (particularly help buffers). +Further, in some instances, how to enter the :HelpToc command is not +necessarily obvious, e.g., when in a Vim |terminal-window|. So, the following +headings address specific details regarding the in-scope types. + +3.1 asciidoc *HelpToc-asciidoc-filetype* + +The heading levels in asciidoc are typically identified by lines starting +with a "=" (up to six, one per level), one or more blank characters, and the +heading text. :HelpToc will generate a table of contents based on either +that form of heading type or, because asciidoc also allows for ATX heading +level syntax (i.e., using the "#" character), headings using that format too. + +As asciidoc is very structured, its table of contents entries are presented +in a standardized form - see |HelpToc-standardized-toc|. So, the initial +"=" or "#" characters and the following space from the related heading are +not included in the table of contents' entries. + +3.2 html *HelpToc-html-filetype* + +HTML provides for six levels of headings,

to

, which may be either +upper or lower case and preceded by all sorts of content like . +:HelpToc will produce a table of contents based on the six heading levels. + +As HTML is very structured, its table of contents entries are presented +in a standardized form - see |HelpToc-standardized-toc|. So, the

to

+tags, any preceding content, and any trailing content after the heading text, +is not included in the table of contents' entries. + +3.3 man pages *HelpToc-man-filetype* + +Retrieving man pages is typically performed in the terminal. To use :HelpToc +to generate a table of contents, the |man.vim| filetype plugin is a +prerequisite. It is provided with Vim, and may be sourced with: > + + :runtime ftplugin/man.vim +< +Once sourced, the |:Man| command will open the applicable man page in a new +buffer (of "man" filetype). For example: > + + :Man pwd +< +Once in the man buffer, entering :HelpToc opens the table of contents popup, +with level 1 containing section names like NAME, SYNOPSIS, etc. Levels +below 1 include subsections and options, with the level depending on the +number of spaces preceding the content. + +The table of contents for a man buffer's popup window has the same syntax +highlighting as man pages. This reflects that its content is reproduced +as-is, i.e., no preceding tags, level-indicating data, etc., need be omitted +for optimal presentation. + +3.4 markdown *HelpToc-markdown-filetype* + +The headings and levels in markdown typically are ATX formatted headings +(lines starting with up to three spaces, one to six "#", then (optionally) +one or blank characters and the heading text). The alternate form, +setext, uses up to three spaces, the heading 1 text, followed by a +line of one or more "=". The setext heading 2 is similar, but for one or +more "-" instead of "=". There is no heading 3+ in setext. ATX and setext +headings are supported. + +As markdown is very structured, its table of contents entries are presented +in a standardized form - see |HelpToc-standardized-toc|. So, they do not +include any leading spaces, any initial "#" characters and the following blank +character(s) in the table of contents' entries. + +3.5 terminal *HelpToc-terminal-buftype* + +There are no explicit "headings" for a terminal buffer. However, :HelpToc +displays the history of executed shell commands. Those may be specified +by changing the pattern used to match the Vim terminal's prompt. +See |HelpToc-configuration| for examples. + +To access the terminal's table of contents, from the Vim's |Terminal-Job| mode +enter CTRL-W N to go to |Terminal-Normal| mode. From there, enter :HelpToc to +generate the table of contents. If you use the terminal's table of contents +a lot, an appropriate mapping may make it easier than using CTRL-W N - e.g.: > + + tnoremap HelpToc +< +As the terminal has only "level 1", the table of contents is presented in a +standardized form - see |HelpToc-standardized-toc| - including only the history +list of commands. The prompt itself is also omitted since it adds no value +repeating it for every entry. + +3.6 tex *HelpToc-tex-filetype* + +In LaTeX, a document may be structured hierarchically using part, chapter, +and sectioning commands. Document structure levels are: + \part{} + \chapter{} + \section{} + \subsection{} + \subsubsection{} + +To keep things simpler, \part{} is supported, though treated as being at +the same level as chapter. Consequently, there are four levels displayed +for a tex filetype's table of contents, regardless of the \documentclass{}, +i.e., part and chapter (at level 1), section (level 2), subsection (level 3), +and subsubsection (level 4). + +Also supported are: + - The "*" used to produce unnumbered headings, which are not intended + for reproduction in a table of contents: > + \section*{Unnumbered section heading not produced in the TOC} +< - Manual toc entries using \addcontentsline, for example: > + \addcontentsline{toc}{section}{entry in the TOC only!} +< +The table of contents for a tex filetype is in a standardized form - +see |HelpToc-standardized-toc|. Omitted are: the "\", the part, chapter, +*section, or addcontentsline, and the left and right curly +brackets preceding and following each heading's text. + +3.7 vim *HelpToc-vim-filetype* + +Vimscript and Vim9 script do not have headings or levels inherently like +markup languages. However, Vim provides for |folds| defined by markers (|{{{|), +which themselves may be succeeded by a number explicitly indicating the fold +level. This is the structure recognized and supported by helptoc.vim. +So, for example, the following would produce three table of contents entries: > + + vim9script + # Variables {{{1 + var b: bool = true + var s: string = $"Fold markers are great? {b}!" + # Functions {{{1 + def MyFunction(): void #{{{2 + echo s + enddef + MyFunction() +< +The table of contents for that script would appear like this: + Variables + Functions + | MyFunction(): void + +Note: The numbered |{{{| marker structure is the only one supported by + helptoc.vim for the vim filetype. + +As the {{{1 to {{{6 markers make the "headings" explicit, the table of +contents is in a standardized form - see |HelpToc-standardized-toc|. +It does not include any leading comment markers (i.e., either # or ") and +omits the markers themselves. + +3.8 xhtml *HelpToc-xhtml-filetype* + +Although XHTML, being XML, is more strictly structured than HTML/HTML5, +there is no practical difference in treatment required for the xhtml filetype +because, at the heading level, the tags that matter are very similar. +See |HelpToc-html-filetype| for how an xhtml filetype's table of contents is +supported. + + +4. STANDARDIZED TOC *HelpToc-standardized-toc* + +The table of contents for a help buffer, terminal, or man page, make sense +being presented in the form they appear, minus trailing content (such as tags). + +The table of contents for a markdown, asciidoc, [x]html, terminal, or tex +buffer have superfluous content if the entire line was to be returned. +For example: +- Markdown has "#" characters before headings when using ATX heading notation. +- Asciidoc will have either those or, more often, "=" characters before its + headings. +- HTML, aside from the " + vim9 g:helptoc.shell_prompt = '^\$\s' + + + vim9 g:helptoc.level_indicator = '¦ ' +< +popup_border By default, the table of contents border will appear above, + right, below, and left of the popup window. If you prefer + not to have the border on the right and left (for example + only), you can achieve that with: > + vim9 g:helptoc.popup_border = [1, 0, 1, 0] + + vim9 g:helptoc.popup_borderchars = [' '] + + vim9 g:helptoc.popup_borderhighlight = ['Cursor'] + +< Note: Choosing a highlight group that persists when + colorschemes change may be a good idea if you + do choose to customize this. + +popup_drag By default, table of contents popup windows may be dragged + with a mouse. If you want to prevent that from happening, + for whatever reason, you may deactivate it with: > + vim9 g:helptoc.popup_drag = false +< +popup_close Table of contents popups have "none" as the default setting + for this option. If you use a mouse, you may want either + to have the option to close popup windows by clicking on them + or to have a clickable "X" in the top right corner. For the + former, use "click", and for the latter, use "button", e.g.: > + vim9 g:helptoc.popup_close = "button" + + vim9 g:helptoc.popup_scrollbar = true +< +NOTE: Information about the "popup_*" options, above, relate to popup options, +which are explained at the 'second argument' part of |popup_create-arguments|. + + +6. LIMITATIONS *HelpToc-limitations* + +- The help filetype may have edge case formatting patterns. Those may result + in some "headings" not being identified and/or may impact the heading levels + of entries in the table of contents itself. +- Terminal window table of contents may not be active (insofar as jumping to + entries going to the Vim terminal's related command line). For example, if + Vim's terminal is set to Windows PowerShell Core, the table of contents will + display successfully, though the entries go nowhere when Enter, J, or K are + entered on them. +- The tex filetype may have variable sectioning commands depending on the + document class. Consequently, some compromises are made, though they should + have minimal impact. Specifically: + * In instances where \part{} and \chapter{} appear in the same buffer, they + will both present at the top level in the table of contents. This should + be a minor matter because, in many instances, chapters will be in a + separate document using \include{}. + * An article or beamer \documentclass without a \part{} (or any document + with neither any \part{} nor any \chapter{} command) will have no content + at level 1. Consequently, its table of contents entries will all appear + preceded by at least one "| " (by default) because its headings start at + level 2 (presuming \section{} is present). +- The vim filetype is only supported where numbered fold markers are applied. + This is intentional (including not handling unnumbered markers, which, when + used in combination with numbered ones, may be used for folding comments). + helptoc.vim itself provides an exemplar of how to use numbered fold markers, + not only for folds, but to support generating a useful table of contents + using :HelpToc. + +============================================================================== +vim:tw=78:ts=8:fo=tcq2:ft=help: diff --git a/runtime/pack/dist/opt/helptoc/doc/tags b/runtime/pack/dist/opt/helptoc/doc/tags new file mode 100644 index 0000000000..cd62dec896 --- /dev/null +++ b/runtime/pack/dist/opt/helptoc/doc/tags @@ -0,0 +1,16 @@ +HelpToc-:HelpToc helptoc.txt /*HelpToc-:HelpToc* +HelpToc-asciidoc-filetype helptoc.txt /*HelpToc-asciidoc-filetype* +HelpToc-configuration helptoc.txt /*HelpToc-configuration* +HelpToc-details helptoc.txt /*HelpToc-details* +HelpToc-html-filetype helptoc.txt /*HelpToc-html-filetype* +HelpToc-limitations helptoc.txt /*HelpToc-limitations* +HelpToc-man-filetype helptoc.txt /*HelpToc-man-filetype* +HelpToc-markdown-filetype helptoc.txt /*HelpToc-markdown-filetype* +HelpToc-overview helptoc.txt /*HelpToc-overview* +HelpToc-standardized-toc helptoc.txt /*HelpToc-standardized-toc* +HelpToc-terminal-buftype helptoc.txt /*HelpToc-terminal-buftype* +HelpToc-tex-filetype helptoc.txt /*HelpToc-tex-filetype* +HelpToc-types helptoc.txt /*HelpToc-types* +HelpToc-vim-filetype helptoc.txt /*HelpToc-vim-filetype* +HelpToc-xhtml-filetype helptoc.txt /*HelpToc-xhtml-filetype* +helptoc.txt helptoc.txt /*helptoc.txt*