diff options
author | dana <dana@dana.is> | 2024-12-16 10:52:22 -0600 |
---|---|---|
committer | dana <dana@dana.is> | 2024-12-16 11:01:23 -0600 |
commit | 7798fd88ac42f55980fb9832f2f7e379392fe6aa (patch) | |
tree | 81cbb265bc700a17fe959d4424e8b0219ec08e87 /Completion | |
parent | d905c7a0d7d8fb789e7f508eb4610ddfa280cf54 (diff) | |
download | zsh-7798fd88ac42f55980fb9832f2f7e379392fe6aa.tar.gz zsh-7798fd88ac42f55980fb9832f2f7e379392fe6aa.zip |
53251: _man: fix page completion on macOS, update fall-back paths, etc.
- fix broken page completion on macOS and FreeBSD (regression caused by
workers/50278)
- update fall-back paths to include /usr/local/share/man (fixes issues like
workers/53249 for systems without `manpath` or equivalent)
- fold macOS completion into FreeBSD's, as macOS 13+ uses it now with little
modification
- add -K option for FreeBSD and -h option for mandoc/NetBSD, complete
pre-processor sequences, complete section lists with commas for man-db
- exclude HTML pages for FreeBSD-likes
Diffstat (limited to 'Completion')
-rw-r--r-- | Completion/Unix/Command/_man | 131 |
1 files changed, 79 insertions, 52 deletions
diff --git a/Completion/Unix/Command/_man b/Completion/Unix/Command/_man index 190811e41..2869e99e2 100644 --- a/Completion/Unix/Command/_man +++ b/Completion/Unix/Command/_man @@ -6,12 +6,16 @@ # - We assume that Linux distributions are using either man-db or mandoc # - @todo Would be nice to support completing the initial operand as a section # name (on non-Solaris systems) +# - @todo We don't support completing the man-db syntaxes <name>.<section> +# (`ls.1`) and <name>(<section>) (`ls(1)`) # - @todo We don't support the man-db feature of 'sub-pages' — that is, treating # pairs of operands like `git diff` as `git-diff` +# - @todo We don't really handle architecture-specific man pages at all # - @todo Option exclusivity isn't super accurate # - @todo Solaris man accepts a single hyphen as the first option to disable # paging (like AIX's -c); we don't support that -# - @todo Linux apropos/whatis take options; we don't complete them yet +# - @todo FreeBSD-like and Linux apropos/whatis take options; we don't complete +# them yet _man() { local dirs expl mrd awk variant noinsert @@ -21,8 +25,13 @@ _man() { if [[ $service == man ]]; then # We'll treat all mandoc-based systems (Alpine, various Illumos distros, - # etc.) as OpenBSD - _pick_variant -r variant openbsd='-S subsection' $OSTYPE --- + # etc.) as OpenBSD, and all FreeBSD-based man implementations (including + # Apple's) as FreeBSD + _pick_variant -r variant \ + freebsd='-S mansect' \ + openbsd='-S subsection' \ + $OSTYPE \ + --- modes=( -f -K -k -l -R -w -W @@ -36,49 +45,44 @@ _man() { --where --where-cat ) - [[ $variant == darwin* ]] && modes+=( -t ) args=( "(${(j< >)modes})"{-f,--whatis}'[display short description (like whatis)]' "(${(j< >)modes})"{-k,--apropos}'[search for keyword (like apropos)]' '(-M --manpath)'{-M+,--manpath=}'[specify manual search path]:manual search path:_sequence -s\: _directories' ) - if [[ $variant == (darwin|dragonfly|freebsd|linux)* ]]; then + if [[ $variant == (freebsd|linux)* ]]; then args+=( '(-a -S -s --all --sections)'{-a,--all}'[display all matching pages]' '(-P --pager)'{-P+,--pager=}'[specify output pager]:pager:_path_commands' - # @todo Could enumerate these - '(-p --preprocessor)'{-p+,--preprocessor=}'[specify roff preprocessor sequence]:preprocessor sequence' + '(-p --preprocessor)'{-p+,--preprocessor=}'[specify roff preprocessor sequence]: :_man_preprocs' ) else args+=( '(-s)-a[display all matching pages]' ) fi [[ $variant == (aix|solaris)* ]] || args+=( - '(-C --config-file)'{-C+,--config-file=}'[specify configuration file]:configuration file:_files' "(${(j< >)modes})"{-w,--path,--where}'[display file locations]' ) + [[ $variant == (aix|freebsd|solaris)* ]] || args+=( + '(-C --config-file)'{-C+,--config-file=}'[specify configuration file]:configuration file:_files' + ) [[ $variant == (aix|netbsd|openbsd)* ]] || args+=( # @todo FreeBSD allows this to be given multiple times '(-d --debug)'{-d,--debug}'[display debugging information]' ) - [[ $variant == (darwin|dragonfly|freebsd|linux|solaris|aix)* ]] && args+=( + [[ $variant == (freebsd|linux|solaris|aix)* ]] && args+=( '(-7 -H -t --ascii --html --troff)'{-t,--troff}'[format man page using troff]' ) - [[ $variant == (darwin|linux)* ]] && args+=( - "(${(j< >)modes})"{-K,--global-apropos}'[search for keyword in all pages]' - '(-m --systems)'{-m+,--systems=}'[search manual of specified system]:operating system' - ) - [[ $variant == (darwin|dragonfly|freebsd)* ]] && args+=( + [[ $variant == (freebsd)* ]] && args+=( '(: -)-h[display help information]' - '(-a)-S+[specify manual sections to search]: :->sects' - ) - [[ $variant == (dragonfly|freebsd)* ]] && args+=( # @todo Could enumerate these '-m[search manual of specified architecture]:architecture' '-o[use non-localized man pages]' + '(-a)-S+[specify manual sections to search]: :->sects' ) [[ $variant == (netbsd|openbsd)* ]] && args+=( '-c[disable paging]' + '-h[display only synopsis]' '-m[augment manual search path]:manual search path:_sequence -s\: _directories' '(-a)-s+[specify manual section to search]: :->sects' ) @@ -92,9 +96,11 @@ _man() { '(-H --html)'{-H-,--html=-}'[produce HTML output for specified browser]::Web browser:_path_commands' '(-i -I --ignore-case --match-case)'{-i,--ignore-case}'[search case-insensitively]' '(-i -I --ignore-case --match-case)'{-I,--match-case}'[search case-sensitively]' + "(${(j< >)modes})"{-K,--global-apropos}'[search for keyword in all pages]' '(-L --locale)'{-L+,--locale=}'[specify locale]:locale:_locales' "(${(j< >)modes})"{-l+,--local-file=}'[format and display specified file]:*:::manual file:_files' "!(${(j< >)modes})"{--location,--location-cat} + '(-m --systems)'{-m+,--systems=}'[search manual of specified system]:operating system' '--names-only[match only page names (with --regex or --wildcard)]' '(--nh --no-hyphenation)'{--nh,--no-hyphenation}'[disable hyphenation]' '(--nj --no-justification)'{--nj,--no-justification}'[disable justification]' @@ -117,21 +123,9 @@ _man() { # @todo Post-process how? '(-t --troff -Z --ditroff)'{-Z,--ditroff}'[post-process output for chosen device]' ) - [[ $variant == darwin* ]] && args+=( - # We use _files here because browsers are usually in /Applications, which - # typically isn't in PATH - '-B+[specify browser to use for HTML files]:Web browser:_files' - '-c[reformat source man page]' - # @todo -d should be exclusive with this above - '(-d)-D[display man page along with debugging information]' - '(-D -F --preformat)'{-F,--preformat}'[format man page only (do not display)]' - '-H+[specify command to render HTML as text]:HTML pager:_path_commands' - # --help and --version are undocumented but functional - '(: -)--help[display help information]' - # -s is also undocumented; it's provided for compatibility with Solaris - '!(-S)-s+: :->sects' - '(: -)'{-v,--version}'[display version information]' - "(${(j< >)modes})-W[display file locations, one per line, with no other information]" + # Currently macOS and Dragonfly don't have this, so check $OSTYPE too + [[ $variant == freebsd* && $OSTYPE == freebsd* ]] && args+=( + "(${(j< >)modes})-K+[perform full text search with specified regexp]:regexp" ) [[ $variant == netbsd* ]] && args+=( '-h[display only synopsis lines]' @@ -157,12 +151,9 @@ _man() { '-r[search remotely]' ) - # Strip (most) long options from non-Linux platforms - if [[ $variant == darwin* ]]; then - args=( ${(M)args:#((#s)|*\))(\*|)(-[^-]|--(help|path|pref|vers))*} ) - elif [[ $variant != linux* ]]; then - args=( ${(M)args:#((#s)|*\))(\*|)-[^-]*} ) - fi + # Strip long options from non-Linux platforms + [[ $variant == linux* ]] || + args=( ${(M)args:#((#s)|*\))(\*|)-[^-]*} ) fi _arguments -s -S : $args '*::: :->man' && return 0 @@ -179,8 +170,12 @@ _man() { fi if [[ -z $_manpath_cache[$MANPATH] ]]; then local mp - mp=( ${(s.:.)$({ command man -w || manpath } 2>/dev/null)} ) - [[ "$mp" == *:* ]] && mp=( ${(s.:.)mp} ) + if [[ $variant == netbsd* ]]; then + mp=( ${(s.:.)$(command man -p 2>/dev/null)} ) + elif [[ $variant != freebsd* ]]; then + mp=( ${(s.:.)$(command man -w 2>/dev/null)} ) + fi + (( $#mp )) || mp=( ${(s.:.)$(manpath 2>/dev/null)} ) if (( $#mp )); then _manpath_cache[$MANPATH]=${(j.:.)mp} elif (( $#manpath )); then @@ -199,8 +194,11 @@ _man() { _manpath+=( /usr/share/man ) fi - (( $#_manpath )) || - _manpath=( /usr/man(-/) /(opt|usr)/(pkg|dt|share|X11R6|local)/(cat|)man(-/) ) + (( $#_manpath )) || _manpath=( + /usr/man(-/) + /(opt|usr)/(pkg|dt|share|X11R6|local)/(cat|)man(-/) + /(opt|usr)/local/share/(cat|)man(-/) + ) # `sman' is the SGML manual directory for Solaris 7. # 1M is system administrator commands on SVR4 @@ -221,28 +219,36 @@ _man() { [[ $service != man ]] || [[ $state == sects ]] || (( $+opt_args[-a] )) then sect='*' + # man-db: multiple sections separated by colons or commas elif - [[ $variant == (darwin|linux)* ]] && + [[ $variant == linux* ]] && [[ -n ${opt_args[(i)-S|-s|--sections]} ]] then noinsert=1 sect=${opt_args[${opt_args[(i)-S|-s|--sections]}]//[:,]/|} + # mandoc, NetBSD: single section only elif - [[ $variant == (netbsd|openbsd|solaris)* ]] && (( $+opt_args[-s] )) + [[ $variant == (netbsd|openbsd)* ]] && (( $+opt_args[-s] )) then noinsert=1 - sect=${opt_args[-s]//,/|} - elif [[ $variant == (dragonfly|freebsd)* ]] && (( $+opt_args[-S] )); then + sect=$opt_args[-s] + # FreeBSD: multiple sections separated by colons + elif [[ $variant == freebsd* ]] && (( $+opt_args[-S] )); then noinsert=1 sect=${opt_args[-S]//:/|} + # Solaris: multiple sections separated by commas + elif + [[ $variant == solaris* ]] && (( $+opt_args[-s] )) + then + noinsert=1 + sect=${opt_args[-s]//,/|} # It's only a small help, but, per man-db, we can avoid treating an initial # operand like `8139too` as a section name by ensuring that only the first # character is a digit. This doesn't do much for stuff like `2to3`, but we can # at least special-case a few common patterns for now elif (( CURRENT > 1 )) && - [[ $variant != solaris* ]] && - [[ ${${(Q)words[1]}##(2to3|7z)*} == ([0-9](|[^0-9[:punct:]]*)|[lnopx]) ]] + [[ ${${(Q)words[1]}##(2to3|7z)*} == ([0-9](|[^0-9[:punct:]]*)|[hlnopx]) ]] then noinsert=1 sect=$words[1] @@ -253,7 +259,7 @@ _man() { # Colons may have been escaped sect=${(Q)sect} - if [[ $sect = (<->*|[lnopx]) || $sect = *\|* ]]; then + if [[ $sect = (<->*|[hlnopx]) || $sect = *\|* ]]; then sects=( ${(s.|.)sect} ) # Most man implementations support partial matching of a page's @@ -288,7 +294,11 @@ _man() { # Solaris 11 and on have a man-index directory that doesn't contain manpages dirs=( ${dirs:#*/man-index/} ) - sects=( ${(o)${${dirs##*(man|cat)}%.*}%/} ) + sects=( ${(ou)${${dirs##*(man|cat)}%.*}%/} ) + + # HTML man pages don't work on FreeBSD-likes. Not sure what they do work on + [[ $variant == freebsd* ]] && + sects=( ${sects:#h} ) # If we've got this far, we can build our look-up table for descriptions of # the more common sections. Unless otherwise labelled, the more specific ones @@ -322,6 +332,7 @@ _man() { 8 'maintenance commands and procedures' 9 'kernel features' 9lua 'Lua kernel bindings' # NetBSD + h 'HTML documentation' # Supported by which implementations? l 'local documentation' # AIX, etc. — TCL on some systems? n 'new documentation' # AIX, etc. o 'old documentation' # AIX, etc. @@ -376,9 +387,13 @@ _man() { done specs=( ${specs%:} ) - if [[ $variant == (darwin|dragonfly|freebsd|linux)* ]]; then + + if + [[ $variant == freebsd* ]] || + [[ $variant == linux* && $PREFIX$SUFFIX != *,* ]] + then _sequence -s : _describe -t sections 'manual section' specs - elif [[ $variant == solaris* ]]; then + elif [[ $variant == (linux|solaris)* ]]; then _sequence -s , _describe -t sections 'manual section' specs else _describe -t sections 'manual section' specs @@ -424,6 +439,7 @@ _man() { fi } +(( $+functions[_man_pages] )) || _man_pages() { local pages sopt tmp @@ -470,4 +486,15 @@ _man_pages() { esac } +(( $+functions[_man_preprocs] )) || +_man_preprocs() { + _values -S '' preprocessor \ + 'e[eqn]' \ + 'g[grap]' \ + 'p[pic]' \ + 'r[refer]' \ + 't[tbl]' \ + 'v[vgrind]' +} + _man "$@" |