Bug #6601

[readline] Alt-* commands do not work in reverse-i-search

Added by rctay (Tay Ray Chuan) over 8 years ago. Updated over 8 years ago.

Target version:
ruby -v:
ruby 1.9.3p236 (2012-06-11) [x86_64-linux]


= Steps to reproduce
Below are the steps to reproduce from an (({irb})) session. ^ is used to denote the cursor position on the screen.

  • Type ((%puts :a%)) then ((%Enter%)). This is to populate the history for reverse-i-search.
    irb(main):001:0> puts :a
    => nil

  • Hit ((%Ctrl-R%)) (for reverse-i-search), followed by ((%u%)):
    (reverse-i-search)`u': puts :a

  • Hit ((%Alt-F%)) (for forward-word).

Observed: reverse-i-search terminated, with an 'f' inserted at cursor position.
irb(main):002:0> pfuts :a

Expected: reverse-i-search terminated, nothing inserted, cursor moves to end of the word (({puts})):
irb(main):002:0> puts :a

Note that other ((%Alt-*%)) commands don't work too (ie ((%x%)) is inserted instead of the command ((%Alt-x%)) being performed), including

  • ((%Alt-B%)) (move backward a word)
  • ((%Alt-C%)) (capitalize letter)
  • ((%Alt-D%)) (delete till end of word)

= Fix

When we hit ((%Alt-F%)) from reverse-i-search, execution arrives at this piece of code in libreadline's (({isearch.c})):

387 /* ESC still terminates the search, but if there is pending
388 input or if input arrives within 0.1 seconds (on systems
389 with select(2)) it is used as a prefix character
390 with rl_execute_next. WATCH OUT FOR THIS! This is intended
391 to allow the arrow keys to be used like F and B are used
392 to terminate the search and execute the movement command.
393 XXX - since _rl_input_available depends on the application-
394 settable keyboard timeout value, this could alternatively
395 use _rl_input_queued(100000) */
396 if (cxt->lastc == ESC && _rl_input_available ())
397 rl_execute_next (ESC);

Due to (({readline_getc()})), our (({rl_getc_function()})) implementation, (({IO::getbyte()})) is called, causing all input characters to be "swallowed" into our byte buffer in (({readline_instream})). Thus (({_rl_input_available()})) incorrectly returns false, and the keystrokes (eg. Alt, F) fail to be recognized as a binding for a command.

The proposed fix (attached) uses (({rb_io_read_pending()})) to emulate (({_rl_input_available()})), and calls (({rl_execute_next()})), as libreadline does.

= Affected Versions

Ruby trunk and 1.9.3 (latest) exhibits this issue.

Ruby 1.8 also has exhibits this issue, but the fix would be different since (({rl_getc_function()})) isn't overriden in (({ext/readline/readline.c})).

Tested on readline 6.2; blame'ing the above snippet shows that readline as far back as 5.1 should also give this behaviour.



readline.diff (852 Bytes) readline.diff applies cleanly on trunk and Backport93 rctay (Tay Ray Chuan), 06/17/2012 05:23 PM

Related issues

Related to Ruby master - Bug #6262: [readline] reverse-i-search with multibyte charsClosedkouji (Kouji Takao)04/06/2012Actions

Also available in: Atom PDF