我该如何做readline参数完成?
问题描述:
我有一个使用readline命令完成的Ruby应用程序。我该如何做readline参数完成?
在输入第一个字符串(命令)之后,我希望能够完成它的参数。参数列表应该基于所选的命令。
有人有一个快速的例子吗?
这些是命令:
COMMANDS = [
'collect', 'watch'
].sort
COLLECT = [
'stuff', 'otherstuff'
].sort
comp = proc do |s|
COMMANDS.grep(/^#{Regexp.escape(s)}/)
end
Readline.completion_proc = comp
每次我按TAB,执行PROC块和从COMMANDS
阵列相匹配的指令。 其中一个命令完全匹配后,我想开始仅在COLLECT
阵列中搜索参数。
答
思考了一会儿后,该解决方案很简单:
comp = proc do |s|
if Readline.line_buffer =~ /^.*/
COLLECT.grep(/^#{Regexp.escape(s)}/)
else
COMMANDS.grep(/^#{Regexp.escape(s)}/)
end
end
现在我只是需要把它变成一些更灵活的/可用。
答
既然你的问题每次找到这样的东西时首先弹出,我想分享我的代码给其他任何人。
#!/usr/bin/env ruby
require 'readline'
module Shell
PROMPT = "shell> "
module InputCompletor
CORE_WORDS = %w[ clear help show exit export]
SHOW_ARGS = %w[ list user ]
EXPORT_ARGS = %w[ file ]
COMPLETION_PROC = proc { |input|
case input
when /^(show|export) (.*)/
command = $1
receiver = $2
DISPATCH_TABLE[$1].call($2)
when /^(h|s|c|e.*)/
receiver = $1
CORE_WORDS.grep(/^#{Regexp.quote(receiver)}/)
when /^\s*$/
puts
CORE_WORDS.map{|d| print "#{d}\t"}
puts
print PROMPT
end
}
def self.show(receiver)
if SHOW_ARGS.grep(/^#{Regexp.quote(receiver)}/).length > 1
SHOW_ARGS.grep(/^#{Regexp.quote(receiver)}/)
elsif SHOW_ARGS.grep(/^#{Regexp.quote(receiver)}/).length == 1
"show #{SHOW_ARGS.grep(/^#{Regexp.quote(receiver)}/).join}"
end
end
def self.export(receiver)
if EXPORT_ARGS.grep(/^#{Regexp.quote(receiver)}/).length > 1
EXPORT_ARGS.grep(/^#{Regexp.quote(receiver)}/)
elsif EXPORT_ARGS.grep(/^#{Regexp.quote(receiver)}/).length == 1
"export #{EXPORT_ARGS.grep(/^#{Regexp.quote(receiver)}/).join}"
end
end
DISPATCH_TABLE = {'show' => lambda {|x| show(x)} ,
'export' => lambda {|x| export(x)}}
end
class CLI
Readline.completion_append_character = ' '
Readline.completer_word_break_characters = "\x00"
Readline.completion_proc = Shell::InputCompletor::COMPLETION_PROC
def initialize
while line = Readline.readline("#{PROMPT}",true)
Readline::HISTORY.pop if /^\s*$/ =~ line
begin
if Readline::HISTORY[-2] == line
Readline::HISTORY.pop
end
rescue IndexError
end
cmd = line.chomp
case cmd
when /^clear/
system('clear')
when /^help/
puts 'no help here'
when /show list/
puts 'nothing to show'
when /^show\s$/
puts 'missing args'
when /export file/
puts 'nothing to export'
when /^export\s$/
puts 'missing args'
when /^exit/
exit
end
end
end
end
end
Shell::CLI.new
你试过写什么吗? –
确实增加了一个例子。我试图通过在proc块内部寻找解决方案。 Readline.line_buffer返回正在编写的整个字符串,我确定它可以用来帮助我为参数创建单独的搜索上下文。 – Dawid
而不是使用'COMMANDS'和'COLLECT'数组,而使用散列。如果用户输入了一个完整的单词,则您的查询是即时的:'COMMANDS [s]'。如果你想要部分命中,然后使用过滤器/正则表达式来搜索'COMMANDS'哈希的'keys'并返回可能的命中或查看Ruby的内置['Abbrev'模块](http://www.ruby- doc.org/stdlib-1.9.3/libdoc/abbrev/rdoc/Abbrev.html),它有助于提供子字符串以匹配部分键入的单词。 –