diff --git a/src/utils/edit.c b/src/utils/edit.c index 22b91746e..d4de2b168 100644 --- a/src/utils/edit.c +++ b/src/utils/edit.c @@ -37,6 +37,9 @@ static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) = static struct termios prevt, newt; +#define CLEAR_END_LINE "\e[K" + + void edit_clear_line(void) { int i; @@ -785,13 +788,169 @@ static enum edit_key_code edit_read_key(int sock) } +static char search_buf[21]; +static int search_skip; + +static char * search_find(void) +{ + int pos = history_pos; + size_t len = os_strlen(search_buf); + int skip = search_skip; + + if (len == 0) + return NULL; + + for (;;) { + if (pos == 0) + pos = CMD_HISTORY_LEN - 1; + else + pos--; + if (pos == history_pos) { + search_skip = 0; + return NULL; + } + + if (os_strstr(history_buf[pos], search_buf)) { + if (skip == 0) + return history_buf[pos]; + skip--; + } + } +} + + +static void search_redraw(void) +{ + char *match = search_find(); + printf("\rsearch '%s': %s" CLEAR_END_LINE, + search_buf, match ? match : ""); + printf("\rsearch '%s", search_buf); + fflush(stdout); +} + + +static void search_start(void) +{ + edit_clear_line(); + search_buf[0] = '\0'; + search_skip = 0; + search_redraw(); +} + + +static void search_clear(void) +{ + search_redraw(); + printf("\r" CLEAR_END_LINE); +} + + +static void search_stop(void) +{ + char *match = search_find(); + search_buf[0] = '\0'; + search_clear(); + if (match) { + os_strlcpy(cmdbuf, match, CMD_BUF_LEN); + cmdbuf_len = os_strlen(cmdbuf); + cmdbuf_pos = cmdbuf_len; + } + edit_redraw(); +} + + +static void search_cancel(void) +{ + search_buf[0] = '\0'; + search_clear(); + edit_redraw(); +} + + +static void search_backspace(void) +{ + size_t len; + len = os_strlen(search_buf); + if (len == 0) + return; + search_buf[len - 1] = '\0'; + search_skip = 0; + search_redraw(); +} + + +static void search_next(void) +{ + search_skip++; + search_find(); + search_redraw(); +} + + +static void search_char(char c) +{ + size_t len; + len = os_strlen(search_buf); + if (len == sizeof(search_buf) - 1) + return; + search_buf[len] = c; + search_buf[len + 1] = '\0'; + search_skip = 0; + search_redraw(); +} + + +static enum edit_key_code search_key(enum edit_key_code c) +{ + switch (c) { + case EDIT_KEY_ENTER: + case EDIT_KEY_CTRL_J: + case EDIT_KEY_LEFT: + case EDIT_KEY_RIGHT: + case EDIT_KEY_HOME: + case EDIT_KEY_END: + case EDIT_KEY_CTRL_A: + case EDIT_KEY_CTRL_E: + search_stop(); + return c; + case EDIT_KEY_DOWN: + case EDIT_KEY_UP: + search_cancel(); + return EDIT_KEY_EOF; + case EDIT_KEY_CTRL_H: + case EDIT_KEY_BACKSPACE: + search_backspace(); + break; + case EDIT_KEY_CTRL_R: + search_next(); + break; + default: + if (c >= 32 && c <= 255) + search_char(c); + break; + } + + return EDIT_KEY_NONE; +} + + static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) { static int last_tab = 0; + static int search = 0; enum edit_key_code c; c = edit_read_key(sock); + if (search) { + c = search_key(c); + if (c == EDIT_KEY_NONE) + return; + search = 0; + if (c == EDIT_KEY_EOF) + return; + } + if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE) last_tab = 0; @@ -867,7 +1026,8 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) edit_redraw(); break; case EDIT_KEY_CTRL_R: - /* TODO: search history */ + search = 1; + search_start(); break; case EDIT_KEY_CTRL_U: clear_left();