<<< Date Index >>>     <<< Thread Index >>>

Re: Listing patterns in the help screen



On Mon, Mar 14, 2005 at 04:32:36AM +0100, Benjamin Pflugmann wrote:
> While I am in the line editor that doesn't work (help doesn't either),
> and that's when it's most useful to me. What about a patch that binds
> the list of patterns to a key when you are typing in a limit, tag
> match or similar (obviously binding it to '?' isn't a good idea).
> 
> That wouldn't make the usual help list any less useful, as it would
> display a help where none was available before.

Good.
Here is a beta-quality patch. (I modified the patch
after the last time I built mutt, so this is untested.
But this should apply and build, I think.)

Mutt will show you the list of patterns when you type <tab>
(the <complete> function) after '~' on a pattern prompt
(e.g. <search> or <limit>). You can choose one of them in
the menu. It's very useful. Thanks for the idea!

-- 
tamo
diff -ru mutt-1.5.8/curs_main.c mutt-1.5.8.modified/curs_main.c
--- mutt-1.5.8/curs_main.c      2005-02-13 04:22:15.000000000 +0900
+++ mutt-1.5.8.modified/curs_main.c     2005-03-15 00:08:21.000000000 +0900
@@ -802,7 +802,7 @@
 
        CHECK_ATTACH;
        mutt_pattern_func (M_DELETE, _("Delete messages matching: "));
-       menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+       menu->redraw = REDRAW_FULL;
        break;
 
 #ifdef USE_POP
@@ -857,8 +857,8 @@
          menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
          if ((Sort & SORT_MASK) == SORT_THREADS)
            mutt_draw_tree (Context);
-         menu->redraw = REDRAW_FULL;
        }
+       menu->redraw = REDRAW_FULL;
        break;    
 
       case OP_QUIT:
@@ -906,6 +906,8 @@
          menu->current = menu->oldcurrent;
        else
          menu->redraw = REDRAW_MOTION;
+       if (op == OP_SEARCH || op == OP_SEARCH_REVERSE)
+         menu->redraw = REDRAW_FULL;
        break;
 
       case OP_SORT:
@@ -950,7 +952,7 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        mutt_pattern_func (M_TAG, _("Tag messages matching: "));
-       menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+       menu->redraw = REDRAW_FULL;
        break;
 
       case OP_MAIN_UNDELETE_PATTERN:
@@ -963,16 +965,16 @@
 CHECK_IMAP_ACL(IMAP_ACL_DELETE);
 #endif
 
-       if (mutt_pattern_func (M_UNDELETE, _("Undelete messages matching: ")) 
== 0)
-         menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+       mutt_pattern_func (M_UNDELETE, _("Undelete messages matching: "));
+       menu->redraw = REDRAW_FULL;
        break;
 
       case OP_MAIN_UNTAG_PATTERN:
 
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
-       if (mutt_pattern_func (M_UNTAG, _("Untag messages matching: ")) == 0)
-         menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+       mutt_pattern_func (M_UNTAG, _("Untag messages matching: "));
+       menu->redraw = REDRAW_FULL;
        break;
 
        /* --------------------------------------------------------------------
diff -ru mutt-1.5.8/enter.c mutt-1.5.8.modified/enter.c
--- mutt-1.5.8/enter.c  2005-02-04 03:47:52.000000000 +0900
+++ mutt-1.5.8.modified/enter.c 2005-03-14 23:27:49.000000000 +0900
@@ -549,6 +549,20 @@
              BEEP (); /* let the user know that nothing matched */
            replace_part (state, 0, buf);
          }
+         else if (flags & M_PATTERN)
+         {
+           my_wcstombs (buf, buflen, state->wbuf, state->curpos);
+           i = strlen (buf);
+           if (i && buf[i - 1] == '~')
+           {
+             if (mutt_ask_pattern (buf, buflen))
+               replace_part (state, i, buf);
+             rv = 1;
+             goto bye;
+           }
+           else
+             goto self_insert;
+         }
          else
            goto self_insert;
          break;
diff -ru mutt-1.5.8/pattern.c mutt-1.5.8.modified/pattern.c
--- mutt-1.5.8/pattern.c        2005-02-09 18:07:45.000000000 +0900
+++ mutt-1.5.8.modified/pattern.c       2005-03-15 00:13:34.000000000 +0900
@@ -25,6 +25,8 @@
 #include "keymap.h"
 #include "mailbox.h"
 #include "copy.h"
+#include "mutt_menu.h"
+#include "mutt_curses.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -39,55 +41,99 @@
 static int eat_date (pattern_t *pat, BUFFER *, BUFFER *);
 static int eat_range (pattern_t *pat, BUFFER *, BUFFER *);
 
+#define EAT_REGEXP     1
+#define EAT_DATE       2
+#define EAT_RANGE      3
 struct pattern_flags
 {
   int tag;     /* character used to represent this op */
   int op;      /* operation to perform */
   int class;
-  int (*eat_arg) (pattern_t *, BUFFER *, BUFFER *);
+  int eat_arg;
+  char *desc;
 }
 Flags[] =
 {
-  { 'A', M_ALL,                        0,              NULL },
-  { 'b', M_BODY,               M_FULL_MSG,     eat_regexp },
-  { 'B', M_WHOLE_MSG,          M_FULL_MSG,     eat_regexp },
-  { 'c', M_CC,                 0,              eat_regexp },
-  { 'C', M_RECIPIENT,          0,              eat_regexp },
-  { 'd', M_DATE,               0,              eat_date },
-  { 'D', M_DELETED,            0,              NULL },
-  { 'e', M_SENDER,             0,              eat_regexp },
-  { 'E', M_EXPIRED,            0,              NULL },
-  { 'f', M_FROM,               0,              eat_regexp },
-  { 'F', M_FLAG,               0,              NULL },
-  { 'g', M_CRYPT_SIGN,                 0,              NULL },
-  { 'G', M_CRYPT_ENCRYPT,      0,              NULL },
-  { 'h', M_HEADER,             M_FULL_MSG,     eat_regexp },
-  { 'H', M_HORMEL,             0,              eat_regexp },
-  { 'i', M_ID,                 0,              eat_regexp },
-  { 'k', M_PGP_KEY,            0,              NULL },
-  { 'L', M_ADDRESS,            0,              eat_regexp },
-  { 'l', M_LIST,               0,              NULL },
-  { 'm', M_MESSAGE,            0,              eat_range },
-  { 'n', M_SCORE,              0,              eat_range },
-  { 'N', M_NEW,                        0,              NULL },
-  { 'O', M_OLD,                        0,              NULL },
-  { 'p', M_PERSONAL_RECIP,     0,              NULL },
-  { 'P', M_PERSONAL_FROM,      0,              NULL },
-  { 'Q', M_REPLIED,            0,              NULL },
-  { 'R', M_READ,               0,              NULL },
-  { 'r', M_DATE_RECEIVED,      0,              eat_date },
-  { 's', M_SUBJECT,            0,              eat_regexp },
-  { 'S', M_SUPERSEDED,         0,              NULL },
-  { 'T', M_TAG,                        0,              NULL },
-  { 't', M_TO,                 0,              eat_regexp },
-  { 'U', M_UNREAD,             0,              NULL },
-  { 'v', M_COLLAPSED,          0,              NULL },
-  { 'V', M_CRYPT_VERIFIED,      0,              NULL },
-  { 'x', M_REFERENCE,          0,              eat_regexp },
-  { 'y', M_XLABEL,             0,              eat_regexp },
-  { 'z', M_SIZE,               0,              eat_range },
-  { '=', M_DUPLICATED,         0,              NULL },
-  { '$', M_UNREFERENCED,       0,              NULL },
+  { 'A', M_ALL,                        0,              0,
+       N_("all messages") },
+  { 'b', M_BODY,               M_FULL_MSG,     EAT_REGEXP,
+       N_("messages whose body matches EXPR") },
+  { 'B', M_WHOLE_MSG,          M_FULL_MSG,     EAT_REGEXP,
+       N_("messages whose body or headers match EXPR") },
+  { 'c', M_CC,                 0,              EAT_REGEXP,
+       N_("messages whose CC header matches EXPR") },
+  { 'C', M_RECIPIENT,          0,              EAT_REGEXP,
+       N_("messages whose recipient matches EXPR") },
+  { 'd', M_DATE,               0,              EAT_DATE,
+       N_("messages sent in DATERANGE") },
+  { 'D', M_DELETED,            0,              0,
+       N_("deleted messages") },
+  { 'e', M_SENDER,             0,              EAT_REGEXP,
+       N_("messages whose Sender header matches EXPR") },
+  { 'E', M_EXPIRED,            0,              0,
+       N_("expired messages") },
+  { 'f', M_FROM,               0,              EAT_REGEXP,
+       N_("messages whose From header matches EXPR") },
+  { 'F', M_FLAG,               0,              0,
+       N_("flagged messages") },
+  { 'g', M_CRYPT_SIGN,                 0,              0,
+       N_("cryptographically signed messages") },
+  { 'G', M_CRYPT_ENCRYPT,      0,              0,
+       N_("cryptographically encrypted messages") },
+  { 'h', M_HEADER,             M_FULL_MSG,     EAT_REGEXP,
+       N_("messages whose header matches EXPR") },
+  { 'H', M_HORMEL,             0,              EAT_REGEXP,
+       N_("messages whose spam tag matches EXPR") },
+  { 'i', M_ID,                 0,              EAT_REGEXP,
+       N_("messages whose Message-ID matches EXPR") },
+  { 'k', M_PGP_KEY,            0,              0,
+       N_("messages which contain PGP key") },
+  { 'L', M_ADDRESS,            0,              EAT_REGEXP,
+       N_("messages whose From/Sender/To/CC matches EXPR") },
+  { 'l', M_LIST,               0,              0,
+       N_("messages addressed to known mailing lists") },
+  { 'm', M_MESSAGE,            0,              EAT_RANGE,
+       N_("messages whose number is in RANGE") },
+  { 'n', M_SCORE,              0,              EAT_RANGE,
+       N_("messages whose score is in RANGE") },
+  { 'N', M_NEW,                        0,              0,
+       N_("new messages") },
+  { 'O', M_OLD,                        0,              0,
+       N_("old messages") },
+  { 'p', M_PERSONAL_RECIP,     0,              0,
+       N_("messages addressed to you") },
+  { 'P', M_PERSONAL_FROM,      0,              0,
+       N_("messages from you") },
+  { 'Q', M_REPLIED,            0,              0,
+       N_("messages which have been replied to") },
+  { 'R', M_READ,               0,              0,
+       N_("already read messages") },
+  { 'r', M_DATE_RECEIVED,      0,              EAT_DATE,
+       N_("messages received in DATERANGE") },
+  { 's', M_SUBJECT,            0,              EAT_REGEXP,
+       N_("messages whose Subject header matches EXPR") },
+  { 'S', M_SUPERSEDED,         0,              0,
+       N_("superseded messages") },
+  { 'T', M_TAG,                        0,              0,
+       N_("tagged messages") },
+  { 't', M_TO,                 0,              EAT_REGEXP,
+       N_("messages whose To header matches EXPR") },
+  { 'U', M_UNREAD,             0,              0,
+       N_("unread messages") },
+  { 'v', M_COLLAPSED,          0,              0,
+       N_("messages in collapsed threads") },
+  { 'V', M_CRYPT_VERIFIED,     0,              0,
+       N_("cryptographically verified messages") },
+  { 'x', M_REFERENCE,          0,              EAT_REGEXP,
+       N_("messages whose References header matches EXPR") },
+  { 'y', M_XLABEL,             0,              EAT_REGEXP,
+       N_("messages whose X-Label header matches EXPR") },
+  { 'z', M_SIZE,               0,              EAT_RANGE,
+       N_("messages whose size is in RANGE") },
+  { '=', M_DUPLICATED,         0,              0,
+       N_("duplicated messages") },
+  { '$', M_UNREFERENCED,       0,              0,
+       N_("unreferenced messages") },
   { 0 }
 };
 
@@ -232,7 +278,7 @@
   return match;
 }
 
-int eat_regexp (pattern_t *pat, BUFFER *s, BUFFER *err)
+static int eat_regexp (pattern_t *pat, BUFFER *s, BUFFER *err)
 {
   BUFFER buf;
   int r;
@@ -257,7 +303,7 @@
   return 0;
 }
 
-int eat_range (pattern_t *pat, BUFFER *s, BUFFER *err)
+static int eat_range (pattern_t *pat, BUFFER *s, BUFFER *err)
 {
   char *tmp;
   int do_exclusive = 0;
@@ -802,13 +848,20 @@
 
        if (entry->eat_arg)
        {
+         int eatrv = 0;
          if (!*ps.dptr)
          {
            snprintf (err->data, err->dsize, _("missing parameter"));
            mutt_pattern_free (&curlist);
            return NULL;
          }
-         if (entry->eat_arg (tmp, &ps, err) == -1)
+         switch (entry->eat_arg)
+         {
+           case EAT_REGEXP: eatrv = eat_regexp (tmp, &ps, err); break;
+           case EAT_DATE: eatrv = eat_date (tmp, &ps, err); break;
+           case EAT_RANGE: eatrv = eat_range (tmp, &ps, err); break;
+         }
+         if (eatrv == -1)
          {
            mutt_pattern_free (&curlist);
            return NULL;
@@ -1340,3 +1393,134 @@
   mutt_error _("Not found.");
   return (-1);
 }
+
+static void pattern_entry (char *s, size_t l, MUTTMENU * menu, int num)
+{
+  LIST **PatTable = (LIST **) menu->data;
+
+  mutt_format_string (s, l, 0, COLS, 0, ' ', PatTable[num]->data,
+                    mutt_strlen (PatTable[num]->data), 0);
+}
+
+static char pattern_menu (LIST *pats)
+{
+  int patmax = 0;
+  LIST **PatTable = NULL;
+  MUTTMENU *menu;
+  int i, done = 0;
+  char helpstr[SHORT_STRING], buf[LONG_STRING];
+  LIST *pat;
+  char rv = 0;
+
+  for (i = 0, pat = pats; pat; pat = pat->next)
+  {
+      if (i == patmax)
+      {
+       patmax += 5;
+       safe_realloc (&PatTable, sizeof (LIST *) * patmax);
+      }
+      PatTable[i++] = pat;
+  }
+
+  helpstr[0] = 0;
+  mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_GENERIC, OP_EXIT);
+  safe_strcat (helpstr, sizeof (helpstr), buf);
+  mutt_make_help (buf, sizeof (buf), _("Select  "), MENU_GENERIC,
+                 OP_GENERIC_SELECT_ENTRY);
+  safe_strcat (helpstr, sizeof (helpstr), buf);
+  mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
+  safe_strcat (helpstr, sizeof (helpstr), buf);
+
+  menu = mutt_new_menu ();
+  menu->max = i;
+  menu->make_entry = pattern_entry;
+  menu->menu = MENU_GENERIC;
+  menu->help = helpstr;
+  menu->data = PatTable;
+  menu->title = _("Patterns");
+
+  mutt_clear_error ();
+
+  while (!done)
+  {
+    switch (mutt_menuLoop (menu))
+    {
+    case OP_GENERIC_SELECT_ENTRY:
+      rv = PatTable[menu->current]->data[1];
+      done = 1;
+      break;
+
+    case OP_EXIT:
+      rv = 0;
+      done = 1;
+      break;
+    }
+  }
+
+  mutt_menuDestroy (&menu);
+  FREE (&PatTable);
+
+  set_option (OPTNEEDREDRAW);
+
+  return (rv);
+}
+
+static LIST *list_patterns ()
+{
+  LIST *first = NULL, *last = NULL, *cur = NULL;
+  int i;
+
+  for (i = 0; Flags[i].tag; i++)
+  {
+    char buf[LONG_STRING];
+    switch (Flags[i].eat_arg)
+    {
+    case EAT_REGEXP:
+      snprintf (buf, sizeof (buf), _("~%c EXPR       %s"),
+                (char) Flags[i].tag, _(Flags[i].desc));
+      break;
+    case EAT_RANGE:
+      snprintf (buf, sizeof (buf), _("~%c RANGE      %s"),
+                (char) Flags[i].tag, _(Flags[i].desc));
+      break;
+    case EAT_DATE:
+      snprintf (buf, sizeof (buf), _("~%c DATERANGE  %s"),
+                (char) Flags[i].tag, _(Flags[i].desc));
+      break;
+    default:
+      snprintf (buf, sizeof (buf), _("~%c            %s"),
+                (char) Flags[i].tag, _(Flags[i].desc));
+    }
+    cur = (LIST *) safe_calloc (1, sizeof (LIST));
+    cur->data = safe_strdup (buf);
+    if (!first)
+      first = cur;
+    if (last)
+      last->next = cur;
+    last = cur;
+  }
+  if (cur)
+    cur->next = NULL;
+  return (first);
+}
+
+int mutt_ask_pattern (char *buf, size_t buflen)
+{
+  char c;
+  LIST *l;
+  int rv = 0;
+
+  if (!buf || buflen < 3)
+    return 0;
+  if ((l = list_patterns()))
+  {
+    if ((c = pattern_menu (l)))
+    {
+      sprintf (buf, "%c ", c); /* __SPRINTF_CHECKED__ */
+      rv = 1;
+    }
+    mutt_free_list (&l);
+  }
+  return rv;
+}
+
diff -ru mutt-1.5.8/protos.h mutt-1.5.8.modified/protos.h
--- mutt-1.5.8/protos.h 2005-02-01 17:59:02.000000000 +0900
+++ mutt-1.5.8.modified/protos.h        2005-03-14 22:29:36.000000000 +0900
@@ -256,6 +256,7 @@
 int mutt_addwch (wchar_t);
 int mutt_alias_complete (char *, size_t);
 int mutt_alloc_color (int fg, int bg);
+int mutt_ask_pattern (char *, size_t);
 int mutt_any_key_to_continue (const char *);
 int mutt_buffy_check (int);
 int mutt_buffy_notify (void);