6

我试图弄清楚如何word在一组字符之后让文件完成在命令行的任何位置工作。如 shell 中所列,这些字符将是[ =+-\'\"()](空格是制表符和空格)。Zsh 会这样做,但只能在反引号字符 '`' 或$(. mksh 执行此操作,除非不在 characters 之后[+-]

通过命令行上的单词位置,我说的是您输入的每组字符,这些字符由空格和一些其他字符分隔。例如,

print Hello World,

words在位置 1-3有3 个。在位置 1,当您第一次输入内容时,完成非常完美。在我提到的所有字符之后,文件完成工作。在第一个之后word,完成系统变得更加智能,因为它变得更加智能。这对命令很有用,但限制文件完成的位置并不是特别有用。

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

: ${a:=/...}

echo "${a:-/...}"

make LDFLAGS+='-nostdlib /.../crt1.o /.../crti.o ...'

env a=/... b=/... ...

我已经查看了'^I'使用 Zsh 附带的几个不同的完成小部件重新绑定(选项卡)并更改了我的zstyle ':completion:*'行。到目前为止,没有任何工作可以改变这个默认的 Zsh 行为。我在想我需要创建一个完成功能,我可以将其添加到zstyle ':completion:*' completer ...行尾作为最后的完成。

在完成功能中,一种方法是剪掉word我想要完成的当前,完成它,然后如果可能的话,将完成重新插入到行中。它也可能更像_precommand是将第二个转移word到第一个word,以便正常的命令完成工作。

我能够进行修改_precommand,以便您可以在任何word位置完成命令。这是新文件,我将其命名_commando并将其目录添加到我的 fpath 中:

#compdef -                                                              

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

shift words
CURRENT=1

_normal

为了使用它,我将它添加到':completion:*' completer ...我的 zshrc 中的行尾,以便它适用于$path. 基本上word,您输入的任何内容都被视为 first word,因此命令完成在word命令行的每个位置都有效。

我试图找出一种方法来完成文件完成,但乍一看它看起来有点复杂。我真的不知道该去哪里,所以我希望得到一些帮助。

4

1 回答 1

3

我仔细查看了一些 Zsh 的内置函数,并注意到一些具有特殊完成行为的函数。它们属于该typeset组,该组具有_typeset默认功能fpath。我只需要为我想做的事情提取几行。这些是我提取的行:

...
elif [[ "$PREFIX" = *\=* ]]; then
compstate[parameter]="${PREFIX%%\=*}"
compset -P 1 '*='
_value
...

这几行允许在命令中的每个斜线后完成排版,如下所示:

typeset file1=/... file2=~/... file3=/...

我据此推断以创建以下函数。您可以修改它以放入您的fpath. 我只是在我的 zshrc 中这样定义它:

_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如下行来使用它:

zstyle ':completion:*' completer _complete _reallyforcefilecompletion

这样,它仅用作最后的手段,以便更智能的完成可以在它之前尝试。以下是从几个变量和所涉及的命令开始的函数的一些解释:

prefix_char: 这被设置为我们想要完成的每个前缀字符。例如,env a=123具有前缀字符=

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

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

compset:该命令简化了特殊参数的修改,而它的返回状态允许对它们进行测试。

_value: 这个不太清楚。该文档指出它在完成中起着某种作用。

完成系统的文档

功能:在第二行,我们声明prefix_char local避免变量污染。在第三行,我们开始一个for循环,选择prefix_char我们想要完成的每一个。在下一个if块中,我们检查变量是否以我们想要完成PREFIX的其中一个结尾,以及是否包含任何引号。由于包含引号,我们使用基本上允许忽略引号,以便我们可以完成它们。剥离并将其移动到,基本上这样它就会被忽略并且完成可以工作。prefix_charsPREFIXPREFIXcompset -qcompset -PPREFIXIPREFIX

elif一条语句用于PREFIX以 prefix_char 结尾但不包含引号,因此我们只使用compset -P. 我添加了return 0打破循环。制作此函数的更正确方法是在case语句中,但我们没有使用compset返回值,所以这是可行的。除了_value. 在大多数情况下,我们只是告诉系统忽略word.


基本上这就是函数的作用。我们有一行看起来像:

env TERM=linux PATH=/<---cursor here

光标位于该斜线的末尾。此函数允许忽略 PREFIX,即 PATH=,因此我们有:

env TERM=linux /<---cursor here

您可以在此处完成已PATH=删除的文件。该函数实际上并没有删除PATH=它,它只是将它重新归类为可以忽略的东西。

使用此功能,您现在可以完成我在问题中列出的所有示例以及更多内容。

最后要提到的一件事,force-list在你的 zshrc 中添加这一行会以某种方式削弱这个功能。它仍然有效,但似乎窒息。无论如何,这个新的强制列表功能要好得多。

zstyle ':completion:*' force-list always

编辑:有几行我忘了复制到函数中。可能应该在发布前检查。我觉得现在很好。

于 2015-09-20T02:59:14.153 回答