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);