highline icon indicating copy to clipboard operation
highline copied to clipboard

consider exposing Readline.completion_proc via HighLine::Question#selection

Open doriantaylor opened this issue 7 years ago • 3 comments

Happy Monday,

Playing around with HighLine, finding myself in a situation where I need finer-grained access to tab completion than an array. Looking at terminal.rb it seems as if it would be pretty easy to re-expose Readline.completion_proc via HighLine::Question.

Something like this would probably be all that was necessary:

def readline_read(question)
  # prep auto-completion
  sel  = question.selection
  proc = sel.is_a?(Proc) ? sel : sel.empty? ? nil : lambda do |str|
      sel.grep(/\A#{Regexp.escape(str)}/)
  end
  Readline.completion_proc = proc

  # work-around ugly readline() warnings
  old_verbose = $VERBOSE
  $VERBOSE    = nil

  raw_answer  = run_preserving_stty do
    Readline.readline("", true)
  end

  $VERBOSE = old_verbose

  raw_answer
end

Then in Highline::Question, something like:

def selection
  if completion.is_a?(Array) or completion.is_a?(Proc)
    completion
  elsif [File, Pathname].include?(completion)
    Dir[File.join(directory.to_s, glob)].map do |file|
      File.basename(file)
    end
  else
    []
  end
end

This is just me eyeballing the issue for now; I can fork and PR if you're amenable.

doriantaylor avatar May 21 '18 17:05 doriantaylor

Hi @doriantaylor , thank you for your comments/suggestions.

I'll probably have time to look at it further by the weekend.

But I can antecipate to you that if it solves an actual problem that you're having, it doesn't break the api and it doesn't raise the code's complexity too much I'll probably welcome your changes 👍

abinoam avatar May 24 '18 02:05 abinoam

Great, I'll cook it up.

doriantaylor avatar May 24 '18 02:05 doriantaylor

Looking over this and I have a couple questions:

  1. Testing strategy: Do I (can I?) use HighLine::Simulate or do I add another manual acceptance test?
  2. The method HighLine#shell_style_lambda does something similar to what I am ultimately trying to do, but only for menus. Perhaps it would make sense to take a step back and look at this more holistically?

I found my way here because I was writing a command-line tool using commander and wanted to implement an umbrella shell command that recycled the other available commands into a readline loop. (To achieve this I had to patch some undesirable behaviour, which the maintainer graciously applied.) Commander, of course, uses HighLine for its readline component, and I want to be able to add tab completion—not just for the commands, but for the options as well.

Given that my desired functionality is at least partially present in HighLine::Menu, I should probably take it into consideration. Nevertheless, I believe it to be still overall useful to be able to access Readline.completion_proc directly, it just looks like a slightly more delicate surgery.

doriantaylor avatar May 26 '18 18:05 doriantaylor