我开发了一个包含可执行脚本(rubygems 术语中的应用程序文件)的 gem。调用时,我想完成给定目录(不是当前工作目录)中的文件名,如下所示:
foo edit my<tab>
扩展为:
foo edit myfile
我能做的是包含一个安装 shell 完成的脚本。如果这是唯一的解决方案——很好。但我想知道是否有一种方法可以让用户从额外的步骤中解放出来,并直接在我的 gem 中包含完成。
那么:有没有办法让 gem 自带 tab 补全?
我开发了一个包含可执行脚本(rubygems 术语中的应用程序文件)的 gem。调用时,我想完成给定目录(不是当前工作目录)中的文件名,如下所示:
foo edit my<tab>
扩展为:
foo edit myfile
我能做的是包含一个安装 shell 完成的脚本。如果这是唯一的解决方案——很好。但我想知道是否有一种方法可以让用户从额外的步骤中解放出来,并直接在我的 gem 中包含完成。
那么:有没有办法让 gem 自带 tab 补全?
当您键入命令以启动脚本时,您的脚本尚未运行。它不能在自己的参数仍在输入时干预它们的处理。如果可能,您可以让该gem
文件安装一个 bash 完成文件并修改用户的~/.bashrc
文件以在安装过程中加载它们。
看看 Ruby 的Abbrev模块。(About.com 也有一些有用的信息。)
从文档:
计算给定字符串集的唯一缩写集。 需要'缩写' 需要'pp' pp Abbrev::abbrev(['ruby', 'rules']).sort 生成: [[“擦”,“红宝石”], [“红宝石”,“红宝石”], [“规则”,“规则”], [“规则”,“规则”], [“规则”,“规则”]] 还向类 Array 添加了一个缩写方法。
我会读取目录,将文件和子目录传递给 Abbrev,然后将结果转换为哈希。观看用户键入。如果他们按下Tab查看他们输入的内容是否与哈希中的键匹配。如果它确实他们键入的内容是唯一的,并且可以解析为该元素的值。
这是如何将 Abbrev 的输出转换为哈希的方法:
irb(main):009:0> hash = Hash[%w[ruby rules].abbrev]
=> {"rub"=>"ruby", "rule"=>"rules", "rul"=>"rules", "ruby"=>"ruby", "rules"=>"rules"}
虽然chepner得出了安装是不可避免的正确结论,但我建议看看其他一些项目是如何解决这个问题的。
Travis CI travis gem 提供在第一次执行时安装完成。它将完成脚本保存到~/.travis/travis.sh然后将以下内容附加到.bashrc:
# added by travis gem
[ -f ~/.travis/travis.sh ] && source ~/.travis/travis.sh
前面的例子有点侵入性。有关更自由放任的方法,请参阅 Python 的pip
(类似于 Ruby 的gem
)。它有一个隐藏的完成选项,可以将 bash 或 zsh 完成脚本打印到标准输出。由用户决定如何获取它。
pip completion --bash
输出以下内容:
# pip bash completion start
_pip_completion()
{
COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \
COMP_CWORD=$COMP_CWORD \
PIP_AUTO_COMPLETE=1 $1 ) )
}
complete -o default -F _pip_completion pip
# pip bash completion end
在一个有点不同但相关的注释上……如果你看一下前面提到的完成脚本,你会注意到它做了一些相当奇怪的事情。它使用第三个选项,而不是使用完成的静态列表(必须经常更新并且容易出现不准确)或通过解析帮助消息(通常慢得令人无法接受)动态生成完成。它直接传递命令行状态pip
以使其生成完成。
Perhaps the most relevant, but also the grandest approach would be to create a global completion script for Ruby gems. The user simply has to install the one global completion gem (there is no getting around this) and then completions are immediately available for any other gems. As far as I know, no one has implemented this in Ruby. For a Python implementation, see argcomplete.
Installation is as follows:
pip install argcomplete
activate-global-python-argcomplete --dest=/path/to/bash_completion.d
Scripts are easily adapted. It is then essentially a one-liner to pass your parser object to argcomplete.