默认情况下,在 Zsh 中,tab密钥绑定到expand-or-complete. 我想以编程方式访问由 press 生成的完成候选列表tab,以便我可以编写自己的函数并自行过滤列表。我知道 Zsh 附带了一个“完成框架”,但我想自己做。
还有一个list-choices函数/小部件,它产生与expand-or-complete标签循环功能相同的输出,但不提供选项卡循环功能。
我已经在 Google 上进行了相当广泛的搜索,并且还浏览了 Zsh 源代码,但结果很枯燥。任何帮助,将不胜感激。
我偶然发现了一种解决方案:zsh-capture-completion。实际上,Unix Stack Exchange 站点上还有另外两个几乎相同的问题,这两个问题都有我在这里给出的答案。
脚本源代码zsh-capture-completion可以在这里找到:
#!/bin/zsh\n\nzmodload zsh/zpty || { echo \'error: missing module zsh/zpty\' >&2; exit 1 }\n\n# spawn shell\nzpty z zsh -f -i\n\n# line buffer for pty output\nlocal line\n\nsetopt rcquotes\n() {\n zpty -w z source $1\n repeat 4; do\n zpty -r z line\n [[ $line == ok* ]] && return\n done\n echo \'error initializing.\' >&2\n exit 2\n} =( <<< \'\n# no prompt!\nPROMPT=\n# load completion system\nautoload compinit\ncompinit -d ~/.zcompdump_capture\n# never run a command\nbindkey \'\'^M\'\' undefined\nbindkey \'\'^J\'\' undefined\nbindkey \'\'^I\'\' complete-word\n# send a line with null-byte at the end before and after completions are output\nnull-line () {\n echo -E - $\'\'\\0\'\'\n}\ncompprefuncs=( null-line )\ncomppostfuncs=( null-line exit )\n# never group stuff!\nzstyle \'\':completion:*\'\' list-grouped false\n# don\'\'t insert tab when attempting completion on empty line\nzstyle \'\':completion:*\'\' insert-tab false\n# no list separator, this saves some stripping later on\nzstyle \'\':completion:*\'\' list-separator \'\'\'\'\n# we use zparseopts\nzmodload zsh/zutil\n# override compadd (this our hook)\ncompadd () {\n # check if any of -O, -A or -D are given\n if [[ ${@[1,(i)(-|--)]} == *-(O|A|D)\\ * ]]; then\n # if that is the case, just delegate and leave\n builtin compadd "$@"\n return $?\n fi\n # ok, this concerns us!\n # echo -E - got this: "$@"\n # be careful with namespacing here, we don\'\'t want to mess with stuff that\n # should be passed to compadd!\n typeset -a __hits __dscr __tmp\n # do we have a description parameter?\n # note we don\'\'t use zparseopts here because of combined option parameters\n # with arguments like -default- confuse it.\n if (( $@[(I)-d] )); then # kind of a hack, $+@[(r)-d] doesn\'\'t work because of line noise overload\n # next param after -d\n __tmp=${@[$[${@[(i)-d]}+1]]}\n # description can be given as an array parameter name, or inline () array\n if [[ $__tmp == \\(* ]]; then\n eval "__dscr=$__tmp"\n else\n __dscr=( "${(@P)__tmp}" )\n fi\n fi\n # capture completions by injecting -A parameter into the compadd call.\n # this takes care of matching for us.\n builtin compadd -A __hits -D __dscr "$@"\n setopt localoptions norcexpandparam extendedglob\n # extract prefixes and suffixes from compadd call. we can\'\'t do zsh\'\'s cool\n # -r remove-func magic, but it\'\'s better than nothing.\n typeset -A apre hpre hsuf asuf\n zparseopts -E P:=apre p:=hpre S:=asuf s:=hsuf\n # append / to directories? we are only emulating -f in a half-assed way\n # here, but it\'\'s better than nothing.\n integer dirsuf=0\n # don\'\'t be fooled by -default- >.>\n if [[ -z $hsuf && "${${@//-default-/}% -# *}" == *-[[:alnum:]]#f* ]]; then\n dirsuf=1\n fi\n # just drop\n [[ -n $__hits ]] || return\n # this is the point where we have all matches in $__hits and all\n # descriptions in $__dscr!\n # display all matches\n local dsuf dscr\n for i in {1..$#__hits}; do\n # add a dir suffix?\n (( dirsuf )) && [[ -d $__hits[$i] ]] && dsuf=/ || dsuf=\n # description to be displayed afterwards\n (( $#__dscr >= $i )) && dscr=" -- ${${__dscr[$i]}##$__hits[$i] #}" || dscr=\n echo -E - $IPREFIX$apre$hpre$__hits[$i]$dsuf$hsuf$asuf$dscr\n done\n}\n# signal success!\necho ok\')\n\nzpty -w z "$*"$\'\\t\'\n\ninteger tog=0\n# read from the pty, and parse linewise\nwhile zpty -r z; do :; done | while IFS= read -r line; do\n if [[ $line == *$\'\\0\\r\' ]]; then\n (( tog++ )) && return 0 || continue\n fi\n # display between toggles\n (( tog )) && echo -E - $line\ndone\n\nreturn 2\nRun Code Online (Sandbox Code Playgroud)\n以下是脚本使用的示例:
\n\xe2\x95\x90\xe2\x95\x90\xe2\x96\xba % cd ~/.zsh_plugins\n\xe2\x95\x90\xe2\x95\x90\xe2\x96\xba % zsh ./zsh-capture-completion/capture.zsh \'cd \'\nzaw/\nzsh-capture-completion/\nzsh-syntax-highlighting/\nzsh-vimode-visual/\nRun Code Online (Sandbox Code Playgroud)\n请注意上面命令中的空格字符。cd通过空格,脚本提供了您可以从当前目录进入的文件夹列表。如果没有它,脚本将提供以 开头的命令的所有完成cd。
我还应该注意到,即使所提供的脚本/插件的作者也认为他的解决方案“hacky”。如果有人知道更短或更直接的解决方案,我会很高兴接受它作为答案。
\n