summary refs log tree commit diff
path: root/Completion/Unix/Command/_man
blob: 67810e1dca4287e09f5832c8fb8760d9d626b809 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#compdef man apropos whatis

_man() {
  local dirs expl mrd awk

  if (( $words[(I)-M] == (( $CURRENT - 1 )) )); then
    _directories && return 0
  fi

  if [[ $service == man ]] && (( $words[(I)-l] + $words[(I)--local-file] )); then
    _files || return 0
  fi

  if (( ! $#_manpath )); then
    local mp
    mp=( ${(s.:.)$(manpath 2>/dev/null)} )
    [[ "$mp" == *:* ]] && mp=( ${(s.:.)mp} )
    if (( $#mp )); then
      _manpath=( $mp )
    elif (( $#manpath )); then
      _manpath=( $manpath )
    fi
  fi

  (( $#_manpath )) ||
      _manpath=( /usr/man(-/) /(opt|usr)/(pkg|dt|share|X11R6|local)/(cat|)man(-/) )

  integer index=$words[(I)-M]
  if (( index )); then
    local opt
    opt=$words[index+1]
    _manpath=($opt)
  fi

  # `sman' is the SGML manual directory for Solaris 7.
  # 1M is system administrator commands on SVR4

  mrd=(${^_manpath/\%L/${LANG:-En_US.ASCII}}/mandb(N))

  # $sect is from the command line, the "3p" in "man 3p memcpy".
  #   It may also be a |-joined (and later in the code "()"-enclosed) list of
  #   section names.
  #   TODO: disentangle this to always be an array.
  # $sect_dirname is from the filesystem, the "3" in "/usr/share/man/man3"
  # These are used by _man_pages
  local sect sect_dirname
  if [[ $OSTYPE = solaris* ]]; then
    sect=${${words[(R)-s*]#-s}:-$words[$words[(i)-s]+1]}
    sect="${sect//,/|}"
  elif [[ -n ${sect:=$words[$words[(i)-S]+1]} || -n ${sect:=$MANSECT} ]]; then
    sect="${sect//:/|}"
    sect="${sect//,/|}"
  elif (( CURRENT > 2 )); then
    case $words[2] in
      (-a) sect='*';;
      (-*) ;;
      (*)  sect=$words[2];;
    esac
  fi

  if [[ $sect = (<->*|1M|l|n) || $sect = *\|* ]]; then
    () {
      local -a sects=( ${(s.|.)sect} )
      if [[ $sect != (l|n) ]]; then
        sects=( ${sects%%[^0-9]#} )
      fi
      dirs=( $^_manpath/(sman|man|cat)${^sects}*/ )
    }
    if [[ $sect == *\|* ]]; then sect="($sect)"; fi
    awk="\$2 == \"$sect\" {print \$1}"
  else
    dirs=( $^_manpath/(sman|man|cat)*/ )
    awk='{print $1}'
  fi
  # Solaris 11 and on have a man-index directory that doesn't contain manpages
  dirs=( ${dirs:#*/man-index/} )
  if [[ $OSTYPE = solaris* && ( $words[CURRENT] = -s* || $words[CURRENT-1] == -s ) ]]; then
    [[ $words[CURRENT] = -s* ]] && compset -P '-s'
    sects=( ${(o)${dirs##*(man|cat)}%/} )
    _wanted sections expl 'section' compadd -a sects
  elif zstyle -t ":completion:${curcontext}:manuals" separate-sections; then
    typeset -U sects
    local ret=1

    sects=( ${(o)${dirs##*(man|cat)}%/} )

    (( $#sects )) || return 1

    _tags manuals.${^sects}
    while _tags; do
      for sect_dirname in $sects; do
        _requested manuals.$sect_dirname expl "manual page, section $sect_dirname" _man_pages &&
            ret=0
      done
      (( ret )) || return 0
    done
    ## To fall back to other sections' manpages when completing filenames, like
    ## the 'else' codepath does:
    #
    # if (( ret )) && [[ $PREFIX$SUFFIX == */* ]]; then
    #   sect_dirname=
    #   _wanted manuals expl 'manual page' _man_pages && return
    # fi

    return 1
  else
    sect_dirname=
    _wanted manuals expl 'manual page' _man_pages
  fi
}

_man_pages() {
  local pages sopt

  # What files corresponding to manual pages can end in.
  local suf='.((?|<->*)(|.gz|.bz2|.Z|.lzma))'

  if [[ $PREFIX$SUFFIX = */* ]]; then
    # Easy way to test for versions of man that allow file names.
    # This can't be a normal man page reference.
    # Try to complete by glob first.
    if [[ -n $sect_dirname ]]; then
      _path_files -g "*.*$sect_dirname*(|.gz|.bz2|.Z|.lzma)" "$expl[@]"
    else
      _path_files -g "*$suf" "$expl[@]" && return
      _path_files "$expl[@]"
    fi
    return $?
  fi

  pages=( ${(M)dirs:#*$sect_dirname/} )
  pages=( ${^pages}/"*$sect${sect:+"*"}" );
  pages=( ${^~pages}(N:t) )

  (($#mrd)) && pages[$#pages+1]=($(awk $awk $mrd))

  # Remove any compression suffix, then remove the minimum possible string
  # beginning with .<->: that handles problem cases like files called
  # `POSIX.1.5'.

  [[ $OSTYPE = solaris* ]] && sopt='-s '
  if ((CURRENT > 2)) ||
      ! zstyle -t ":completion:${curcontext}:manuals.$sect_dirname" insert-sections
  then
    compadd "$@" - ${pages%$~suf}
  else
    compadd "$@" -P "$sopt$sect_dirname " - ${pages%$~suf}
  fi
}

_man "$@"