12

If I want to have a prompt on the terminal with a default value already typed in, how can I do that?

Ruby's standard Readline.readline() lets me set the history but not fill in a default value (as far as I can tell, at least)

I would like something like this:

code:

input = Readline.readline_with_default('>', 'default_text')

console:

> default_text|
Wayne Conrad
  • 103,207
  • 26
  • 155
  • 191
jes5199
  • 18,324
  • 12
  • 36
  • 40
  • An example or illustration could make this question more clear. – John Douthat Feb 22 '10 at 20:57
  • 1
    it's hard to give an example for interactive console behavior, but here's an attempt. – jes5199 Feb 22 '10 at 21:07
  • do you need the user to be able to modify the default_text, like backspace over it, or do you simply want to read an empty line as the default text? – John Douthat Feb 22 '10 at 21:09
  • 1
    yes, I want them to modify it. – jes5199 Feb 22 '10 at 21:16
  • 1
    my reading of ext/readline.c leads me to believe it's not supported in Ruby's Readline library. If this functionality is possible in GNU Readline, an extension could be created, otherwise, I second Farrel's ncurses suggestion. – John Douthat Feb 23 '10 at 19:40
  • BTW the latest version of [haskeline](http://trac.haskell.org/haskeline) (0.6.4.0) has such an API: [`getInputLineWithInitial`](http://hackage.haskell.org/packages/archive/haskeline/0.6.4.0/doc/html/System-Console-Haskeline.html#g:5): "This function behaves in the exact same manner as `getInputLine`, except that it pre-populates the input area. The text that resides in the input area is given as a 2-tuple with two Strings. The string on the left of the tuple is what will appear to the left of the cursor and the string on the right is what will appear to the right of the cursor." – imz -- Ivan Zakharyaschev Apr 20 '11 at 22:59
  • And I'm in the search of something like this for Curry -- http://stackoverflow.com/q/5737170/94687 . If not the pre-populated input text requirement, a simple readline-based wrapper like `rlwrap` would do for any program... (Perhaps, we could make up a wrapper like `rlwrap`, but with a protocol for pre-population of the input line?..) – imz -- Ivan Zakharyaschev Apr 20 '11 at 23:04

6 Answers6

10

What you are asking is possible with Readline. There's a callback where you can get control after the prompt is displayed and insert some text into the read buffer.

This worked for me:

Readline.pre_input_hook = -> do
  Readline.insert_text "hello.txt"
  Readline.redisplay

  # Remove the hook right away.
  Readline.pre_input_hook = nil
end

input = Readline.readline("Filename: ", false)
puts "-- input:#{input.inspect}"

BTW, I fairly tried to use HighLine, but it appeared to be a no-alternative to me. One of the disappointing reasons was the fact that HighLine#ask reads cursor movement keys as regular input. I stopped looking in that direction after that sort of discovery.

Alex Fortuna
  • 1,223
  • 12
  • 16
  • 1
    That's exactly what I was looking for! Thanks! – wrzasa Apr 04 '16 at 19:56
  • Thanks for showing this great solution. Specially the `Readline.pre_input_hook = nil` trick. I didn't know that pre_input_hook can be used like this. So smart! – agate Sep 19 '18 at 02:27
  • 2
    Be warned! This do not work in the Readline implementation on MacOS X. I was trying for an hour to figure out why it wasn't working. There are no errors, no warnings, nothing, just doesn't work. In ubuntu, it works properly. – Sergio Mar 16 '20 at 13:57
  • Looks like `insert_text` invokes GNU's `rl_insert_text`, which differs between Ubuntu and MacOS. https://apidock.com/ruby/Readline/insert_text/class – Ting Yi Shih Oct 22 '20 at 05:37
  • The example in this answer failed to work for me (on current Ubuntu) - no errors and nothing inserted at the prompt. I can't figure out why. – Guss Oct 12 '22 at 10:55
5

+1 to highline

try with something like:

require 'highline/import'
input = ask('> ') {|q| q.default = 'default_text'} # > |default_text|
Pablo Castellazzi
  • 4,164
  • 23
  • 20
3

Sounds like a job for ncurses. Seems like rbcurse (http://rbcurse.rubyforge.org/) is the best maintained API at the moment.

Farrel
  • 2,383
  • 18
  • 14
2

I'm struggling with the same thing.

The way I'm doing it right now is:

options = ["the_text_you_want"]
question = "use TAB or up arrow to show the text > "

Readline.completion_append_character = " "
Readline::HISTORY.push options.first
Readline.completion_proc = proc { |s| options.grep( /^#{Regexp.escape(s)}/ ) }

while value = Readline.readline(question, true)
  exit if value == 'q'
  puts value.chomp.strip #do something with the value here
end

yes, it's silly, but it has been the only way I've found to do it.

did anybody find any solution to this?

raf
  • 310
  • 2
  • 10
2

New answer to an old question, but adding because I found this looking for an answer to the same question.

tty-prompt looks like it does what you are looking for - asking for input with an editable default. It's the only gem I found that would give me the editable default (but there may be others)

Full code to to that would look like:

require "tty-prompt"
prompt = TTY::Prompt.new
input = prompt.ask('What is your name?', value: 'Bob')
Jon Howard
  • 21
  • 2
1

Highline doesn't do exactly what you describe, but maybe it's close enough.

Ken Liu
  • 22,503
  • 19
  • 75
  • 98