我该如何做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阵列中搜索参数。

+0

你试过写什么吗? –

+0

确实增加了一个例子。我试图通过在proc块内部寻找解决方案。 Readline.line_buffer返回正在编写的整个字符串,我确定它可以用来帮助我为参数创建单独的搜索上下文。 – Dawid

+1

而不是使用'COMMANDS'和'COLLECT'数组,而使用散列。如果用户输入了一个完整的单词,则您的查询是即时的:'COMMANDS [s]'。如果你想要部分命中,然后使用过滤器/正则表达式来搜索'COMMANDS'哈希的'keys'并返回可能的命中或查看Ruby的内置['Abbrev'模块](http://www.ruby- doc.org/stdlib-1.9.3/libdoc/abbrev/rdoc/Abbrev.html),它有助于提供子字符串以匹配部分键入的单词。 –

思考了一会儿后,该解决方案很简单:

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