我正在尝试创建一个自动加载完成文件对于 zsh。为此,我_myprog
在 fpath 中的文件夹中添加了一个文件。
这个文件大致是这样的:
#compdef myprog
_myprog () {
local cmd
if (( CURRENT > 2)); then
cmd=${words[2]}
curcontext="${curcontext%:*:*}:myprog-$cmd"
(( CURRENT-- ))
shift words
case "${cmd}" in
list|ls)
_arguments : "--limit[Max depth]" "--folders[Print flat list of folders]"
_describe -t commands "myprog list" subcommands
;;
insert)
_arguments : "--force[Overwrite file]" "--append[Append to existing data]"
_describe -t commands "myprog insert" subcommands
_myprog_complete_folders
;;
esac
else
local -a subcommands
subcommands=(
"insert:Insert a new file"
"list:List existing files"
)
_describe -t command 'myprog' subcommands
_arguments : "--yes[Assume yes]"
_myprog_complete_files
fi
}
_myprog_complete_files () {
_values 'files' $(myprog ls)
}
_myprog_complete_folders () {
_values 'folders' $(myprog ls --folders)
}
_myprog
所以,我的程序有两种我想要自动完成的场景:
当不使用子命令时,我想指定远程位置的路径。这是由函数完成的,
_myprog_complete_files
感谢函数_value
。文件列表是通过运行提供的myprog ls
,它在新行上打印每个远程文件。插入新的远程文件时,我希望能够自动完成文件夹名称,这也是在
_myprog_complete_folders
使用函数中完成的_value
,但这次文件夹列表是使用生成的myprog ls --folder
,它只打印文件夹。
到目前为止一切顺利...除了当我用来<tab><tab>
显示值列表并且我试图在文件夹名称后面键入文件名时,zsh 在文件夹名称后面插入一个空格。
例如:
$ myprog insert web<tab><tab><tab>
-- folders --
web/ web/foo/ web/bar/
应该选择web/foo
,它有效地执行了此操作并自动完成,myprog insert web/foo/
但请注意尾随空格!因此,如果我在选择要使用的文件夹后尝试直接键入要插入的文件的名称(<tab>
假设我想调用它)baz
,那么我最终会发现myprog insert web/foo/ baz
这根本不是我的目标。
我尝试浏览 zsh 文档,但没有成功。例如,我尝试 zstyle ':completion::complete:myprog-insert:' add-space false
在 .zshrc 和文件中进行设置,但均无济于事_myprog
。设置与未设置时我什至看不出有什么区别。
我猜我一定错过了一些东西,因为能够在自动完成后直接键入以指定参数等似乎是一个理想的功能。
答案1
add-space
中的代码似乎$fpath[-1]/_expand
与您通过 ; 的完成无关_values
。这可以通过add-space
在所有地方设置为 false 来检查,或者通过调用_complete_debug
并查看完成过程经历了哪些代码:
% bindkey -M viins "^t" _complete_debug
% foo
Trace output left in /tmp/zsh438foo2 (up-history to view)
一种解决方案是使用-s ...
的功能_values
,它可以选择插入通常用于连接多个值的分隔符,然后在使用分隔符时禁用该功能:
#compdef foo
local curcontext="$curcontext" state line
choices=(aaa bbb ccc)
_arguments '1:dir:->folders' && return 0
case "$state" in
folders)
if ! compset -P '*/'; then
_values -s / folders $choices
fi
;;
esac
其中 afoo a
tab应该附加一个斜杠,然后从/
现在开始compset
测试应该阻止额外的完成。