From 2b0f8febf0905ca9351757fe1b9f3c9a6f21a13d Mon Sep 17 00:00:00 2001 From: Juerd Waalboer Date: Sun, 11 Feb 2024 04:05:52 +0100 Subject: [PATCH] v6.0.4: use readline's internal loop This fixes the bug that empty lines would be inserted after each prompt, starting from the first use of ^D. Readline considers ^D end-of-file even when it's not, and for whatever reason then adds a \n after BRACK_PASTE_FINI, which results in empty lines after subsequent prompts. With readline's internal loop, rl_found_eof gets reset to false, but users of a custom loop don't get that luxury, and Term::ReadLine::Gnu doesn't expose rl_found_eof (which was added to readline's API only a few years ago) to do it manually. One workaround, used briefly but not committed, would be to disable bracketed paste. A better workaround, as implemented by this commit, is to abandon the custom loop and use readline's blocking call instead. --- lib/RevBank/Prompt.pm | 30 +++++++++--------------------- revbank | 2 +- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/lib/RevBank/Prompt.pm b/lib/RevBank/Prompt.pm index c28d63b..30f913f 100755 --- a/lib/RevBank/Prompt.pm +++ b/lib/RevBank/Prompt.pm @@ -5,7 +5,6 @@ use warnings; use feature qw(signatures isa); no warnings "experimental::signatures"; -use IO::Select; use List::Util qw(uniq); use Term::ReadLine; require Term::ReadLine::Gnu; # The other one sucks. @@ -64,9 +63,6 @@ sub reconstruct($word) { sub prompt($prompt, $completions = [], $default = "", $pos = 0, $cart = undef, $plugins = []) { state $readline = Term::ReadLine->new($0); - my $select = IO::Select->new; - $select->add(\*STDIN); - if ($prompt) { $prompt =~ s/$/:/ if $prompt !~ /[?>](?:\x01[^\x02]*\x02)?$/; $prompt .= " "; @@ -88,21 +84,12 @@ sub prompt($prompt, $completions = [], $default = "", $pos = 0, $cart = undef, $ # but it can be assigned through the corresponding .inputrc command. $readline->parse_and_bind("set completion-ignore-case on"); - my $done; - my $input; - - $readline->callback_handler_install($prompt, sub { - $done = 1; - $input = shift; - $readline->callback_handler_remove; - }); - $readline->insert_text($default); $readline->Attribs->{point} = $pos; - $readline->redisplay(); my $begin = my $time = time; - while (not $done) { + + $readline->Attribs->{event_hook} = sub { if ($::ABORT_HACK) { # Global variable that a signal handling plugin can set. # Do not use, but "return ABORT" instead. @@ -110,10 +97,6 @@ sub prompt($prompt, $completions = [], $default = "", $pos = 0, $cart = undef, $ $::ABORT_HACK = 0; main::abort($reason); } - if ($select->can_read(.05)) { - $readline->callback_read_char; - $begin = $time; - } if (time > $time) { $time = time; call_hooks( @@ -124,10 +107,15 @@ sub prompt($prompt, $completions = [], $default = "", $pos = 0, $cart = undef, $ $readline, ); } - } + }; + + $readline->ornaments(0); + my $input = $readline->readline($prompt); print "\e[0m"; - defined $input or return; + + return undef if not defined $input; + $readline->addhistory($input); $input =~ s/^\s+//; # trim leading whitespace diff --git a/revbank b/revbank index 2d64064..edf4aa7 100755 --- a/revbank +++ b/revbank @@ -16,7 +16,7 @@ use RevBank::Messages; use RevBank::Cart; use RevBank::Prompt; -our $VERSION = "6.0.3"; +our $VERSION = "6.0.4"; our %HELP1 = ( "abort" => "Abort the current transaction", );