]> granicus.if.org Git - neomutt/commitdiff
Add $history_remove_dups option to remove dups from history ring.
authorKevin McCarthy <kevin@8t8.us>
Sat, 13 May 2017 01:31:36 +0000 (18:31 -0700)
committerRichard Russon <rich@flatcap.org>
Thu, 18 May 2017 13:34:14 +0000 (14:34 +0100)
When set, duplicate entries will be removed from the history ring when
a new entry is added.  The duplicate removal rearranges the history
ring such that created empty slots are right after the "last" position
in the ring, preserving the most history.

Rewrite the next/prev functions to take into account that blank slots can
now be in the middle of the array.

doc/manual.xml.head
history.c
init.h
options.h

index 39658c0f8093412d5ab2d4ab7511b389aa9baf5b..e4108359bb31e9f8cd0801346790362ca50046b8 100644 (file)
@@ -1394,10 +1394,12 @@ color sidebar_divider   color8  default
           </listitem>
         </itemizedlist>
         <para>Mutt automatically filters out consecutively repeated items from
-        the history. It also mimics the behavior of some shells by ignoring
-        items starting with a space. The latter feature can be useful in macros
-        to not clobber the history's valuable entries with unwanted
-        entries.</para>
+        the history. If
+        <link linkend="history-remove-dups">$history_remove_dups</link>is set,
+        all repeated items are removed from the history. It also mimics the
+        behavior of some shells by ignoring items starting with a space. The
+        latter feature can be useful in macros to not clobber the history's
+        valuable entries with unwanted entries.</para>
       </sect2>
     </sect1>
 
index 11aaa92ab0be1860c8e40009c7121fc1b44bdd09..12c09f2127b2bb24e567260306455881f360bafa 100644 (file)
--- a/history.c
+++ b/history.c
 #include "lib.h"
 #include "protos.h"
 
+/* This history ring grows from 0..HistSize, with last marking the
+ * where new entries go:
+ *         0        the oldest entry in the ring
+ *         1        entry
+ *         ...
+ *         x-1      most recently entered text
+ *  last-> x        NULL  (this will be overwritten next)
+ *         x+1      NULL
+ *         ...
+ *         HistSize NULL
+ *
+ * Once the array fills up, it is used as a ring.  last points where a new
+ * entry will go.  Older entries are "up", and wrap around:
+ *         0        entry
+ *         1        entry
+ *         ...
+ *         y-1      most recently entered text
+ *  last-> y        entry (this will be overwritten next)
+ *         y+1      the oldest entry in the ring
+ *         ...
+ *         HistSize entry
+ *
+ * When $history_remove_dups is set, duplicate entries are scanned and removed
+ * each time a new entry is added.  In order to preserve the history ring size,
+ * entries 0..last are compacted up.  Entries last+1..HistSize are
+ * compacted down:
+ *         0        entry
+ *         1        entry
+ *         ...
+ *         z-1      most recently entered text
+ *  last-> z        entry (this will be overwritten next)
+ *         z+1      NULL
+ *         z+2      NULL
+ *         ...
+ *                  the oldest entry in the ring
+ *                  next oldest entry
+ *         HistSize entry
+ */
 struct history
 {
   char **hist;
@@ -208,6 +246,51 @@ static void save_history(history_class_t hclass, const char *s)
   }
 }
 
+/* When removing dups, we want the created "blanks" to be right below the
+ * resulting h->last position.  See the comment section above 'struct history'.
+ */
+static void remove_history_dups(history_class_t hclass, const char *s)
+{
+  int source, dest, old_last;
+  struct history *h = GET_HISTORY(hclass);
+
+  if (!HistSize || !h)
+    return; /* disabled */
+
+  /* Remove dups from 0..last-1 compacting up. */
+  source = dest = 0;
+  while (source < h->last)
+  {
+    if (!mutt_strcmp(h->hist[source], s))
+      FREE(&h->hist[source++]);
+    else
+      h->hist[dest++] = h->hist[source++];
+  }
+
+  /* Move 'last' entry up. */
+  h->hist[dest] = h->hist[source];
+  old_last = h->last;
+  h->last = dest;
+
+  /* Fill in moved entries with NULL */
+  while (source > h->last)
+    h->hist[source--] = NULL;
+
+  /* Remove dups from last+1 .. HistSize compacting down. */
+  source = dest = HistSize;
+  while (source > old_last)
+  {
+    if (!mutt_strcmp(h->hist[source], s))
+      FREE(&h->hist[source--]);
+    else
+      h->hist[dest--] = h->hist[source--];
+  }
+
+  /* Fill in moved entries with NULL */
+  while (dest > old_last)
+    h->hist[dest--] = NULL;
+}
+
 void mutt_init_history(void)
 {
   history_class_t hclass;
@@ -241,6 +324,8 @@ void mutt_history_add(history_class_t hclass, const char *s, int save)
      */
     if (*s != ' ' && (!h->hist[prev] || (mutt_strcmp(h->hist[prev], s) != 0)))
     {
+      if (option(OPTHISTREMOVEDUPS))
+        remove_history_dups(hclass, s);
       if (save && SaveHist)
         save_history(hclass, s);
       mutt_str_replace(&h->hist[h->last++], s);
@@ -259,13 +344,17 @@ char *mutt_history_next(history_class_t hclass)
   if (!HistSize || !h)
     return ""; /* disabled */
 
-  next = h->cur + 1;
-  if (next > HistSize)
-    next = 0;
-  if (h->hist[next] || (next == h->last))
-    h->cur = next;
-  else
-    h->cur = 0;
+  next = h->cur;
+  do
+  {
+    next++;
+    if (next > HistSize)
+      next = 0;
+    if (next == h->last)
+      break;
+  } while (h->hist[next] == NULL);
+
+  h->cur = next;
   return (h->hist[h->cur] ? h->hist[h->cur] : "");
 }
 
@@ -277,15 +366,17 @@ char *mutt_history_prev(history_class_t hclass)
   if (!HistSize || !h)
     return ""; /* disabled */
 
-  prev = h->cur - 1;
-  if (prev < 0)
+  prev = h->cur;
+  do
   {
-    prev = HistSize;
-    while ((prev > 0) && (prev != h->last) && (h->hist[prev] == NULL))
-      prev--;
-  }
-  if (h->hist[prev] || (prev == h->last))
-    h->cur = prev;
+    prev--;
+    if (prev < 0)
+      prev = HistSize;
+    if (prev == h->last)
+      break;
+  } while (h->hist[prev] == NULL);
+
+  h->cur = prev;
   return (h->hist[h->cur] ? h->hist[h->cur] : "");
 }
 
diff --git a/init.h b/init.h
index 29882d4a03539a47475ba9f9617048931d839cdb..d34c2178f25a2af30ba0a06dd00f6655bf697181 100644 (file)
--- a/init.h
+++ b/init.h
@@ -1214,6 +1214,12 @@ struct option_t MuttVars[] = {
   ** .pp
   ** The file in which Mutt will save its history.
   */
+  { "history_remove_dups", DT_BOOL, R_NONE, OPTHISTREMOVEDUPS, 0 },
+  /*
+  ** .pp
+  ** When \fIset\fP, all of the string history will be scanned for duplicates
+  ** when a new entry is added.
+  */
   { "honor_disposition", DT_BOOL, R_NONE, OPTHONORDISP, 0 },
   /*
   ** .pp
index cff3bb63df817f076f14a616c3a613a12eb04cff..bf4e769dbca6786cf5d6530b1be4617123e22fb1 100644 (file)
--- a/options.h
+++ b/options.h
@@ -72,6 +72,7 @@ enum
   OPTHIDETHREADSUBJECT,
   OPTHIDETOPLIMITED,
   OPTHIDETOPMISSING,
+  OPTHISTREMOVEDUPS,
   OPTHONORDISP,
   OPTIGNORELWS,
   OPTIGNORELISTREPLYTO,