lineedit: fix handling of repeating Alt-b, Alt-f, Alt-d, Alt-Backspace
authorRostislav Skudnov <rostislav@tuxera.com>
Thu, 24 Nov 2016 14:04:00 +0000 (15:04 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 24 Nov 2016 14:04:00 +0000 (15:04 +0100)
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>
include/libbb.h
libbb/lineedit.c
libbb/read_key.c

index 20fc7329f6e886b71a4e7c1b522a96dc9be49f91..bdafcf5a6cba40760ed119a5732503fc6a8787e2 100644 (file)
@@ -1463,46 +1463,46 @@ unsigned long long bb_makedev(unsigned major, unsigned minor) FAST_FUNC;
  * yet doesn't represent any valid Unicode character.
  * Also, -1 is reserved for error indication and we don't use it. */
 enum {
-       KEYCODE_UP       =  -2,
-       KEYCODE_DOWN     =  -3,
-       KEYCODE_RIGHT    =  -4,
-       KEYCODE_LEFT     =  -5,
-       KEYCODE_HOME     =  -6,
-       KEYCODE_END      =  -7,
-       KEYCODE_INSERT   =  -8,
-       KEYCODE_DELETE   =  -9,
-       KEYCODE_PAGEUP   = -10,
-       KEYCODE_PAGEDOWN = -11,
-       // -12 is reserved for Alt/Ctrl/Shift-TAB
+       KEYCODE_UP        =  -2,
+       KEYCODE_DOWN      =  -3,
+       KEYCODE_RIGHT     =  -4,
+       KEYCODE_LEFT      =  -5,
+       KEYCODE_HOME      =  -6,
+       KEYCODE_END       =  -7,
+       KEYCODE_INSERT    =  -8,
+       KEYCODE_DELETE    =  -9,
+       KEYCODE_PAGEUP    = -10,
+       KEYCODE_PAGEDOWN  = -11,
+       KEYCODE_BACKSPACE = -12, /* Used only if Alt/Ctrl/Shifted */
+       KEYCODE_D         = -13, /* Used only if Alted */
 #if 0
-       KEYCODE_FUN1     = -13,
-       KEYCODE_FUN2     = -14,
-       KEYCODE_FUN3     = -15,
-       KEYCODE_FUN4     = -16,
-       KEYCODE_FUN5     = -17,
-       KEYCODE_FUN6     = -18,
-       KEYCODE_FUN7     = -19,
-       KEYCODE_FUN8     = -20,
-       KEYCODE_FUN9     = -21,
-       KEYCODE_FUN10    = -22,
-       KEYCODE_FUN11    = -23,
-       KEYCODE_FUN12    = -24,
-#endif
-       /* Be sure that last defined value is small enough
-        * to not interfere with Alt/Ctrl/Shift bits.
-        * So far we do not exceed -31 (0xfff..fffe1),
-        * which gives us three upper bits in LSB to play with.
+       KEYCODE_FUN1      = ,
+       KEYCODE_FUN2      = ,
+       KEYCODE_FUN3      = ,
+       KEYCODE_FUN4      = ,
+       KEYCODE_FUN5      = ,
+       KEYCODE_FUN6      = ,
+       KEYCODE_FUN7      = ,
+       KEYCODE_FUN8      = ,
+       KEYCODE_FUN9      = ,
+       KEYCODE_FUN10     = ,
+       KEYCODE_FUN11     = ,
+       KEYCODE_FUN12     = ,
+#endif
+       /* ^^^^^ Be sure that last defined value is small enough.
+        * Current read_key() code allows going up to -32 (0xfff..fffe0).
+        * This gives three upper bits in LSB to play with:
+        * KEYCODE_foo values are 0xfff..fffXX, lowest XX bits are: scavvvvv,
+        * s=0 if SHIFT, c=0 if CTRL, a=0 if ALT,
+        * vvvvv bits are the same for same key regardless of "shift bits".
         */
-       //KEYCODE_SHIFT_TAB  = (-12)         & ~0x80,
-       //KEYCODE_SHIFT_...  = KEYCODE_...   & ~0x80,
-       //KEYCODE_CTRL_UP    = KEYCODE_UP    & ~0x40,
-       //KEYCODE_CTRL_DOWN  = KEYCODE_DOWN  & ~0x40,
-       KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40,
-       KEYCODE_CTRL_LEFT  = KEYCODE_LEFT  & ~0x40,
-       //KEYCODE_ALT_UP     = KEYCODE_UP    & ~0x20,
-       //KEYCODE_ALT_DOWN   = KEYCODE_DOWN  & ~0x20,
-       KEYCODE_ALT_RIGHT  = KEYCODE_RIGHT & ~0x20,
-       KEYCODE_ALT_LEFT   = KEYCODE_LEFT  & ~0x20,
+       //KEYCODE_SHIFT_...   = KEYCODE_...   & ~0x80,
+       KEYCODE_CTRL_RIGHT    = KEYCODE_RIGHT & ~0x40,
+       KEYCODE_CTRL_LEFT     = KEYCODE_LEFT  & ~0x40,
+       KEYCODE_ALT_RIGHT     = KEYCODE_RIGHT & ~0x20,
+       KEYCODE_ALT_LEFT      = KEYCODE_LEFT  & ~0x20,
+       KEYCODE_ALT_BACKSPACE = KEYCODE_BACKSPACE & ~0x20,
+       KEYCODE_ALT_D         = KEYCODE_D     & ~0x20,
 
        KEYCODE_CURSOR_POS = -0x100, /* 0xfff..fff00 */
        /* How long is the longest ESC sequence we know?
index 2cc61db40be2bdc7d0eb86b771506afac44e2bc3..ac049f57d9bc7027e8b92dc0a4df8ddf5954ffba 100644 (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 */
 
index ace23defb88a5f70cadff88e2acb1713f935519e..951786869c25e8104ca84bd4abfd4cf495539790 100644 (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   ,