]> granicus.if.org Git - mutt/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)
committerKevin McCarthy <kevin@8t8.us>
Sun, 4 Feb 2018 02:08:28 +0000 (18:08 -0800)
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.

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

diff --git a/OPS b/OPS
index cc1bc3bdc6fa9c5103a64c8e87a74e4f11abcf18..f53cd63a69c4c6e72daf88c20bd8277bc2f718b7 100644 (file)
--- a/OPS
+++ b/OPS
@@ -72,6 +72,7 @@ OP_EDITOR_FORWARD_CHAR "move the cursor one character to the right"
 OP_EDITOR_FORWARD_WORD "move the cursor to the end of the word"
 OP_EDITOR_HISTORY_DOWN "scroll down through the history list"
 OP_EDITOR_HISTORY_UP "scroll up through the history list"
+OP_EDITOR_HISTORY_SEARCH "search through the history list"
 OP_EDITOR_KILL_EOL "delete chars from cursor to end of line"
 OP_EDITOR_KILL_EOW "delete chars from the cursor to the end of the word"
 OP_EDITOR_KILL_LINE "delete all chars on the line"
index 30bcdb5f1dc6273462026a1551393c983117ca5b..6c1d64a51f4182589f62daccae2e732c4bc7b4b7 100644 (file)
@@ -557,6 +557,7 @@ descriptions.
 <row><entry>^V</entry><entry><literal>&lt;quote-char&gt;</literal></entry><entry>quote the next typed key</entry></row>
 <row><entry>&lt;Up&gt;</entry><entry><literal>&lt;history-up&gt;</literal></entry><entry>recall previous string from history</entry></row>
 <row><entry>&lt;Down&gt;</entry><entry><literal>&lt;history-down&gt;</literal></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><literal>&lt;backspace&gt;</literal></entry><entry>kill the char in front of the cursor</entry></row>
 <row><entry>Esc u</entry><entry><literal>&lt;upcase-word&gt;</literal></entry><entry>convert word to upper case</entry></row>
 <row><entry>Esc l</entry><entry><literal>&lt;downcase-word&gt;</literal></entry><entry>convert word to lower case</entry></row>
diff --git a/enter.c b/enter.c
index 188cf295d3f478fe9af113d059342f6153f629d3..f1fb746cf0a98473e27f0323098bdd0af199f26e 100644 (file)
--- a/enter.c
+++ b/enter.c
@@ -351,6 +351,15 @@ int _mutt_enter_string (char *buf, size_t buflen, int col,
          redraw = MUTT_REDRAW_INIT;
          break;
 
+        case OP_EDITOR_HISTORY_SEARCH:
+          state->curpos = state->lastchar;
+          my_wcstombs (buf, buflen, state->wbuf, state->curpos);
+          mutt_history_complete (buf, buflen, hclass);
+          replace_part (state, 0, buf);
+          rv = 1;
+          goto bye;
+          break;
+
        case OP_EDITOR_BACKSPACE:
          if (state->curpos == 0)
            BEEP ();
index 1f7ca59266af8bd66d8b98a0a347c509adff0847..2985c6eb4dbfe6fc6dc2801ae0a06cda459b5086 100644 (file)
@@ -447,6 +447,7 @@ const struct binding_t 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 4e00384d3099fe7f71e48c420d17b48f2e3d2614..a4b2b83738e87eeec2f6eafb58f39e693d93fc85 100644 (file)
--- a/history.c
+++ b/history.c
@@ -22,6 +22,7 @@
 
 #include "mutt.h"
 #include "history.h"
+#include "mutt_menu.h"
 
 #include <stdint.h>
 
@@ -70,6 +71,14 @@ struct history
   short last;
 }; 
 
+static const struct mapping_t 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 */
 
 static struct history History[HC_LAST];
@@ -477,3 +486,105 @@ void mutt_history_save_scratch (history_class_t hclass, const char *s)
    * an old garbage value that should be overwritten */
   mutt_str_replace (&h->hist[h->last], s);
 }
+
+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, format_flag 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, MUTTMENU *m, int num)
+{
+  char *entry = ((char **)m->data)[num];
+
+  mutt_FormatString (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)
+{
+  MUTTMENU *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_menuLoop (menu))
+    {
+      case OP_GENERIC_SELECT_ENTRY:
+        strfcpy (buf, matches[menu->current], buflen);
+        /* fall through */
+
+      case OP_EXIT:
+        done = 1;
+        break;
+    }
+  }
+
+  mutt_pop_current_menu (menu);
+  mutt_menuDestroy (&menu);
+}
+
+static int search_history (char *search_buf, history_class_t hclass, char **matches)
+{
+  struct history *h = GET_HISTORY(hclass);
+  int match_count = 0, cur;
+
+  if (!HistSize || !h)
+    return 0;
+
+  cur = h->last;
+  do
+  {
+    cur--;
+    if (cur < 0)
+      cur = HistSize;
+    if (cur == h->last)
+      break;
+    if (mutt_stristr (h->hist[cur], search_buf))
+      matches[match_count++] = h->hist[cur];
+  } while (match_count < HistSize);
+
+  return match_count;
+}
+
+void mutt_history_complete (char *buf, size_t buflen, history_class_t hclass)
+{
+  char **matches;
+  int match_count;
+
+  matches = safe_calloc (HistSize, sizeof (char *));
+  match_count = search_history (buf, hclass, matches);
+  if (match_count)
+  {
+    if (match_count == 1)
+      strfcpy (buf, matches[0], buflen);
+    else
+      history_menu (buf, buflen, matches, match_count);
+  }
+  FREE(&matches);
+}
+
index 994526b630f75e83682bf8364ba127614da5e0de..76860056e72b2e31a6e612ad8ed9e08589401ec2 100644 (file)
--- a/history.h
+++ b/history.h
@@ -44,5 +44,6 @@ char *mutt_history_prev(history_class_t);
 void mutt_reset_history_state (history_class_t);
 int mutt_history_at_scratch (history_class_t);
 void mutt_history_save_scratch (history_class_t, const char *);
+void mutt_history_complete (char *, size_t, history_class_t);
 
 #endif