diff --git a/Makefile.am b/Makefile.am index dee252f7..1b592332 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,7 +16,7 @@ TESTS=tests/01.t tests/02.t tests/03.t tests/04.t tests/05.t tests/06.t \ tests/37.t tests/38.t tests/39.t tests/40.t tests/41.t tests/42.t \ tests/43.t tests/44.t tests/45.t tests/46.t tests/47.t tests/48.t \ tests/49.t tests/50.t tests/51.t tests/52.t tests/53.t tests/54.t \ - tests/55.t tests/56.t tests/57.t tests/58.t + tests/55.t tests/56.t tests/57.t tests/58.t tests/59.t tests/60.t TEST_EXTENSIONS=.t T_LOG_COMPILER=$(top_srcdir)/tests/pick-test.sh AM_COLOR_TESTS=no diff --git a/pick.1 b/pick.1 index 2f49d88e..53f2ac24 100644 --- a/pick.1 +++ b/pick.1 @@ -74,8 +74,10 @@ Delete one character to the left of the cursor in the search query input field. .It Ic Delete | Ctrl-D Delete the character under the cursor in the search query input field. .It Ic Ctrl-W -Delete to the beginning of the closest word to the left in the search query -input field. +Delete the word to the left of the cursor. +A word is recognized as a sequence of characters for which either +.Xr isalnum 3 +is true or the character is an underscore. .It Ic Ctrl-U Delete to the beginning of the line in the search query input field. .It Ic Ctrl-K diff --git a/pick.c b/pick.c index 9c8223de..0f0b831f 100644 --- a/pick.c +++ b/pick.c @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef HAVE_NCURSESW_H #include @@ -74,6 +75,7 @@ static __dead void handle_sigint(int); static void handle_sigwinch(int); static int isu8cont(unsigned char); static int isu8start(unsigned char); +static int isword(const char *); static size_t min_match(const char *, size_t, ssize_t *, ssize_t *); static int print_choices(int, int); @@ -285,7 +287,7 @@ selected_choice(void) { size_t cursor_position, i, j, length, xscroll; char buf[6]; - int choices_count, word_position; + int choices_count; int selection = 0; int yscroll = 0; @@ -413,22 +415,21 @@ selected_choice(void) if (cursor_position == 0) break; - for (word_position = cursor_position;;) { - while (isu8cont(query[--word_position])) + for (i = cursor_position; i > 0;) { + while (isu8cont(query[--i])) continue; - if (word_position < 1) + if (isword(query + i)) break; - if (query[word_position] != ' ' - && query[word_position - 1] == ' ') + } + for (j = i; i > 0; i = j) { + while (isu8cont(query[--j])) + continue; + if (!isword(query + j)) break; } - delete_between( - query, - query_length, - word_position, - cursor_position); - query_length -= cursor_position - word_position; - cursor_position = word_position; + delete_between(query, query_length, i, cursor_position); + query_length -= cursor_position - i; + cursor_position = i; filter_choices(); selection = yscroll = 0; break; @@ -1037,3 +1038,19 @@ isu8start(unsigned char c) { return MB_CUR_MAX > 1 && (c & (0x80 | 0x40)) == (0x80 | 0x40); } + +int +isword(const char *s) +{ + wchar_t wc; + + switch (mbtowc(&wc, s, MB_CUR_MAX)) { + case -1: + mbtowc(NULL, NULL, MB_CUR_MAX); + /* FALLTHROUGH */ + case 0: + return 0; + } + + return iswalnum(wc) || wc == L'_'; +} diff --git a/tests/13.t b/tests/13.t index dc6f9083..be8ee418 100644 --- a/tests/13.t +++ b/tests/13.t @@ -1,7 +1,7 @@ description: UTF-8 delete word -keys: aa bå \027 bb \n # CTRL_W ENTER +keys: aa\\ Åå \027 aa\\ aa \n # CTRL_W ENTER stdin: -aa bb -aa bå +aa Åå aa +aa Åå aa aa stdout: -aa bb +aa Åå aa aa diff --git a/tests/59.t b/tests/59.t new file mode 100644 index 00000000..d526a577 --- /dev/null +++ b/tests/59.t @@ -0,0 +1,7 @@ +description: non alphanumeric characters are not recognized as part of a word +keys: a/a \027 a/a \n # CTRL_W ENTER +stdin: +a/a +a/a/a +stdout: +a/a/a diff --git a/tests/60.t b/tests/60.t new file mode 100644 index 00000000..1426eaa6 --- /dev/null +++ b/tests/60.t @@ -0,0 +1,7 @@ +description: underscore is recognized as part of a word +keys: aa_aa \027 bb \n # CTRL_W ENTER +stdin: +aa_aa_bb +bb +stdout: +bb