|
1 | 1 | # cd(1) completion -*- shell-script -*-
|
2 | 2 |
|
3 |
| -# This meta-cd function observes the CDPATH variable, so that `cd` |
4 |
| -# additionally completes on directories under those specified in CDPATH. |
5 |
| -_comp_cmd_cd() |
| 3 | +_comp_cmd_cd__compgen_cdable_vars() |
6 | 4 | {
|
7 |
| - local cur prev words cword comp_args |
8 |
| - _comp_initialize -- "$@" || return |
| 5 | + shopt -q cdable_vars || return 1 |
9 | 6 |
|
10 |
| - if [[ $cur == -* ]]; then |
11 |
| - _comp_compgen_help -c help "$1" |
12 |
| - compopt +o nospace |
13 |
| - return |
14 |
| - fi |
| 7 | + local vars |
| 8 | + _comp_compgen -v vars -- -v || return "$?" |
15 | 9 |
|
16 |
| - local i j k |
| 10 | + # Remove variables that do not contain a valid directory path. |
| 11 | + local _i |
| 12 | + for _i in "${!vars[@]}"; do |
| 13 | + # Note: ${!vars[_i]} produces the "nounset" error when vars[_i] is an |
| 14 | + # empty array name. |
| 15 | + [[ -d ${!vars[_i]-} ]] || unset -v 'vars[_i]' |
| 16 | + done |
17 | 17 |
|
18 |
| - compopt -o filenames |
| 18 | + _comp_compgen -U vars set "${vars[@]}" |
| 19 | +} |
| 20 | + |
| 21 | +# This generator function observes the CDPATH variable, to additionally |
| 22 | +# complete directories under those specified in CDPATH. |
| 23 | +_comp_cmd_cd__compgen_cdpath() |
| 24 | +{ |
| 25 | + local _p |
19 | 26 |
|
20 |
| - # Use standard dir completion if no CDPATH or parameter starts with /, |
| 27 | + # Generate CDPATH completions when the parameter does not start with /, |
21 | 28 | # ./ or ../
|
22 |
| - if [[ ! ${CDPATH-} || $cur == ?(.)?(.)/* ]]; then |
23 |
| - _comp_compgen_filedir -d |
24 |
| - return |
25 |
| - fi |
| 29 | + [[ ! ${CDPATH-} || $cur == ?(.)?(.)/* ]] && return 1 |
26 | 30 |
|
27 |
| - local mark_dirs="" mark_symdirs="" |
28 |
| - _comp_readline_variable_on mark-directories && mark_dirs=set |
29 |
| - _comp_readline_variable_on mark-symlinked-directories && mark_symdirs=set |
| 31 | + local _mark_dirs="" _mark_symdirs="" |
| 32 | + _comp_readline_variable_on mark-directories && _mark_dirs=set |
| 33 | + _comp_readline_variable_on mark-symlinked-directories && _mark_symdirs=set |
| 34 | + |
| 35 | + local -a _cdpaths=() |
30 | 36 |
|
31 | 37 | # we have a CDPATH, so loop on its contents
|
32 |
| - local paths dirs |
| 38 | + local paths dirs _d |
33 | 39 | _comp_split -F : paths "$CDPATH"
|
34 |
| - for i in "${paths[@]}"; do |
| 40 | + for _p in "${paths[@]}"; do |
35 | 41 | # create an array of matched subdirs
|
36 |
| - k=${#COMPREPLY[@]} |
37 |
| - _comp_compgen -v dirs -c "$i/$cur" -- -d |
38 |
| - for j in "${dirs[@]}"; do |
39 |
| - if [[ ($mark_symdirs && -L $j || $mark_dirs && ! -L $j) && ! -d ${j#"$i/"} ]]; then |
40 |
| - j+="/" |
| 42 | + _comp_compgen -v dirs -c "$_p/$cur" -- -d |
| 43 | + for _d in "${dirs[@]}"; do |
| 44 | + if [[ ($_mark_symdirs && -L $_d || $_mark_dirs && ! -L $_d) && ! -d ${_d#"$_p/"} ]]; then |
| 45 | + _d+="/" |
41 | 46 | fi
|
42 |
| - COMPREPLY[k++]=${j#"$i/"} |
| 47 | + _cdpaths+=("${_d#"$_p/"}") |
43 | 48 | done
|
44 | 49 | done
|
| 50 | + _comp_unlocal paths dirs |
45 | 51 |
|
46 |
| - _comp_compgen -a filedir -d |
47 |
| - |
48 |
| - if ((${#COMPREPLY[@]} == 1)); then |
49 |
| - i=${COMPREPLY[0]} |
50 |
| - if [[ $i == "$cur" && $i != "*/" ]]; then |
51 |
| - COMPREPLY[0]="${i}/" |
| 52 | + if ((${#_cdpaths[@]} == 1)); then |
| 53 | + _p=${_cdpaths[0]} |
| 54 | + if [[ $_p == "$cur" && $_p != */ ]]; then |
| 55 | + _cdpaths[0]=$_p/ |
52 | 56 | fi
|
53 | 57 | fi
|
| 58 | + |
| 59 | + _comp_compgen_set "${_cdpaths[@]}" |
| 60 | +} |
| 61 | + |
| 62 | +_comp_cmd_cd() |
| 63 | +{ |
| 64 | + local cur prev words cword comp_args |
| 65 | + _comp_initialize -- "$@" || return |
| 66 | + |
| 67 | + if [[ $cur == -* ]]; then |
| 68 | + _comp_compgen_help -c help "$1" |
| 69 | + compopt +o nospace |
| 70 | + return |
| 71 | + fi |
| 72 | + |
| 73 | + compopt -o filenames |
| 74 | + _comp_cmd_cd__compgen_cdable_vars |
| 75 | + _comp_cmd_cd__compgen_cdpath |
| 76 | + _comp_compgen -a filedir -d |
54 | 77 | }
|
55 |
| -if shopt -q cdable_vars; then |
56 |
| - complete -v -F _comp_cmd_cd -o nospace cd pushd |
57 |
| -else |
58 |
| - complete -F _comp_cmd_cd -o nospace cd pushd |
59 |
| -fi |
| 78 | +complete -F _comp_cmd_cd -o nospace cd pushd |
0 commit comments