将前一个命令的参数添加到zsh完成


21

在zsh(以及bash)中,您可以使用一些历史单词扩展来表示先前命令的参数。

此示例显示了!:#扩展历史记录中从上一个命令获取第二个参数:

% echo foo bar baz
foo bar baz
% echo !:2
echo bar
bar

我经常会忘记一个特定参数是什么#参数!:#,当我记住它是哪个arg时,键入并不总是那么快。我知道meta-.要替换最后一个参数,但是有时它不是我想要的最后一个参数。

我想添加上一条命令中的参数作为建议,以完成我在zsh中键入的任何命令。

我能够弄清楚如何创建一个shell函数,该函数可以从最后一个命令创建一个参数数组(0..N)并将其绑定到特定命令。

_last_command_args() {
    last_command=$history[$[HISTCMD-1]]
    last_command_array=("${(s/ /)last_command}") 
    _sep_parts last_command_array
}

# trying to get last_command_args to be suggested for any command, this just works for foo
compdef _last_command_args foo

这是仅在我按以下位置的Tab键时完成foo的样子<TAB>

% echo bar baz qux
bar baz qux
% foo <TAB>
bar   baz   echo  qux 

这对于完成命令“ foo”非常有用,但是我希望这些可以作为我执行的任何zsh扩展的选项。我认为这与zstyle completer东西有关,但是经过数小时的黑客攻击后,我意识到我已经超出了深度。

如何从上一个命令中获取参数作为zsh中任何命令的建议完成?

如果有帮助,我已经在bitbucket上共享了完整的zshrc compinstall文件。许多原因都来自多种渠道,其中一些是我自己入侵的。

更新:

@朱利安·尼古洛(Julien Nicoulaud)的回答使我接近,我将其标记为已接受,因为它使我到达了需要去的地方。

使用我的特定配置,使用建议的方法:

zstyle ':completion:*' completer _last_command_args _complete

对于我来说,这不是很有效,因为它会导致制表符补全仅显示最后一个命令的参数列表(尽管它实际上也与文件名一起完成,只是不显示它们)。将顺序更改_complete _last_command_args为相反。它会显示正常的文件名,但不会显示last_command_args

我猜想这与完成程序的工作方式有关。我认为它仅显示成功返回的第一个方法的输出,但是我在解析zsh源以完全了解正在发生的过程时遇到了麻烦。我能够调整我的方法以包含一个调用,_complete以便它显示最后一个参数命令以及常规的自动完成功能。并没有那么分开,但对我来说足够好了。

这是我与其他zstyle东西一起使用的全部功能:

# adds the arguments from the last commadn to the autocomplete list
# I wasn't able to get this to work standalone and still print out both regular
# completion plus the last args, but this works well enough.
_complete_plus_last_command_args() {
    last_command=$history[$[HISTCMD-1]]
    last_command_array=("${(s/ /)last_command}") 
    _sep_parts last_command_array
    _complete 
}


_force_rehash() {
  (( CURRENT == 1 )) && rehash
  return 1  # Because we didn't really complete anything
}

zstyle ':completion:::::' completer _force_rehash _complete_plus_last_command_args _approximate 

我拥有的其他zstyle行,不一定要起作用,但可能会影响为什么对我有效:

zstyle -e ':completion:*:approximate:*' max-errors 'reply=( $(( ($#PREFIX + $#SUFFIX) / 3 )) )'
zstyle ':completion:*:descriptions' format "- %d -"
zstyle ':completion:*:corrections' format "- %d - (errors %e})"
zstyle ':completion:*:default' list-prompt '%S%M matches%s'
zstyle ':completion:*' group-name ''
zstyle ':completion:*:manuals' separate-sections true
zstyle ':completion:*' menu select
zstyle ':completion:*' verbose yes

现在,如果我位于带有file1.txt和的目录中file2.txt,而我的最后一个命令是echo foo bar baz,则得到此信息是为了自动完成,这正是我想要的:

% ls
bar   baz   echo  foo 
- files -
file1.txt   file2.txt 

2
这是一个
了不起的

2
作为^[ .insert-last-word)的补充,我喜欢copy-earlier-word在所到达的行的单词之间循环insert-last-word。为您.zshrcautoload copy-earlier-word && zle -N copy-earlier-word && bindkey '^[,' copy-earlier-word
吉尔斯(Gilles)“所以,别再邪恶了”

@吉尔斯谢谢!如果我无法获得完全自动完成功能,那将使我更接近功能。大约80%的时间,如果不是最后一个参数,那是我想要的倒数第二个参数,并且C-。+ C-很好。
泰德·纳莱德

Answers:


6

您可以将完成程序添加到默认使用的完成程序列表中:

zstyle ':completion:*' completer _last_command_args _complete

1
如果有任何_last_command_args完成,则不显示其他完成。除了通常的以外,您又如何获得它们?
吉尔(Gilles)“所以,别再邪恶了”,

1
感谢您的回答,这使我足够接近,可以为我工作,因此我接受了。我所做的不同操作是上述问题的更新。您的解决方案没有同时打印出最后一个命令的参数以及普通完成程序中的文件等。我_complete在自己创建的函数中进行了组合,它的工作原理与我想要的一样。
泰德·纳莱德

您说得对,我的回答不正确。
nicoulaj 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.