Một cách gián tiếp nhờ JakeGould tôi tình cờ tìm thấy một giải pháp : zsh-capture-completion
. Trên thực tế có hai khác câu hỏi gần như giống hệt trên các trang web Unix stack Exchange, cả với câu trả lời tôi đã đưa ra ở đây.
Mã nguồn script zsh-capture-completion
có thể được tìm thấy ở đây:
#!/bin/zsh
zmodload zsh/zpty || { echo 'error: missing module zsh/zpty' >&2; exit 1 }
# spawn shell
zpty z zsh -f -i
# line buffer for pty output
local line
setopt rcquotes
() {
zpty -w z source $1
repeat 4; do
zpty -r z line
[[ $line == ok* ]] && return
done
echo 'error initializing.' >&2
exit 2
} =( <<< '
# no prompt!
PROMPT=
# load completion system
autoload compinit
compinit -d ~/.zcompdump_capture
# never run a command
bindkey ''^M'' undefined
bindkey ''^J'' undefined
bindkey ''^I'' complete-word
# send a line with null-byte at the end before and after completions are output
null-line () {
echo -E - $''\0''
}
compprefuncs=( null-line )
comppostfuncs=( null-line exit )
# never group stuff!
zstyle '':completion:*'' list-grouped false
# don''t insert tab when attempting completion on empty line
zstyle '':completion:*'' insert-tab false
# no list separator, this saves some stripping later on
zstyle '':completion:*'' list-separator ''''
# we use zparseopts
zmodload zsh/zutil
# override compadd (this our hook)
compadd () {
# check if any of -O, -A or -D are given
if [[ ${@[1,(i)(-|--)]} == *-(O|A|D)\ * ]]; then
# if that is the case, just delegate and leave
builtin compadd "$@"
return $?
fi
# ok, this concerns us!
# echo -E - got this: "$@"
# be careful with namespacing here, we don''t want to mess with stuff that
# should be passed to compadd!
typeset -a __hits __dscr __tmp
# do we have a description parameter?
# note we don''t use zparseopts here because of combined option parameters
# with arguments like -default- confuse it.
if (( $@[(I)-d] )); then # kind of a hack, $+@[(r)-d] doesn''t work because of line noise overload
# next param after -d
__tmp=${@[$[${@[(i)-d]}+1]]}
# description can be given as an array parameter name, or inline () array
if [[ $__tmp == \(* ]]; then
eval "__dscr=$__tmp"
else
__dscr=( "${(@P)__tmp}" )
fi
fi
# capture completions by injecting -A parameter into the compadd call.
# this takes care of matching for us.
builtin compadd -A __hits -D __dscr "$@"
setopt localoptions norcexpandparam extendedglob
# extract prefixes and suffixes from compadd call. we can''t do zsh''s cool
# -r remove-func magic, but it''s better than nothing.
typeset -A apre hpre hsuf asuf
zparseopts -E P:=apre p:=hpre S:=asuf s:=hsuf
# append / to directories? we are only emulating -f in a half-assed way
# here, but it''s better than nothing.
integer dirsuf=0
# don''t be fooled by -default- >.>
if [[ -z $hsuf && "${${@//-default-/}% -# *}" == *-[[:alnum:]]#f* ]]; then
dirsuf=1
fi
# just drop
[[ -n $__hits ]] || return
# this is the point where we have all matches in $__hits and all
# descriptions in $__dscr!
# display all matches
local dsuf dscr
for i in {1..$#__hits}; do
# add a dir suffix?
(( dirsuf )) && [[ -d $__hits[$i] ]] && dsuf=/ || dsuf=
# description to be displayed afterwards
(( $#__dscr >= $i )) && dscr=" -- ${${__dscr[$i]}##$__hits[$i] #}" || dscr=
echo -E - $IPREFIX$apre$hpre$__hits[$i]$dsuf$hsuf$asuf$dscr
done
}
# signal success!
echo ok')
zpty -w z "$*"$'\t'
integer tog=0
# read from the pty, and parse linewise
while zpty -r z; do :; done | while IFS= read -r line; do
if [[ $line == *$'\0\r' ]]; then
(( tog++ )) && return 0 || continue
fi
# display between toggles
(( tog )) && echo -E - $line
done
return 2
Dưới đây là một ví dụ về việc sử dụng tập lệnh:
══► % cd ~/.zsh_plugins
══► % zsh ./zsh-capture-completion/capture.zsh 'cd '
zaw/
zsh-capture-completion/
zsh-syntax-highlighting/
zsh-vimode-visual/
Lưu ý ký tự khoảng trắng trong lệnh trên. Với không gian, tập lệnh cung cấp danh sách các thư mục mà bạn có thể cd
nhập từ thư mục hiện tại. Không có nó, kịch bản sẽ cung cấp tất cả các hoàn thành cho một lệnh bắt đầu bằng cd
.
Tôi cũng nên lưu ý rằng ngay cả tác giả của tập lệnh / plugin được cung cấp cũng coi giải pháp của mình là "hacky". Nếu bất cứ ai biết về giải pháp ngắn hơn hoặc thẳng hơn, tôi sẽ rất vui lòng chấp nhận nó như là câu trả lời.