lineedit: handle Ctrl-arrows
function old new delta
read_line_input 4629 4824 +195
BB_isalnum - 39 +39
BB_ispunct - 35 +35
BB_isspace - 31 +31
static.esccmds 69 93 +24
vi_word_motion 165 162 -3
vi_back_motion 204 198 -6
vi_end_motion 172 163 -9
bb_iswspace 28 - -28
bb_iswpunct 32 - -32
bb_iswalnum 37 - -37
------------------------------------------------------------------------------
(add/remove: 3/3 grow/shrink: 5/8 up/down: 334/-129) Total: 205 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 5f5beb1..bfd0e33 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -16,12 +16,18 @@
/*
* Usage and known bugs:
- * Terminal key codes are not extensive, and more will probably
- * need to be added. This version was created on Debian GNU/Linux 2.x.
+ * Terminal key codes are not extensive, more needs to be added.
+ * This version was created on Debian GNU/Linux 2.x.
* Delete, Backspace, Home, End, and the arrow keys were tested
* to work in an Xterm and console. Ctrl-A also works as Home.
* 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
* take up space on the screen. The redisplay code assumes, unless
* told otherwise, that each character in the prompt is a printable
@@ -64,11 +70,9 @@
#if ENABLE_FEATURE_ASSUME_UNICODE
# define BB_NUL L'\0'
# define CHAR_T wchar_t
-# define BB_isspace(c) iswspace(c)
-# define BB_isalnum(c) iswalnum(c)
-# define BB_ispunct(c) iswpunct(c)
-# define BB_isprint(c) iswprint(c)
-/* this catches bugs */
+static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); }
+static bool BB_isalnum(CHAR_T c) { return ((unsigned)c < 256 && isalnum(c)); }
+static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
# undef isspace
# undef isalnum
# undef ispunct
@@ -83,11 +87,6 @@
# define BB_isspace(c) isspace(c)
# define BB_isalnum(c) isalnum(c)
# define BB_ispunct(c) ispunct(c)
-# if ENABLE_LOCALE_SUPPORT
-# define BB_isprint(c) isprint(c)
-# else
-# define BB_isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233'))
-# endif
#endif
@@ -1302,24 +1301,10 @@
#endif /* MAX_HISTORY */
+#if ENABLE_FEATURE_EDITING_VI
/*
- * This function is used to grab a character buffer
- * from the input file descriptor and allows you to
- * a string with full command editing (sort of like
- * a mini readline).
- *
- * The following standard commands are not implemented:
- * ESC-b -- Move back one word
- * ESC-f -- Move forward one word
- * ESC-d -- Delete back one word
- * ESC-h -- Delete forward one word
- * CTL-t -- Transpose two characters
- *
- * Minimalist vi-style command line editing available if configured.
* vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
*/
-
-#if ENABLE_FEATURE_EDITING_VI
static void
vi_Word_motion(int eat)
{
@@ -1428,6 +1413,58 @@
}
#endif
+/* Modelled after bash 4.0 behavior of Ctrl-<arrow> */
+static void ctrl_left(void)
+{
+ CHAR_T *command = command_ps;
+
+ while (1) {
+ CHAR_T c;
+
+ input_backward(1);
+ if (cursor == 0)
+ break;
+ c = command[cursor];
+ if (c != ' ' && !BB_ispunct(c)) {
+ /* we reached a "word" delimited by spaces/punct.
+ * go to its beginning */
+ while (1) {
+ c = command[cursor - 1];
+ if (c == ' ' || BB_ispunct(c))
+ break;
+ input_backward(1);
+ if (cursor == 0)
+ break;
+ }
+ break;
+ }
+ }
+}
+static void ctrl_right(void)
+{
+ CHAR_T *command = command_ps;
+
+ while (1) {
+ CHAR_T c;
+
+ c = command[cursor];
+ if (c == BB_NUL)
+ break;
+ if (c != ' ' && !BB_ispunct(c)) {
+ /* we reached a "word" delimited by spaces/punct.
+ * go to its end + 1 */
+ while (1) {
+ input_forward();
+ c = command[cursor];
+ if (c == BB_NUL || c == ' ' || BB_ispunct(c))
+ break;
+ }
+ break;
+ }
+ input_forward();
+ }
+}
+
/*
* read_line_input and its helpers
@@ -2028,6 +2065,12 @@
case KEYCODE_LEFT:
input_backward(1);
break;
+ case KEYCODE_CTRL_LEFT:
+ ctrl_left();
+ break;
+ case KEYCODE_CTRL_RIGHT:
+ ctrl_right();
+ break;
case KEYCODE_DELETE:
input_delete(0);
break;