
为什么以下代码无法完成命令foo
?当我输入它然后输入 时foo <Tab>
,外壳会挂起并且不会接受任何输入,直到我按下^C
(退出命令完成)。
我的假设是/dev/tty
shell 已经读取了它,并且它在某种程度上cat
也影响了读取它的能力,但在这种情况下我仍然需要一个解决方法。
_foo() {
_values 'foo' "$(cat < /dev/tty)"
}
compdef _foo foo
请注意,这个示例是故意简化的:实际用例是运行终端接口程序(想想 ncurses)而不是cat
.
答案1
在完成过程中,您位于 zsh 行编辑器中,因此终端行规则自己的行编辑器被禁用,就像您运行了:
stty -icanon -echo
在该模式下,cat
无法退出,因为您无法表示输入结束(^D
是行规则行编辑器行为的一部分icanon
),并且您不会看到您键入的内容的回显。
你可以这样做:
_foo() {
_values 'foo' "$(
{
s=$(stty -g)
stty sane
cat
stty $s
} < /dev/tty)"
zle -I
}
也就是说,在运行之前将终端设备置于预期的状态cat
(可以^D
按空行或按两次来结束输入)cat
并在运行后恢复。我们告诉 zle 它必须重新绘制其提示符和缓冲区,因为您在行规则行编辑器中键入的内容的回显会使事情变得混乱zle -I
(无效)。
答案2
这可能太简单了,cat
会读/dev/tty
很长一段时间。随着_foo
完成
#compdef foo
_values 'foo' "$(promptfor)"
和promptfor
一个
#!/usr/bin/env expect
set fh [open /dev/tty r+]
stty raw -echo
set key [read $fh 1] ;# read from tty
puts stdout $key ;# to ZSH
flush stdout
stty -raw echo
我的 ZSH onfoo
tab将完成promptfor
运行时按下的任何键。
如果您有某种守护进程,那么您可能需要一些更奇特的东西,例如 ZSH 和您的守护进程可以用来执行任何必要通信的套接字;read
在 ZSH 中可以从任意文件描述符或协进程读取...