perl6 Is there a way to do editable prompt input?

2019-07-05 20:23发布

In bash shell, if you hit up or down arrows, the shell will show you your previous or next command that you entered, and you can edit those commands to be new shell commands.

In perl6, if you do

my $name = prompt("Enter name: ");

it will print "Enter name: " and then ask for input; is there a way to have perl6 give you a default value and then you just edit the default to be the new value. E.g.:

my $name = prompt("Your name:", "John Doe");

and it prints

Your name: John Doe

where the John Doe part is editable, and when you hit enter, the edited string is the value of $name.

https://docs.perl6.org/routine/prompt does not show how to do it.

This is useful if you have to enter many long strings each of which is just a few chars different from others.

Thanks.

3条回答
beautiful°
2楼-- · 2019-07-05 20:30

To get the editing part going, you could use the Linenoise module:

zef install Linenoise

(https://github.com/hoelzro/p6-linenoise)

Then, in your code, do:

use Linenoise;
sub prompt($p) {
    my $l = linenoise $p;
    linenoiseHistoryAdd($l);
    $l
}

Then you can do your loop with prompt. Remember, basically all Perl 6 builtin functions can be overridden lexically. Now, how to fill in the original string, that I haven't figure out just yet. Perhaps the libreadline docs can help you with that.

查看更多
Root(大扎)
3楼-- · 2019-07-05 20:40

Another solution :

Use io-prompt With that you can set a default value and even a default type:

my $a = ask( "Life, the universe and everything?", 42, type => Num );
Life, the universe and everything? [42]
Int $a = 42

You can install it with:

zef install IO::Prompt

However, if just a default value is not enough. Then it is better you use the approach Liz has suggested.

查看更多
聊天终结者
4楼-- · 2019-07-05 20:42

Well by default, programs are completely unaware of their terminals.
You need your program to communicate with the terminal to do things like pre-fill an input line, and it's unreasonable to expect Perl 6 to handle something like this as part of the core language.

That said, your exact case is handled by the Readline library as long as you have a compatible terminal.

It doesn't look like the perl 6 Readline has pre-input hooks setup so you need to handle the callback and read loop yourself, unfortunately. Here's my rough attempt that does exactly what you want:

use v6;
use Readline;

sub prompt-prefill($question, $suggestion) {
  my $rl = Readline.new;
  my $answer;
  my sub line-handler( Str $line ) {
    rl_callback_handler_remove();
    $answer = $line;
  }

  rl_callback_handler_install( "$question ", &line-handler );

  $rl.insert-text($suggestion);
  $rl.redisplay;
  while (!$answer) {
    $rl.callback-read-char();
  }

  return $answer;
}


my $name = prompt-prefill("What's your name?", "Bob");
say "Hi $name. Go away.";

If you are still set on using Linenoise, you might find the 'hints' feature good enough for your needs (it's used extensively by the redis-cli application if you want a demo). See the hint callback used with linenoiseSetHintsCallback in the linenoise example.c file. If that's not good enough you'll have to start digging into the guts of linenoise.

查看更多
登录 后发表回答