fix bug #5978 "history searching (ctrl-R) doesn't work"
authorDennis Groenen <tj.groenen@gmail.com>
Wed, 3 Aug 2011 14:47:42 +0000 (16:47 +0200)
committerDennis Groenen <tj.groenen@gmail.com>
Wed, 3 Aug 2011 14:47:42 +0000 (16:47 +0200)
debian/config/config.busybox
debian/patches/ctrl_r-history-search.patch [new file with mode: 0644]
debian/patches/series

index 7e210c3..22271aa 100644 (file)
@@ -99,6 +99,7 @@ CONFIG_FEATURE_EDITING_MAX_LEN=1024
 # CONFIG_FEATURE_EDITING_VI is not set
 CONFIG_FEATURE_EDITING_HISTORY=100
 CONFIG_FEATURE_EDITING_SAVEHISTORY=y
+CONFIG_FEATURE_REVERSE_SEARCH=y
 CONFIG_FEATURE_TAB_COMPLETION=y
 # CONFIG_FEATURE_USERNAME_COMPLETION is not set
 CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
diff --git a/debian/patches/ctrl_r-history-search.patch b/debian/patches/ctrl_r-history-search.patch
new file mode 100644 (file)
index 0000000..a952318
--- /dev/null
@@ -0,0 +1,241 @@
+libbb/lineedit: implement optional Ctrl-R history search
+Source: http://git.busybox.net/busybox/commit/?id=a669eca3a230e35e4a6894a30168a047000f3b75
+---
+
+--- a/libbb/Config.src
++++ b/libbb/Config.src
+@@ -93,6 +93,14 @@ config FEATURE_EDITING_SAVEHISTORY
+       help
+         Enable history saving in shells.
++config FEATURE_REVERSE_SEARCH
++      bool "Reverse history search"
++      default y
++      depends on FEATURE_EDITING_SAVEHISTORY
++      help
++        Enable readline-like Ctrl-R combination for reverse history search.
++        Increases code by about 0.5k.
++
+ config FEATURE_TAB_COMPLETION
+       bool "Tab completion"
+       default y
+--- a/libbb/lineedit.c
++++ b/libbb/lineedit.c
+@@ -202,9 +202,9 @@ static void deinit_S(void)
+ #if ENABLE_UNICODE_SUPPORT
+-static size_t load_string(const char *src, int maxsize)
++static size_t load_string(const char *src)
+ {
+-      ssize_t len = mbstowcs(command_ps, src, maxsize - 1);
++      ssize_t len = mbstowcs(command_ps, src, S.maxsize - 1);
+       if (len < 0)
+               len = 0;
+       command_ps[len] = BB_NUL;
+@@ -297,9 +297,9 @@ static wchar_t adjust_width_and_validate
+       return wc;
+ }
+ #else /* !UNICODE */
+-static size_t load_string(const char *src, int maxsize)
++static size_t load_string(const char *src)
+ {
+-      safe_strncpy(command_ps, src, maxsize);
++      safe_strncpy(command_ps, src, S.maxsize);
+       return strlen(command_ps);
+ }
+ # if ENABLE_FEATURE_TAB_COMPLETION
+@@ -1202,10 +1202,10 @@ static NOINLINE void input_tab(smallint 
+                       strcpy(match_buf, &command[cursor_mb]);
+                       /* where do we want to have cursor after all? */
+                       strcpy(&command[cursor_mb], chosen_match + match_pfx_len);
+-                      len = load_string(command, S.maxsize);
++                      len = load_string(command);
+                       /* add match and tail */
+                       sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf);
+-                      command_len = load_string(command, S.maxsize);
++                      command_len = load_string(command);
+                       /* write out the matched command */
+                       /* paranoia: load_string can return 0 on conv error,
+                        * prevent passing pos = (0 - 12) to redraw */
+@@ -1911,6 +1911,140 @@ static int isrtl_str(void)
+ #undef CTRL
+ #define CTRL(a) ((a) & ~0x40)
++enum {
++      VI_CMDMODE_BIT = 0x40000000,
++      /* 0x80000000 bit flags KEYCODE_xxx */
++};
++
++#if ENABLE_FEATURE_REVERSE_SEARCH
++/* Mimic readline Ctrl-R reverse history search.
++ * When invoked, it shows the following prompt:
++ * (reverse-i-search)'': user_input [cursor pos unchanged by Ctrl-R]
++ * and typing results in search being performed:
++ * (reverse-i-search)'tmp': cd /tmp [cursor under t in /tmp]
++ * Search is performed by looking at progressively older lines in history.
++ * Ctrl-R again searches for the next match in history.
++ * Backspace deletes last matched char.
++ * Control keys exit search and return to normal editing (at current history line).
++ */
++static int32_t reverse_i_search(void)
++{
++      char match_buf[128]; /* for user input */
++      char read_key_buffer[KEYCODE_BUFFER_SIZE];
++      const char *matched_history_line;
++      const char *saved_prompt;
++      int32_t ic;
++
++      matched_history_line = NULL;
++      read_key_buffer[0] = 0;
++      match_buf[0] = '\0';
++
++      /* Save and replace the prompt */
++      saved_prompt = cmdedit_prompt;
++      goto set_prompt;
++
++      while (1) {
++              int h;
++              unsigned match_buf_len = strlen(match_buf);
++
++              fflush_all();
++//FIXME: correct timeout?
++              ic = lineedit_read_key(read_key_buffer);
++
++              switch (ic) {
++              case CTRL('R'): /* searching for the next match */
++                      break;
++
++              case '\b':
++              case '\x7f':
++                      /* Backspace */
++                      if (unicode_status == UNICODE_ON) {
++                              while (match_buf_len != 0) {
++                                      uint8_t c = match_buf[--match_buf_len];
++                                      if ((c & 0xc0) != 0x80) /* start of UTF-8 char? */
++                                              break; /* yes */
++                              }
++                      } else {
++                              if (match_buf_len != 0)
++                                      match_buf_len--;
++                      }
++                      match_buf[match_buf_len] = '\0';
++                      break;
++
++              default:
++                      if (ic < ' '
++                       || (!ENABLE_UNICODE_SUPPORT && ic >= 256)
++                       || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT)
++                      ) {
++                              goto ret;
++                      }
++
++                      /* Append this char */
++#if ENABLE_UNICODE_SUPPORT
++                      if (unicode_status == UNICODE_ON) {
++                              mbstate_t mbstate = { 0 };
++                              char buf[MB_CUR_MAX + 1];
++                              int len = wcrtomb(buf, ic, &mbstate);
++                              if (len > 0) {
++                                      buf[len] = '\0';
++                                      if (match_buf_len + len < sizeof(match_buf))
++                                              strcpy(match_buf + match_buf_len, buf);
++                              }
++                      } else
++#endif
++                      if (match_buf_len < sizeof(match_buf) - 1) {
++                              match_buf[match_buf_len] = ic;
++                              match_buf[match_buf_len + 1] = '\0';
++                      }
++                      break;
++              } /* switch (ic) */
++
++              /* Search in history for match_buf */
++              h = state->cur_history;
++              if (ic == CTRL('R'))
++                      h--;
++              while (h >= 0) {
++                      if (state->history[h]) {
++                              char *match = strstr(state->history[h], match_buf);
++                              if (match) {
++                                      state->cur_history = h;
++                                      matched_history_line = state->history[h];
++                                      command_len = load_string(matched_history_line);
++                                      cursor = match - matched_history_line;
++//FIXME: cursor position for Unicode case
++
++                                      free((char*)cmdedit_prompt);
++ set_prompt:
++                                      cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf);
++                                      cmdedit_prmt_len = strlen(cmdedit_prompt);
++                                      goto do_redraw;
++                              }
++                      }
++                      h--;
++              }
++
++              /* Not found */
++              match_buf[match_buf_len] = '\0';
++              beep();
++              continue;
++
++ do_redraw:
++              redraw(cmdedit_y, command_len - cursor);
++      } /* while (1) */
++
++ ret:
++      if (matched_history_line)
++              command_len = load_string(matched_history_line);
++
++      free((char*)cmdedit_prompt);
++      cmdedit_prompt = saved_prompt;
++      cmdedit_prmt_len = strlen(cmdedit_prompt);
++      redraw(cmdedit_y, command_len - cursor);
++
++      return ic;
++}
++#endif
++
+ /* maxsize must be >= 2.
+  * Returns:
+  * -1 on read errors or EOF, or on bare Ctrl-D,
+@@ -2026,15 +2160,14 @@ int FAST_FUNC read_line_input(const char
+                * clutters the big switch a bit, but keeps all the code
+                * in one place.
+                */
+-              enum {
+-                      VI_CMDMODE_BIT = 0x40000000,
+-                      /* 0x80000000 bit flags KEYCODE_xxx */
+-              };
+               int32_t ic, ic_raw;
+               fflush_all();
+               ic = ic_raw = lineedit_read_key(read_key_buffer);
++#if ENABLE_FEATURE_REVERSE_SEARCH
++ again:
++#endif
+ #if ENABLE_FEATURE_EDITING_VI
+               newdelflag = 1;
+               if (vi_cmdmode) {
+@@ -2138,6 +2271,11 @@ int FAST_FUNC read_line_input(const char
+                       while (cursor > 0 && !BB_isspace(command_ps[cursor-1]))
+                               input_backspace();
+                       break;
++#if ENABLE_FEATURE_REVERSE_SEARCH
++              case CTRL('R'):
++                      ic = ic_raw = reverse_i_search();
++                      goto again;
++#endif
+ #if ENABLE_FEATURE_EDITING_VI
+               case 'i'|VI_CMDMODE_BIT:
+@@ -2291,7 +2429,7 @@ int FAST_FUNC read_line_input(const char
+                       /* Rewrite the line with the selected history item */
+                       /* change command */
+                       command_len = load_string(state->history[state->cur_history] ?
+-                                      state->history[state->cur_history] : "", maxsize);
++                                      state->history[state->cur_history] : "");
+                       /* redraw and go to eol (bol, in vi) */
+                       redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
+                       break;
index 13d2583..fe4d601 100644 (file)
@@ -21,4 +21,5 @@ showkey-any-stdin.patch
 showkey-default-option.patch
 ps-accept-and-ignore-missing-options.patch
 ash-history-buffer.patch
+ctrl_r-history-search.patch