]> granicus.if.org Git - neomutt/commitdiff
Add history-search function, bound to ctrl-r.
authorKevin McCarthy <kevin@8t8.us>
Sun, 4 Feb 2018 02:08:28 +0000 (18:08 -0800)
committerRichard Russon <rich@flatcap.org>
Tue, 20 Feb 2018 22:04:56 +0000 (22:04 +0000)
Create a very basic "search history" functionality in the line editor.
It uses the current input, and searches backward through history.  If
there is one match, it immediately uses that otherwise it pops up a
simple menu of matches.

doc/manual.xml.head
enter.c
functions.h
history.c
history.h
opcodes.h

index 6fdc48f05fc06c70c8e955e46de07067c66b7eca..51a6f0f8824893eacd907d60d168789fca02706a 100644 (file)
@@ -1318,6 +1318,13 @@ color sidebar_divider   color8  default
                 </entry>
                 <entry>recall next string from history</entry>
               </row>
+              <row>
+                <entry>^R</entry>
+                <entry>
+                  <literal>&lt;history-search&gt;</literal>
+                </entry>
+                <entry>use current input to search history</entry>
+              </row>
               <row>
                 <entry>&lt;BackSpace&gt;</entry>
                 <entry>
diff --git a/enter.c b/enter.c
index f47575694e64158bfbcb3106f5798c43960b53c4..82865b91ddfc27dedf8cf7183307e5c465752b7f 100644 (file)
--- a/enter.c
+++ b/enter.c
@@ -263,6 +263,15 @@ int mutt_enter_string_full(char *buf, size_t buflen, int col, int flags, int mul
           redraw = MUTT_REDRAW_INIT;
           break;
 
+        case OP_EDITOR_HISTORY_SEARCH:
+          state->curpos = state->lastchar;
+          mutt_mb_wcstombs(buf, buflen, state->wbuf, state->curpos);
+          mutt_history_complete(buf, buflen, hclass);
+          replace_part(state, 0, buf);
+          rc = 1;
+          goto bye;
+          break;
+
         case OP_EDITOR_BACKSPACE:
           if (state->curpos == 0)
             BEEP();
index 23645fd5b6ce3520f2903450c8a42d45d92a213e..0af28f0a46e47e73d5f531367c4409bf107b9945 100644 (file)
@@ -536,6 +536,7 @@ const struct Binding OpEditor[] = { /* map: editor */
   { "buffy-cycle",           OP_EDITOR_BUFFY_CYCLE,          " " },
   { "history-up",            OP_EDITOR_HISTORY_UP,           NULL },
   { "history-down",          OP_EDITOR_HISTORY_DOWN,         NULL },
+  { "history-search",         OP_EDITOR_HISTORY_SEARCH,             "\022" },
   { "transpose-chars",       OP_EDITOR_TRANSPOSE_CHARS,      NULL },
   { NULL,                    0,                              NULL },
 };
index 94835882b19eb5986a94fc8cf33f324554a93b52..483ce9a40d8e205d438fb9b70ba940fe967cc490 100644 (file)
--- a/history.c
+++ b/history.c
 #include "mutt/mutt.h"
 #include "history.h"
 #include "globals.h"
+#include "keymap.h"
+#include "mutt_curses.h"
+#include "mutt_menu.h"
+#include "opcodes.h"
 #include "options.h"
 #include "protos.h"
 
@@ -112,6 +116,14 @@ struct History
   short last;
 };
 
+static const struct Mapping HistoryHelp[] = {
+  { N_("Exit"), OP_EXIT },
+  { N_("Select"), OP_GENERIC_SELECT_ENTRY },
+  { N_("Search"), OP_SEARCH },
+  { N_("Help"), OP_HELP },
+  { NULL, 0 },
+};
+
 /* global vars used for the string-history routines */
 
 short History;          /**< Number of history entries stored in memory */
@@ -632,3 +644,104 @@ void mutt_hist_save_scratch(enum HistoryClass hclass, const char *str)
    * an old garbage value that should be overwritten */
   mutt_str_replace(&h->hist[h->last], str);
 }
+
+static const char *history_format_str(char *dest, size_t destlen, size_t col, int cols,
+                                      char op, const char *src, const char *fmt,
+                                      const char *ifstring, const char *elsestring,
+                                      unsigned long data, enum FormatFlag flags)
+{
+  char *match = (char *) data;
+
+  switch (op)
+  {
+    case 's':
+      mutt_format_s(dest, destlen, fmt, match);
+      break;
+  }
+
+  return (src);
+}
+
+static void history_entry(char *s, size_t slen, struct Menu *m, int num)
+{
+  char *entry = ((char **) m->data)[num];
+
+  mutt_expando_format(s, slen, 0, MuttIndexWindow->cols, "%s", history_format_str,
+                      (unsigned long) entry, MUTT_FORMAT_ARROWCURSOR);
+}
+
+static void history_menu(char *buf, size_t buflen, char **matches, int match_count)
+{
+  struct Menu *menu;
+  int done = 0;
+  char helpstr[LONG_STRING];
+  char title[STRING];
+
+  snprintf(title, sizeof(title), _("History '%s'"), buf);
+
+  menu = mutt_new_menu(MENU_GENERIC);
+  menu->make_entry = history_entry;
+  menu->title = title;
+  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_GENERIC, HistoryHelp);
+  mutt_push_current_menu(menu);
+
+  menu->max = match_count;
+  menu->data = matches;
+
+  while (!done)
+  {
+    switch (mutt_menu_loop(menu))
+    {
+      case OP_GENERIC_SELECT_ENTRY:
+        mutt_str_strfcpy(buf, matches[menu->current], buflen);
+        /* fall through */
+
+      case OP_EXIT:
+        done = 1;
+        break;
+    }
+  }
+
+  mutt_pop_current_menu(menu);
+  mutt_menu_destroy(&menu);
+}
+
+static int search_history(char *search_buf, enum HistoryClass hclass, char **matches)
+{
+  struct History *h = get_history(hclass);
+  int match_count = 0, cur;
+
+  if ((History == 0) || !h)
+    return 0;
+
+  cur = h->last;
+  do
+  {
+    cur--;
+    if (cur < 0)
+      cur = History;
+    if (cur == h->last)
+      break;
+    if (mutt_str_stristr(h->hist[cur], search_buf))
+      matches[match_count++] = h->hist[cur];
+  } while (match_count < History);
+
+  return match_count;
+}
+
+void mutt_history_complete(char *buf, size_t buflen, enum HistoryClass hclass)
+{
+  char **matches;
+  int match_count;
+
+  matches = mutt_mem_calloc(History, sizeof(char *));
+  match_count = search_history(buf, hclass, matches);
+  if (match_count)
+  {
+    if (match_count == 1)
+      mutt_str_strfcpy(buf, matches[0], buflen);
+    else
+      history_menu(buf, buflen, matches, match_count);
+  }
+  FREE(&matches);
+}
index 5d08282e40ec2f9f029027080d446a19a095e4ef..0928e35da6c6c3757d6c4c5e30b3863648133b17 100644 (file)
--- a/history.h
+++ b/history.h
@@ -54,5 +54,6 @@ char *mutt_hist_prev(enum HistoryClass hclass);
 void  mutt_hist_read_file(void);
 void  mutt_hist_reset_state(enum HistoryClass hclass);
 void  mutt_hist_save_scratch(enum HistoryClass hclass, const char *str);
+void  mutt_history_complete(char *buf, size_t buflen, enum HistoryClass hclass);
 
 #endif /* _MUTT_HISTORY_H */
index 5dab7238b028977e86c11afa23ed23c0badedf56..e1bc9cfb86314f8b957907ff6599766f50ce89a2 100644 (file)
--- a/opcodes.h
+++ b/opcodes.h
   _fmt(OP_EDITOR_FORWARD_WORD,            N_("move the cursor to the end of the word")) \
   _fmt(OP_EDITOR_HISTORY_DOWN,            N_("scroll down through the history list")) \
   _fmt(OP_EDITOR_HISTORY_UP,              N_("scroll up through the history list")) \
+  _fmt(OP_EDITOR_HISTORY_SEARCH,          N_("search through the history list")) \
   _fmt(OP_EDITOR_KILL_EOL,                N_("delete chars from cursor to end of line")) \
   _fmt(OP_EDITOR_KILL_EOW,                N_("delete chars from the cursor to the end of the word")) \
   _fmt(OP_EDITOR_KILL_LINE,               N_("delete all chars on the line")) \