From 9ce09bc9cb7743f87eb3e536c81d8c303e12bc81 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Thu, 3 Nov 2011 13:28:22 +0100
Subject: lineedit: add support for M-b, M-f, M-d, M-Backspace

function                                             old     new   delta
ctrl_left                                              -      96     +96
ctrl_right                                             -      76     +76
static.esccmds                                        81      93     +12
read_line_input                                     3876    3885      +9
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 2/0 up/down: 193/0)             Total: 193 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 include/libbb.h  | 46 +++++++++++++++++++++++++++++-----------------
 libbb/lineedit.c | 40 ++++++++++++++++++++++++++++++++++++++++
 libbb/read_key.c | 11 ++++++++---
 3 files changed, 77 insertions(+), 20 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index 791cdd94e..53224fa35 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1358,25 +1358,37 @@ enum {
 	KEYCODE_DELETE   =  -9,
 	KEYCODE_PAGEUP   = -10,
 	KEYCODE_PAGEDOWN = -11,
-
-	KEYCODE_CTRL_UP    = KEYCODE_UP    & ~0x40,
-	KEYCODE_CTRL_DOWN  = KEYCODE_DOWN  & ~0x40,
+	// -12 is reserved for Alt/Ctrl/Shift-TAB
+#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_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,
-#if 0
-	KEYCODE_FUN1     = -12,
-	KEYCODE_FUN2     = -13,
-	KEYCODE_FUN3     = -14,
-	KEYCODE_FUN4     = -15,
-	KEYCODE_FUN5     = -16,
-	KEYCODE_FUN6     = -17,
-	KEYCODE_FUN7     = -18,
-	KEYCODE_FUN8     = -19,
-	KEYCODE_FUN9     = -20,
-	KEYCODE_FUN10    = -21,
-	KEYCODE_FUN11    = -22,
-	KEYCODE_FUN12    = -23,
-#endif
+	//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_CURSOR_POS = -0x100, /* 0xfff..fff00 */
 	/* How long is the longest ESC sequence we know?
 	 * We want it big enough to be able to contain
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 603bbfcae..0d232889b 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -2504,6 +2504,44 @@ 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, timeout);
+			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;
+					input_backward(cursor - sc);
+					while (--nc >= cursor)
+						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 */
 
@@ -2532,9 +2570,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
 			input_backward(1);
 			break;
 		case KEYCODE_CTRL_LEFT:
+		case KEYCODE_ALT_LEFT: /* bash doesn't do it */
 			ctrl_left();
 			break;
 		case KEYCODE_CTRL_RIGHT:
+		case KEYCODE_ALT_RIGHT: /* bash doesn't do it */
 			ctrl_right();
 			break;
 		case KEYCODE_HOME:
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 5dcd19c3f..8d72d2a63 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -40,13 +40,14 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
 		'[','C'        |0x80,KEYCODE_RIGHT   ,
 		'[','D'        |0x80,KEYCODE_LEFT    ,
 		/* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift-<arrow> */
-		/* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt-<arrow> */
+		/* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt-<arrow> - implemented below */
 		/* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */
 		/* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */
 		/* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */
 		'[','H'        |0x80,KEYCODE_HOME    , /* xterm */
-		/* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */
 		'[','F'        |0x80,KEYCODE_END     , /* xterm */
+		/* [ESC] ESC [ [2] H - [Alt-][Shift-]Home (End similarly?) */
+		/* '[','Z'        |0x80,KEYCODE_SHIFT_TAB, */
 		'[','1','~'    |0x80,KEYCODE_HOME    , /* vt100? linux vt? or what? */
 		'[','2','~'    |0x80,KEYCODE_INSERT  ,
 		/* ESC [ 2 ; 3 ~ - Alt-Insert */
@@ -86,8 +87,12 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
 		/* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */
 		'[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT,
 		'[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT ,
+		/* '[','1',';','3','A' |0x80,KEYCODE_ALT_UP    , - unused */
+		/* '[','1',';','3','B' |0x80,KEYCODE_ALT_DOWN  , - unused */
+		'[','1',';','3','C' |0x80,KEYCODE_ALT_RIGHT,
+		'[','1',';','3','D' |0x80,KEYCODE_ALT_LEFT ,
+		/* '[','3',';','3','~' |0x80,KEYCODE_ALT_DELETE, - unused */
 		0
-		/* ESC [ Z - Shift-Tab */
 	};
 
 	pfd.fd = fd;
-- 
cgit v1.2.3-55-g6feb