lineedit: fix handling of repeating Alt-b, Alt-f, Alt-d, Alt-Backspace

These key combinations should repeat correctly when the keys are
pressed and held.

Before this change, they do this erratically - many repeats are "eaten"
because they are treated as unrecognized ESC seqs:
ESC 0x7f is treated by Alt+baskspace, but ESC 0x7f ESC 0x7f ESC 0x7f
is unrecognized.

Escape sequences corresponding to these key combinations are moved from
read_line_input to lineedit_read_key.

Also, these key sequences are now enabled regardless of whether
FEATURE_EDITING_VI is set, since Vim does not actually support these key
combinations, but they are present in readline library.

function                                             old     new   delta
static.esccmds                                        93     103     +10
read_line_input                                     3737    3687     -50

Signed-off-by: Rostislav Skudnov <rostislav@tuxera.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Rostislav Skudnov
2016-11-24 15:04:00 +01:00
committed by Denys Vlasenko
parent cb810c48c0
commit 2e4ef38743
3 changed files with 67 additions and 79 deletions

View File

@ -13,7 +13,6 @@
*
* This code is 'as is' with no warranty.
*/
/*
* Usage and known bugs:
* Terminal key codes are not extensive, more needs to be added.
@ -23,9 +22,6 @@
* Ctrl-E also works as End.
*
* The following readline-like commands are not implemented:
* ESC-b -- Move back one word
* ESC-f -- Move forward one word
* ESC-d -- Delete forward one word
* CTL-t -- Transpose two characters
*
* lineedit does not know that the terminal escape sequences do not
@ -2483,6 +2479,24 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
while (cursor > 0 && !BB_isspace(command_ps[cursor-1]))
input_backspace();
break;
case KEYCODE_ALT_D: {
/* Delete word forward */
int nc, sc = cursor;
ctrl_right();
nc = cursor - sc;
input_backward(nc);
while (--nc >= 0)
input_delete(1);
break;
}
case KEYCODE_ALT_BACKSPACE: {
/* Delete word backward */
int sc = cursor;
ctrl_left();
while (sc-- > cursor)
input_delete(1);
break;
}
#if ENABLE_FEATURE_REVERSE_SEARCH
case CTRL('R'):
ic = ic_raw = reverse_i_search();
@ -2625,44 +2639,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
vi_cmdmode = 1;
input_backward(1);
}
/* Handle a few ESC-<key> combinations the same way
* standard readline bindings (IOW: bash) do.
* Often, Alt-<key> generates ESC-<key>.
*/
ic = lineedit_read_key(read_key_buffer, 50);
switch (ic) {
//case KEYCODE_LEFT: - bash doesn't do this
case 'b':
ctrl_left();
break;
//case KEYCODE_RIGHT: - bash doesn't do this
case 'f':
ctrl_right();
break;
//case KEYCODE_DELETE: - bash doesn't do this
case 'd': /* Alt-D */
{
/* Delete word forward */
int nc, sc = cursor;
ctrl_right();
nc = cursor - sc;
input_backward(nc);
while (--nc >= 0)
input_delete(1);
break;
}
case '\b': /* Alt-Backspace(?) */
case '\x7f': /* Alt-Backspace(?) */
//case 'w': - bash doesn't do this
{
/* Delete word backward */
int sc = cursor;
ctrl_left();
while (sc-- > cursor)
input_delete(1);
break;
}
}
break;
#endif /* FEATURE_COMMAND_EDITING_VI */

View File

@ -18,8 +18,20 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
/* Known escape sequences for cursor and function keys.
* See "Xterm Control Sequences"
* http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
* Array should be sorted from shortest to longest.
*/
static const char esccmds[] ALIGN1 = {
'\x7f' |0x80,KEYCODE_ALT_BACKSPACE,
'\b' |0x80,KEYCODE_ALT_BACKSPACE,
'd' |0x80,KEYCODE_ALT_D ,
/* lineedit mimics bash: Alt-f and Alt-b are forward/backward
* word jumps. We cheat here and make them return ALT_LEFT/RIGHT
* keycodes. This way, lineedit need no special code to handle them.
* If we'll need to distinguish them, introduce new ALT_F/B keycodes,
* and update lineedit to react to them.
*/
'f' |0x80,KEYCODE_ALT_RIGHT,
'b' |0x80,KEYCODE_ALT_LEFT,
'O','A' |0x80,KEYCODE_UP ,
'O','B' |0x80,KEYCODE_DOWN ,
'O','C' |0x80,KEYCODE_RIGHT ,