zsh
では、cd
コマンドには2つの引数形式があります。cd OLD NEW
は${PWD/OLD/NEW}
に変わります。新しいスタイルの補完システムでは、zshはNEW
を補完できます。2番目の引数は、既存のディレクトリを取得するためにOLD
を置き換えることができるものに基づいて補完されます。ただし、最初の引数は既存のディレクトリに対してのみ完了します。
既存のディレクトリを補完することに加えて、OLD
の可能な値である補完をzshに提供させるにはどうすればよいですか?
たとえば、現在のディレクトリが/path/to/foo
であり、ディレクトリ/also/to/foo
および/path/to/foo/prime
もある場合、cd p
Tabp
からprime
を完了します。 cd path also
を実行する場合は、zshでpath
も補完として提供したいと思います。どうやって?
2番目の引数の入力済みの値を使用して最初の引数の可能性を制限することはプラスですが、最初の引数を個別に完了することも問題ありません。
$PWD
のコンポーネントをcd
補完リストに追加できると思いますが、これには_cd
をいじる必要があるようです。つまり、カスタマイズされたバージョンの_cd
が最初に$fpath
に表示される必要があります。
% cd && mkdir zcomp
% cp $fpath[-1]/_cd zcomp
% fpath=(~/zcomp $fapth)
次に、~/zcomp/_cd
の上部に関数を追加します
_our_pwd() {
_values ourpwd ${(ps:/:)PWD}
}
次に、_alternative
行の直前に、選択肢のリストに返されるものを追加します
...
alt=("$service-options:$service option:_cd_options" "$alt[@]")
fi
alt=(ourpwd:pwd:_our_pwd "$alt[@]")
_alternative "$alt[@]" && ret=0
return ret
...
ただし、これにより常にpwd
コンポーネントがcd
補完に追加されます。
% cd
Users jdoe Applications/ Desktop/ Documents/ Downloads/ Library/
...
追加のロジックを使用すると、常にではなく、すでに2番目の引数が存在する場合にのみ、$PWD
コンポーネントを追加できます。
しかしながら!これは常にcd
完了をめちゃくちゃにするので、上流の_cd
完了にモンキーパッチを適用する必要があります。別のオプションは、おそらくcd
と呼ばれる2つの引数cdsub
によって提供される関数の新しい名前を作成し、そのためにPWD
コンポーネントの補完のみを表示することです。 。これを~/.zshrc
に追加します
function cdsub { builtin cd "$@" }
そして、内臓の_cd
_cdsub
の完了 は$fpath
のどこかに配置されます:
#compdef cdsub
#
# Modified version of _cd from ZSH 5.3.1 with specific support for the
# `cd old new` form whereby PWD elements are provided for completion.
_cd_options() {
_arguments -s \
'-q[quiet, no output or use of hooks]' \
'-s[refuse to use paths with symlinks]' \
'(-P)-L[retain symbolic links ignoring CHASE_LINKS]' \
'(-L)-P[resolve symbolic links as CHASE_LINKS]'
}
setopt localoptions nonomatch
local expl ret=1 curarg
integer argstart=2 noopts
if (( CURRENT > 1 )); then
# if not in command position, may have options.
# Careful: -<-> is not an option.
while [[ $words[$argstart] = -* && argstart -lt CURRENT ]]; do
curarg=$words[$argstart]
[[ $curarg = -<-> ]] && break
(( argstart++ ))
[[ $curarg = -- ]] && noopts=1 && break
done
fi
if [[ CURRENT -eq $((argstart+1)) ]]; then
# cd old new: look for old in $PWD and see what can replace it
local rep
# Get possible completions using Word in position 2
rep=(${~PWD/$words[$argstart]/*}~$PWD(-/))
# Now remove all the common parts of $PWD and the completions from this
rep=(${${rep#${PWD%%$words[$argstart]*}}%${PWD#*$words[$argstart]}})
(( $#rep )) && _wanted -C replacement strings expl replacement compadd -a rep
else
_values ourpwd ${(ps:/:)PWD} && ret=0
return ret
fi