diff -Naurd mutt-cvs/curs_lib.c mutt/curs_lib.c
--- mutt-cvs/curs_lib.c	2005-10-07 00:08:24.000000000 +0200
+++ mutt/curs_lib.c	2005-12-04 02:23:49.000000000 +0100
@@ -130,6 +130,7 @@
     mutt_refresh ();
     getyx (stdscr, y, x);
     ret = _mutt_enter_string (buf, buflen, y, x, complete, multiple, files, numfiles, es);
+    complete &= ~(M_CLEAR);
   }
   while (ret == 1);
   CLEARLINE (LINES-1);
diff -Naurd mutt-cvs/curs_main.c mutt/curs_main.c
--- mutt-cvs/curs_main.c	2005-12-04 01:36:40.000000000 +0100
+++ mutt/curs_main.c	2005-12-04 02:24:36.000000000 +0100
@@ -811,7 +811,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
@@ -866,10 +866,8 @@
 	  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
 	  if (Context->msgcount && (Sort & SORT_MASK) == SORT_THREADS)
 	    mutt_draw_tree (Context);
-	  menu->redraw = REDRAW_FULL;
 	}
-        if (Context->pattern)
-	  mutt_message _("To view all messages, limit to \"all\".");
+	menu->redraw = REDRAW_FULL;
 	break;	  
 
       case OP_QUIT:
@@ -917,6 +915,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:
@@ -966,7 +966,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:
@@ -979,16 +979,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 -Naurd mutt-cvs/enter.c mutt/enter.c
--- mutt-cvs/enter.c	2005-09-18 01:02:03.000000000 +0200
+++ mutt/enter.c	2005-12-04 02:23:49.000000000 +0100
@@ -568,6 +568,17 @@
 	      BEEP (); /* let the user know that nothing matched */
 	    replace_part (state, 0, buf);
 	  }
+	  else if (flags & M_PATTERN)
+	  {
+	    if ((i = state->curpos) && state->wbuf[i - 1] == '~')
+	    {
+	      if (mutt_ask_pattern (buf, buflen))
+		replace_part (state, i, buf);
+	      rv = 1;
+	      goto bye;
+	    }
+	    goto self_insert;
+	  }
 	  else
 	    goto self_insert;
 	  break;
diff -Naurd mutt-cvs/pattern.c mutt/pattern.c
--- mutt-cvs/pattern.c	2005-12-04 01:36:41.000000000 +0100
+++ mutt/pattern.c	2005-12-04 02:30:15.000000000 +0100
@@ -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>
@@ -45,57 +47,103 @@
 static int eat_range (pattern_t *pat, BUFFER *, BUFFER *);
 static int patmatch (const pattern_t *pat, const char *buf);
 
+#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_LIST,		0,		NULL },
-  { 'L', M_ADDRESS,		0,		eat_regexp },
-  { '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_DATE_RECEIVED,	0,		eat_date },
-  { 'R', M_READ,		0,		NULL },
-  { 's', M_SUBJECT,		0,		eat_regexp },
-  { 'S', M_SUPERSEDED,		0,		NULL },
-  { 't', M_TO,			0,		eat_regexp },
-  { 'T', M_TAG,			0,		NULL },
-  { 'u', M_SUBSCRIBED_LIST,	0,		NULL },
-  { 'U', M_UNREAD,		0,		NULL },
-  { 'v', M_COLLAPSED,		0,		NULL },
-  { 'V', M_CRYPT_VERIFIED,	0,		NULL },
-  { 'x', M_REFERENCE,		0,		eat_regexp },
-  { 'X', M_MIMEATTACH,		0,		eat_range },
-  { '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_LIST,		0,		0,
+	N_("messages addressed to known mailing lists") },
+  { 'L', M_ADDRESS,		0,		EAT_REGEXP,
+	N_("messages whose From/Sender/To/CC matches EXPR") },
+  { '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_DATE_RECEIVED,	0,		EAT_DATE,
+	N_("messages received in DATERANGE") },
+  { 'R', M_READ,		0,		0,
+	N_("already read messages") },
+  { 's', M_SUBJECT,		0,		EAT_REGEXP,
+	N_("messages whose Subject header matches EXPR") },
+  { 'S', M_SUPERSEDED,		0,		0,
+	N_("superseded messages") },
+  { 't', M_TO,			0,		EAT_REGEXP,
+	N_("messages whose To header matches EXPR") },
+  { 'T', M_TAG,			0,		0,
+	N_("tagged messages") },
+  { 'u', M_SUBSCRIBED_LIST,	0,		0,
+	N_("messages addressed to subscribed mailing lists") },
+  { '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") },
+  { 'X', M_MIMEATTACH,		0,		EAT_RANGE,
+ 	N_("messages with RANGE attachments") },
+  { '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 }
 };
 
@@ -252,7 +300,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;
@@ -298,7 +346,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;
@@ -854,13 +902,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;
@@ -1203,7 +1258,11 @@
 
   strfcpy (buf, NONULL (Context->pattern), sizeof (buf));
   if (mutt_get_field (prompt, buf, sizeof (buf), M_PATTERN | M_CLEAR) != 0 || !buf[0])
+  {
+    if (op == M_LIMIT && Context->pattern)
+      mutt_message _("To view all messages, limit to \"all\".");
     return (-1);
+  }
 
   mutt_message _("Compiling search pattern...");
   
@@ -1420,3 +1479,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 -Naurd mutt-cvs/protos.h mutt/protos.h
--- mutt-cvs/protos.h	2005-10-22 20:50:07.000000000 +0200
+++ mutt/protos.h	2005-12-04 02:23:49.000000000 +0100
@@ -258,6 +258,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);
