Hi, just wanted to remind in case this patch got lost in the mailing list..

On Thu, 30 Jun 2011, kyak wrote:

Implemented readline's mimic for reverse history search (Ctrl+r)

Signed-off-by: kyak <[email protected]>
---
libbb/Config.src |    7 ++
libbb/lineedit.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 200 insertions(+), 0 deletions(-)

diff --git a/libbb/Config.src b/libbb/Config.src
index 0ea8f43..3b1487d 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -94,6 +94,13 @@ config FEATURE_EDITING_SAVEHISTORY
        help
          Enable history saving in shells.

+config FEATURE_REVERSE_SEARCH
+       bool "Reverse history search"
+       default n
+       depends on FEATURE_EDITING_SAVEHISTORY
+       help
+         Enable readline-alike Ctrl+r combination for reverse history search
+
config FEATURE_TAB_COMPLETION
        bool "Tab completion"
        default y
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 4e3bc0e..c9c6728 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1948,6 +1948,194 @@ static int isrtl_str(void)
#undef CTRL
#define CTRL(a) ((a) & ~0x40)

+#if ENABLE_FEATURE_REVERSE_SEARCH
+/* mimic readline's Ctrl+r behaviour for reverse history search */
+static smallint reverse_i_search(void)
+{
+       /* prepare the prompt */
+       const char prmt[] = "(reverse-i-search)`";
+       int prmt_len = strlen(prmt);
+       char *prmt_mem_ptr = xzalloc(1);
+       /* save the real prompt */
+       char *prmt_mem_ptr_save = xzalloc(1);
+       /* user input is collected here */
+       char *match_buf;
+       /* matched lines from history are here */
+       char *cmdline_buf;
+       char read_key_buffer[KEYCODE_BUFFER_SIZE];
+       int ic;
+       char buf[MB_CUR_MAX + 1];
+       wchar_t wc[MAX_LINELEN];
+       ssize_t len, len_cmd;
+       mbstate_t mbst = { 0 };
+       smallint break_out = 0;
+       smallint break_out_search = 0;
+       smallint has_match = 0;
+       int i;
+       int cur = state->cur_history, cur_match = state->cur_history;
+       int cmdedit_y_add = 0, cmdedit_y_add_prev = 0, cmdedit_y_add_cmp = 0;
+
+       read_key_buffer[0] = 0;
+       prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), prmt);
+       /* save prompt */
+ prmt_mem_ptr_save = strcat(xrealloc(prmt_mem_ptr_save, cmdedit_prmt_len+1), cmdedit_prompt);
+       /* overwrite the prompt */
+       cmdedit_prompt = prmt_mem_ptr;
+       cmdedit_prmt_len = prmt_len;
+       /* save what's already typed */
+       match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t));
+       cmdline_buf = xmalloc(MAX_LINELEN * sizeof(int16_t));
+       save_string(match_buf, MAX_LINELEN);
+       command_len = load_string("", MAX_LINELEN);
+       redraw(cmdedit_y, 0);
+       fputs(match_buf, stdout);
+       fputs("': ", stdout);
+       fputs(match_buf, stdout);
+ cmdedit_y_add_cmp = (prmt_len+1 + 2 * strlen(match_buf)) / (cmdedit_termw);
+       cmdedit_y_add_prev = cmdedit_y_add_cmp;
+       /* switch to char-consumption mode... */
+       while (1) {
+               fflush_all();
+               ic = lineedit_read_key(read_key_buffer, -1);
+               switch (ic) {
+ case KEYCODE_RIGHT: /* left-right keys act differently from Enter */
+                       case KEYCODE_LEFT:
+                               if (has_match == 1) {
+ command_len = load_string(cmdline_buf, MAX_LINELEN);
+                               } else {
+ command_len = load_string(match_buf, MAX_LINELEN);
+                               }
+                               cmdedit_prompt = prmt_mem_ptr_save;
+                               cmdedit_prmt_len = strlen(cmdedit_prompt);
+                               redraw(cmdedit_y + cmdedit_y_add, 0);
+                               break_out = 0;
+                               break;
+                       case CTRL('R'): /* searching for the next match */
+                               break_out = 2;
+                               break;
+                       case CTRL('C'):
+                       case KEYCODE_UP:
+                       case KEYCODE_DOWN:
+                       case KEYCODE_HOME:
+                       case KEYCODE_END:
+                       case KEYCODE_DELETE:
+                       case KEYCODE_CTRL_RIGHT:
+                       case KEYCODE_CTRL_LEFT:
+                       case '\x1b': /* ESC */
+                               command_len = load_string("", MAX_LINELEN);
+                               cmdedit_prompt = prmt_mem_ptr_save;
+                               redraw(cmdedit_y + cmdedit_y_add, 0);
+                               break_out = 0;
+                               break;
+                       case '\b':   /* ^H */
+                       case '\x7f': /* DEL */
+                               /* convert to wide char string,
+                                * delete char, then convert back */
+                               len = mbstowcs(wc, match_buf, sizeof(wc));
+                               if (len < 0)
+                                       len = 0;
+                               wc[len-1] = '\0';
+                               wcstombs(match_buf, wc, MAX_LINELEN);
+                               break_out = 2;
+                               has_match = 0;
+                               break;
+                       case '\r':
+                       case '\n': /* Enter */
+                               if (has_match == 1) {
+ command_len = load_string(cmdline_buf, MAX_LINELEN);
+                               } else {
+ command_len = load_string(match_buf, MAX_LINELEN);
+                               }
+                               cmdedit_prompt = prmt_mem_ptr_save;
+                               redraw(cmdedit_y + cmdedit_y_add, 0);
+                               goto_new_line();
+                               break_out = 1;
+                               break;
+                       default: /* process the char */
+                               len = wcrtomb(buf, ic, &mbst);
+                               if (len > 0) {
+                                       buf[len] = '\0';
+                               }
+                               strcat(match_buf, buf);
+                               break_out = 2;
+                               break;
+               }
+               if (break_out != 2)
+                       break;
+               /* if there is something in type buffer,
+                * do iterative search in history */
+               if (strlen(match_buf) > 0) {
+                       /* save current position in history */
+                       cur = state->cur_history;
+                       if (ic != CTRL('R')) {
+                               cur_match = state->cur_history;
+                       } else {
+                               /* if we hit Ctrl+r (again),
+ * start searching from the last matched position */
+                               state->cur_history = cur_match;
+                       }
+                       while(get_previous_history()) {
+ cmdline_buf = state->history[state->cur_history] ? + state->history[state->cur_history] : '\0';
+                               has_match = 0;
+                               break_out_search = 0;
+ for(i=0;i+strlen(match_buf)<=strlen(cmdline_buf);i++) { + if (strncmp(match_buf, cmdline_buf+i, strlen(match_buf)) == 0) {
+                                               has_match = 1;
+                                               break_out_search = 1;
+ /* save position of current match */ + cur_match = state->cur_history;
+                                               break;
+                                       }
+                               }
+                               if (break_out_search == 1)
+                                       break;
+                       }
+               }
+ /* TODO: this could be done better. There are still some (rare)
+                * cases of wrapping miscalculation */
+               len = mbstowcs(wc, match_buf, sizeof(wc));
+               if (len < 0)
+                       len = strlen(match_buf);
+
+               len_cmd = mbstowcs(wc, cmdline_buf, sizeof(wc));
+               if (len_cmd < 0)
+                       len_cmd = strlen(cmdline_buf);
+
+ cmdedit_y_add = (prmt_len+1 + len + (has_match ? len_cmd : len)) /
+                       (cmdedit_termw);
+
+               if (cmdedit_y_add > cmdedit_y_add_cmp) {
+ for (int j = 1; j <= (cmdedit_y_add-cmdedit_y_add_cmp); j++) {
+                               /* scroll up */
+                               printf(ESC"D");
+                       }
+                       if (cmdedit_y_add-cmdedit_y_add_cmp > 1)
+ redraw(cmdedit_y + cmdedit_y_add - cmdedit_y_add_cmp, 0);
+                       else
+                               redraw(cmdedit_y + cmdedit_y_add, 0);
+                       cmdedit_y_add_cmp = cmdedit_y_add;
+               } else if (cmdedit_y_add != cmdedit_y_add_prev) {
+                       redraw(cmdedit_y + cmdedit_y_add_prev, 0);
+               } else {
+                       redraw(cmdedit_y + cmdedit_y_add, 0);
+               }
+
+               fputs(match_buf, stdout);
+               fputs("': ", stdout);
+               if (has_match == 0) {
+                       fputs(match_buf, stdout);
+               } else {
+                       fputs(cmdline_buf, stdout);
+               }
+               cmdedit_y_add_prev = cmdedit_y_add;
+               /* restore current position in history */
+               state->cur_history=cur;
+       } /* !while */
+       return break_out;
+}
+#endif
+
/* maxsize must be >= 2.
 * Returns:
 * -1 on read errors or EOF, or on bare Ctrl-D,
@@ -2174,6 +2362,11 @@ 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;
+#if ENABLE_FEATURE_REVERSE_SEARCH
+               case CTRL('R'):
+                       break_out = reverse_i_search();
+                       break;
+#endif

#if ENABLE_FEATURE_EDITING_VI
                case 'i'|VI_CMDMODE_BIT:
--
1.7.1
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to