![zsh 模糊模式匹配删除键入的字符](https://linux22.com/image/174441/zsh%20%E6%A8%A1%E7%B3%8A%E6%A8%A1%E5%BC%8F%E5%8C%B9%E9%85%8D%E5%88%A0%E9%99%A4%E9%94%AE%E5%85%A5%E7%9A%84%E5%AD%97%E7%AC%A6.png)
我在 zshrc 中使用以下内容:
zstyle ':completion:*' matcher-list 'm:{[:lower:]}={[:upper:]} r:|?=**'
(这要归功于马龙)
但我发现一些奇怪的行为。例如采取以下测试用例:
% tree zsh-test
zsh-test
├── a-xx
├── b-xx
└── somefile
然后打字ls zsh-test/xx
和点击Tab我可能期望看到的a-xx
并列b-xx
为可能性。相反,没有列出任何内容和xx
我输入的部分是已删除!
我认为正在发生的事情是xx
生成两个选项,然后 zsh 正在寻找一个公共前缀,但没有找到一个,因此将我的文本替换为任何内容。这不是很有帮助。我有RTM但这并没有帮助我实现找到直观的模糊匹配器模式的目标。
有没有办法让它显示与模式匹配的候选者,而不删除我的模式?
这种行为的奇怪之处在于,我什至无法习惯它,因为如果我在目录内zsh-test
并输入内容,ls xx
Tab那么它会按预期工作 - 显示两个候选人!
答案1
发生这种情况是因为 Zshzsh-test/
在第一种情况下将其视为明确的前缀,而在第二种情况下,没有明确的前缀。 (是的,有一个明确的后缀,但不幸的是,Zsh 对此没有做任何事情。)默认情况下,如果 Zsh 看到明确的前缀,那么第一次按Tab将简单地插入该前缀,可能会删除您已经存在的字符键入。
您可以通过在 shell 中输入以下内容来测试这一点:
autoload -Uz compinit && compinit
zstyle ':completion:*' matcher-list 'm:{[:lower:]}={[:upper:]} r:|?=**'
bindkey '^I' complete-word
zle -C complete-word complete-word complete-word
complete-word() {
_main_complete;
compadd -x "unambiguous prefix: '${compstate[unambiguous]}'";
compstate[list]='list force';
}
然后,再次尝试您的两个案例。对于第一种情况,您将看到unambiguous prefix: 'zsh-test/'
.对于第二种情况,你会看到unambiguous prefix: ''
不幸的是,没有办法配置Zsh 以获得您想要的行为。但是,如果您愿意更深入地研究兔子洞,那么可以通过将以下脚本添加到您的.zshrc
文件中来实现您想要的行为:
zmodload -i zsh/complist
autoload -Uz compinit && compinit
zstyle ':completion:*' matcher-list 'm:{[:lower:]}={[:upper:]} r:|?=**'
bindkey '^I' complete-word
zle -C complete-word menu-select complete-word
complete-word() {
_main_complete;
compstate[list]='list';
local word=$PREFIX$SUFFIX
(( compstate[unambiguous_cursor] <= ${#word} )) && compstate[insert]='menu';
}
compstate[list]='list'
确保当有多个匹配可用时自动列出完成情况。- 最后一行检查默认行为是否会删除光标所在的当前单词的任何部分,如果是,则插入列表中的第一项。
- 然后,(由
menu-select
提供zsh/complist
)zle -C complete-word menu-select complete-word
可让您使用您的选择Tab或arrow keys从列表中选择不同的项目。
以这种方式调整 Zsh 的完成系统可能很快就会变得相当复杂,而且其中的许多部分都没有详细记录。我强烈建议您查看我的zsh-autocomplete
插入,它定制了 Zsh 完成系统,以开箱即用地完成大多数人期望它做的事情。
答案2
完成菜单后,您确实会得到两个zsh-test/a-xx
和zsh-test/b-xx
。我无法告诉你为什么 xx 被删除。但从你所说的看来你试图获得模糊匹配,并且可能有更简单的方法。
'r:|?=**'
相当具有侵略性。就模糊性而言,它允许在每个输入的字符之间存在额外的字符,但不处理转置字符之类的事情。 Just'b:=*'
将允许子字符串和_approximate
完成器以某种更受控制的方式处理近似值,更喜欢需要较少校正的匹配。