Zsh:如何强制文件在一组字符后处处完成?

Zsh:如何强制文件在一组字符后处处完成?,zsh,zshrc,zsh-completion,Zsh,Zshrc,Zsh Completion,我正试图找出如何使文件完成在命令行中一组字符之后的任何word位置上工作。如shell中所列,这些字符将是[=+-\'\'”()](空格为制表符和空格)。Zsh将执行此操作,但仅在反勾字符“`”或$”()之后执行此操作。mksh不在字符[+-]之后执行此操作 根据命令行上的单词位置,我指的是您键入的每一组字符,它们由空格和一些其他字符分隔。例如 打印Hello World 在位置1-3处有三个单词。在位置1处,当您第一次输入内容时,补全非常完美。文件补全可以在我提到的所有字符之后工作。在第一个单

我正试图找出如何使文件完成在命令行中一组字符之后的任何
word
位置上工作。如shell中所列,这些字符将是
[=+-\'\'”()]
(空格为制表符和空格)。Zsh将执行此操作,但仅在反勾字符“`”或
$”(
)之后执行此操作。mksh不在字符
[+-]
之后执行此操作

根据命令行上的单词位置,我指的是您键入的每一组字符,它们由空格和一些其他字符分隔。例如

打印Hello World

在位置1-3处有三个
单词
。在位置1处,当您第一次输入内容时,补全非常完美。文件补全可以在我提到的所有字符之后工作。在第一个
单词
之后,补全系统变得更加有限,因为它很智能。这对命令很有用,但限制了您可以做的事情文件完成并不是特别有帮助

以下是一些文件完成对我不起作用但我认为应该起作用的例子:

:${a:=/…}

echo“${a:-/…}”

make LDFLAGS+='-nostlib/../crt1.o/../crti.o…'

env a=/…b=/…

我已经看过重新绑定
“^I”
(选项卡)Zsh附带了一些不同的完成小部件,并更改了我的
zstyle':completion:'
行。到目前为止,还没有任何东西能改变这个默认的Zsh行为。我想我需要创建一个完成函数,我可以将它添加到我的
zstyle':completion:'completer…
行的末尾,作为最后的补偿伊顿

在completion函数中,一种方法是将当前的
单词
切掉,完成它,然后如果可能的话,将其重新插入行中。它也可能更像
\u precommand
,将第二个
单词
移动到第一个
单词
,以便正常的命令执行莱顿工作

我可以修改
\u precommand
,以便您可以在任何
word
位置完成命令。这是新文件,我将其命名为
\u commando
,并将其目录添加到我的fpath:

#compdef -                                                              

# precommands is made local in _main_complete
precommands+=($words[1,$(( CURRENT -1 ))])

shift words
CURRENT=1

_normal
为了使用它,我将它添加到了我的
:completion:'completer…
行的末尾,因此它适用于
$path
中的每个程序。基本上,您键入的任何
word
都被认为是第一个
word
,因此命令完成在命令行的每个
word
位置都有效


我正试图找到一种方法来完成同样的文件完成工作,但一开始看起来有点复杂。我真的不知道该怎么做,所以我想在这方面获得一些帮助。

我仔细查看了Zsh的一些内置函数,发现了一些具有特殊完成行为的函数。它们属于
typeset
组,它在默认的
fpath
中有一个功能
\u typeset
。我只需要提取几行就可以完成我想做的事情。这些是我提取的行:

...
elif [[ "$PREFIX" = *\=* ]]; then
compstate[parameter]="${PREFIX%%\=*}"
compset -P 1 '*='
_value
...
这几行允许在命令中的每个斜杠后完成排版,如下所示:

typeset file1=/... file2=~/... file3=/...
_reallyforcefilecompletion() {
    local prefix_char

    for prefix_char in ' ' $'\t' '=' '+' '-' "'" '"' ')' ':'; do
        if [[ "$PREFIX" = *${prefix_char}* ]]; then
            if [[ "$PREFIX" = *[\'\"]* ]]; then
                compset -q -P "*${prefix_char}"
            else
                compset -P "*${prefix_char}"
            fi
            _value
            break
        fi
    done
}
zstyle ':completion:*' completer _complete _reallyforcefilecompletion
我由此推断创建了以下函数。您可以将其修改为放入
fpath
。我只是在我的zshrc中这样定义它:

typeset file1=/... file2=~/... file3=/...
_reallyforcefilecompletion() {
    local prefix_char

    for prefix_char in ' ' $'\t' '=' '+' '-' "'" '"' ')' ':'; do
        if [[ "$PREFIX" = *${prefix_char}* ]]; then
            if [[ "$PREFIX" = *[\'\"]* ]]; then
                compset -q -P "*${prefix_char}"
            else
                compset -P "*${prefix_char}"
            fi
            _value
            break
        fi
    done
}
zstyle ':completion:*' completer _complete _reallyforcefilecompletion
您可以通过将其添加到
zstyle
行来使用它,如下所示:

typeset file1=/... file2=~/... file3=/...
_reallyforcefilecompletion() {
    local prefix_char

    for prefix_char in ' ' $'\t' '=' '+' '-' "'" '"' ')' ':'; do
        if [[ "$PREFIX" = *${prefix_char}* ]]; then
            if [[ "$PREFIX" = *[\'\"]* ]]; then
                compset -q -P "*${prefix_char}"
            else
                compset -P "*${prefix_char}"
            fi
            _value
            break
        fi
    done
}
zstyle ':completion:*' completer _complete _reallyforcefilecompletion
这样,它只能作为最后的手段使用,以便更智能的补全可以在它之前尝试。以下是对该函数的一些解释,从涉及的几个变量和命令开始:

prefix\u char
:这将设置为我们要在后面完成的每个前缀字符。例如,
env a=123
具有前缀字符
=

前缀
:最初,这将设置为当前单词的一部分,从单词的开头到光标的位置;可以更改为为所有匹配项提供一个公共前缀

IPREFIX
(未在代码中显示):
compset
将字符串匹配项从
PREFIX
移动到
IPREFIX
,以便完成
PREFIX
的其余部分

compset
:此命令简化了特殊参数的修改,而其返回状态允许对其执行测试

\u value
:对这一点不太确定。文档说明它在完成过程中起到某种作用

函数:在第二行,我们声明
prefix\u char
local
以避免变量污染。在第三行,我们开始
for
循环,选择每个
prefix\u char
之后要完成的。在下一个
if
块中,我们检查变量
prefix
是否以
前缀字符
我们希望在之后完成,如果
前缀
包含任何引号。由于
前缀
包含引号,我们使用
compset-q
基本上允许忽略引号,以便我们可以在其中完成。
compset-P
去除
前缀
,并将其移动到
IPREFIX
,基本上是这样它会被忽略,完成也会起作用

下一个
elif
语句用于以PREFIX_char结尾但不包含引号的
PREFIX
语句,因此我们只使用
compset-p
。我添加了
return 0
来打破循环。更正确的方法是在
case
语句中创建此函数,但我们没有使用
compset
return除了
\u value
,你看不到任何关于文件完成的信息。在大多数情况下,我们只是告诉系统忽略
单词的一部分


基本上这就是函数所做的