具有否定 null glob 的 zsh glob 限定符的工作方式与使用 null glob 的方式相同

具有否定 null glob 的 zsh glob 限定符的工作方式与使用 null glob 的方式相同

注意:请不要回应这是 XY 情况。我试图理解通配模式是如何工作的,而不是试图实现特定的结果。我对使用 zstyle 等实现此目的的其他方法也不感兴趣。

最近我处于一种我想要的情况仅完成来自特定目录的符号链接作为函数的参数。只要目录至少有一个符号链接,类似的模式就可以用作of 的*(@)参数。如果目录中没有符号链接,则完成过滤器会失败,因为它现在完成常规文件(非符号链接)...所以我浏览了文档,似乎添加(NULL GLOB) 限定符就是答案。我将模式更改为,但当没有符号链接时仍然返回常规文件。令人惊讶的是,在 N (模式)前面添加一个否定可以使其在所有情况下都能正常工作。但我有点不确定这是否是因为我遇到了 zsh bug(并且此模式将来将停止工作),或者此模式是否真的有意义并且值得依赖。-g_filesN*(@N)*(@^N)

如果有人能够确认下面的模式是否有效,而不是因为它是 zsh bug,以及它的含义,那就太好了。这是一个测试文件foocomp.zsh

function foo {
    echo "foo called with $1"
}

function _foo {
    _files -g '*(@^N)' -W $PWD/foodir/
}

function bar {
    echo "bar called with $1"
}

function _bar {
    _files -g '*(@N)' -W $PWD/foodir/
}

compdef _foo foo

compdef _bar bar

脚步:

  1. 将文件保存foocomp.zsh到某个目录
  2. mkdir foodir && cd foodir
  3. touch hello && ln -s hello world && cd ..
  4. 来源foocomp.zsh
  5. 输入 foo 或 bar 并按 Tab,它应该只完成世界。
  6. 删除符号链接世界
  7. 输入 foo 并再次按 Tab,它不会完成任何操作(这是所需的行为)
  8. 输入 bar 并再次按 Tab,它将完成 hello。

答案1

_files函数是一个包装器_path_files_path_files代码不仅涉及 glob,还涉及各种其他逻辑和 zstyle 设置;添加 a-g glob会影响pats数组包含的内容,设置一个gopts命中各个分支的标志,并且还有额外的代码检查 in 中的元素是否pats包含 glob 限定符。您确实需要跟踪此函数调用以查看不同参数发生了什么,以及 glob 限定符如何影响以下代码。

% less ${^fpath}/_path_files(N)

_path_files全局 zstyle 可能会以意想不到且难以调试的方式干扰代码。例如,您可以*(@^N)foo命令设置 glob,然后几个月后您或某个随机插件进行了冲突的 zstyle 更改,然后几个月后您注意到不再*(@^N)按预期运行并且不知道原因。通过跟踪,我们可以看到发生了什么并测试我的非正式推理是否正确:

% functions -t _path_files

事实上这很烦人;_complete_debug相反,会将完成跟踪放入临时文件中(control+ x ?):

% bindkey | grep _debug
"^X?" _complete_debug

因此,我们有四种情况,foo以及bar中存在和不存在链接的情况foodir。所以在按下一些键之后...

% mv zsh3827foo2 withlink-foo
% mv zsh3827bar3 withlink-bar
% mv zsh3827foo4 nolink-foo
% mv zsh3827bar5 nolink-bar

如果在调用之间修改完成,则这些实际上可能更容易区分,_complete_debug以便命令名称差异不会使问题复杂化。无论如何,最终一个显着的区别是

-       +_path_files:468> compfiles -p tmp1 accex '' ' ' .. fake '*(#q@^N)'
-       +_path_files:472> tmp1=
+       +_path_files:468> compfiles -p tmp1 accex '' ' ' .. fake '*(#q@N)'
+       +_path_files:472> tmp1=( )

对于^正确的foo集合tmp1=,而不正确的集合则bar 设置一个空数组tmp1=( ),然后在重新加入共享完成轨道之前在其他地方进行长分支。所以这是一个相当微妙的点,通常的错误消息被吞没在 compfiles;中的某个地方。在命令行上可以看到,仅在不存在符号链接的目录中^@关闭:NULL_GLOB

% a=( *(#q@^N) )
zsh: no matches found: *(#q@^N)
% a=( *(#q@N) )

Src/Zle/computil.c函数中的 Overcompfiles被记录为返回一个数组parnam1

 * SYNOPSIS:
 *     1. compfiles -p  parnam1 parnam2 skipped matcher sdirs parnam3 varargs [.
.varargs]
...
 *     1. Set parnam1 to an array of patterns....
 *        ${(P)parnam1} is an in/out parameter.

所以我想如果compfiles总是应该返回一个数组,这可能是一个错误?但这可能是应该与 ZSH 开发人员讨论的问题。否则,对于这种情况,我仍然会使用 zstyle 解决方案来避免全局 zstyle 更改可能影响此完成代码。

相关内容