[git commit] lineedit: fix handling of repeating Alt-b, Alt-f, Alt-d, Alt-Backspace

Denys Vlasenko vda.linux at googlemail.com
Thu Nov 24 14:04:00 UTC 2016


commit: https://git.busybox.net/busybox/commit/?id=2e4ef38743c3d4aef109b5cc04429ec1f0e2f6c8
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at tuxera.com>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 include/libbb.h  | 76 ++++++++++++++++++++++++++++----------------------------
 libbb/lineedit.c | 60 ++++++++++++++------------------------------
 libbb/read_key.c | 12 +++++++++
 3 files changed, 68 insertions(+), 80 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index 20fc732..bdafcf5 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -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?
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 2cc61db..ac049f5 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -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 */
 
diff --git a/libbb/read_key.c b/libbb/read_key.c
index ace23de..9517868 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -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   ,


More information about the busybox-cvs mailing list