# HG changeset patch
# User David Champion <[email protected]>
# Date 1385592820 21600
#      Wed Nov 27 16:53:40 2013 -0600
# Node ID 44c56715ef8bb953bfda7a271a2c0544b55941cc
# Parent  3306cb186f49e83edf15aac91c51f4c6131ef8fe
add `unbind' and `unmacro' commands

This is a refresh and update of a very old (~2001) patch providing
unbind and unmacro commands.  The topic has been through a lot of
controversy.  Originally the unbind patch was simply a shortcut to
binding keys to noop -- unless you unbound *, in which case they
were truly unbound.

The distinction is subtle, and concerns what the correct fallback
behavior is after a key is unbound.  Consider the following steps, run
with 'mutt -F/dev/null -f/dev/null'.

1. pressing 't' in the index gives a 'There are no messages' response,
   because 't' is unbound in index but bound in generic to <tag-entry>.
2. enter command: bind index t help
3. pressing 't' in the index results in help
4. enter command: unbind index t
5. pressing 't' in the index results in 'Key is not bound'.  There
   is no fallthrough to the generic menu, because 't' is -really-
   bound to <noop>.

This updated patch now does a true unbind: it removes the mapping from
the key table completely, so that step 5 becomes the same as step 1.

It also adds the capability to use '*' for any bind or macro command.

diff -r 3306cb186f49 -r 44c56715ef8b doc/manual.xml.head
--- a/doc/manual.xml.head       Tue Oct 29 00:11:16 2013 -0700
+++ b/doc/manual.xml.head       Wed Nov 27 16:53:40 2013 -0600
@@ -2158,7 +2158,9 @@
 <para>
 <emphasis>map</emphasis> specifies in which menu the binding belongs.
 Multiple maps may be specified by separating them with commas (no
-additional whitespace is allowed). The currently defined maps are:
+additional whitespace is allowed).  A <literal>*</literal> attempts
+to bind in all maps, but beware that not all functions are defined
+for all maps.  The currently defined maps are:
 </para>
 
 <anchor id="maps"/>
@@ -4378,6 +4380,44 @@
 
 </sect1>
 
+<sect1 id="unbind">
+<title>Removing key bindings</title>
+<para>Usage:</para>
+
+<cmdsynopsis>
+<command>unbind</command>
+<arg choice="plain"><replaceable class="parameter">map</replaceable></arg>
+<group choice="req">
+<arg choice="plain"><replaceable class="parameter">key</replaceable></arg>
+<arg choice="plain"><replaceable class="parameter">*</replaceable></arg>
+</group>
+</cmdsynopsis>
+
+<para>
+This command removes one or all key bindings from a set of menus.
+As with <literal>bind</literal>, multiple menus may be separated
+by commas, or a <literal>*</literal> can be used to unbind in all
+menus.
+If <literal>key</literal> is <literal>*</literal>, all bindings
+in the specified set of maps are removed.
+</para>
+
+<para>
+To prevent you from hanging yourself, <literal>unbind</literal> will
+always push the <literal>enter-command</literal> function back onto
+the Generic bindings table, bound to the <quote>:</quote> key.)  A set
+of basic <literal>editor</literal> bindings is also added so that the
+<literal>enter-command</literal> prompt is actually usable, and an
+<literal>exit</literal> bindind is added to the <literal>pager</literal>
+map.
+</para>
+
+<para>
+The <literal>bind map *</literal> command will reload default bindings
+for the specified map(s), but it does not re-parse any Muttrc files.
+</para>
+</sect1>
+
 <sect1 id="unhook">
 <title>Removing Hooks</title>
 
@@ -4404,6 +4444,26 @@
 
 </sect1>
 
+<sect1 id="unmacro">
+<title>Removing macros</title>
+<para>Usage:</para>
+
+<cmdsynopsis>
+<command>unmacro</command>
+<arg choice="plain"><replaceable class="parameter">map</replaceable></arg>
+<group choice="req">
+<arg choice="plain"><replaceable class="parameter">key(s)</replaceable></arg>
+<arg choice="plain"><replaceable class="parameter">*</replaceable></arg>
+</group>
+</cmdsynopsis>
+
+<para>
+<literal>Unmacro</literal> is identical to <literal>unbind</literal>,
+except that <literal>unbind</literal> operates only on single-key
+bindings, and <literal>unmacro</literal> operates only on macros.
+</para>
+</sect1>
+
 <sect1 id="formatstrings">
 <title>Format Strings</title>
 
@@ -8470,6 +8530,19 @@
 
 <listitem>
 <cmdsynopsis>
+<command><link linkend="unbind">unbind</link></command>
+<arg choice="plain">
+<replaceable class="parameter">map</replaceable>
+</arg>
+<group choice="req">
+<arg choice="plain"><replaceable class="parameter">key</replaceable></arg>
+<arg choice="plain"><replaceable class="parameter">*</replaceable></arg>
+</group>
+</cmdsynopsis>
+</listitem>
+
+<listitem>
+<cmdsynopsis>
 <command><link linkend="charset-hook">charset-hook</link></command>
 <arg choice="plain">
 <replaceable class="parameter">alias</replaceable>
@@ -8754,6 +8827,19 @@
 
 <listitem>
 <cmdsynopsis>
+<command><link linkend="unmacro">unmacro</link></command>
+<arg choice="plain">
+<replaceable class="parameter">map</replaceable>
+</arg>
+<group choice="req">
+<arg choice="plain"><replaceable class="parameter">key(s)</replaceable></arg>
+<arg choice="plain"><replaceable class="parameter">*</replaceable></arg>
+</group>
+</cmdsynopsis>
+</listitem>
+
+<listitem>
+<cmdsynopsis>
 <command><link linkend="mailboxes">mailboxes</link></command>
 <arg choice="plain">
 <replaceable class="parameter">mailbox</replaceable>
diff -r 3306cb186f49 -r 44c56715ef8b doc/muttrc.man.head
--- a/doc/muttrc.man.head       Tue Oct 29 00:11:16 2013 -0700
+++ b/doc/muttrc.man.head       Wed Nov 27 16:53:40 2013 -0600
@@ -160,11 +160,16 @@
 .BR mailcap (5)
 entry given for the original MIME type.  For instance, you may add
 the \fBapplication/octet-stream\fP MIME type to this list.
-.TP
+.PP
+.nf
 \fBbind\fP \fImap1,map2,...\fP \fIkey\fP \fIfunction\fP
+\fBunbind\fP \fImap1,map2,...\fP [ \fB*\fP | \fIkey\fP ]
+.fi
+.IP
 This command binds the given \fIkey\fP for the given \fImap\fP or maps
 to the given \fIfunction\fP. Multiple maps may be specified by
-separating them with commas (no whitespace is allowed).
+separating them with commas (no whitespace is allowed). An asterisk
+(\fB*\fP) represents all maps.
 .IP
 Valid maps are:
 .BR generic ", " alias ", " attach ", " 
@@ -176,6 +181,17 @@
 For more information on keys and functions, please consult the Mutt
 Manual. Note that the function name is to be specified without
 angle brackets.
+.IP
+The \fBunbind\fP command removes key bindings.  Either the map
+name or the key name may be a wildcard (\fB*\fP).  (To unbind the
+asterisk key itself, use \(lq\fBbind \fImap\fB * noop\fP\(rq.)
+.IP
+To prevent irreversible damage, \fBunbind\fP will always ensure that
+the \fBenter-command\fP function is bound in the \fIgeneric\fP map.
+Similarly, some basic \fIeditor\fP bindings are loaded, and an \fIexit\fP
+function is bound in the \fIpager\fP map.
+\(lq\fBbind \fImap\fB *\fP\(rq will reload all default bindings for
+the specified map(s).
 .TP
 \fBaccount-hook\fP [\fB!\fP]\fIregexp\fP \fIcommand\fP
 This hook is executed whenever you access a remote mailbox. Useful
@@ -214,11 +230,19 @@
 .IP
 When several \fBfolder-hook\fPs match a given mail folder, they are
 executed in the order given in the configuration file.
-.TP
+.PP
+.nf
 \fBmacro\fP \fImap\fP \fIkey\fP \fIsequence\fP [ \fIdescription\fP ]
-This command binds the given \fIsequence\fP of keys to the given
+\fBunmacro\fP [ \fB*\fP | \fImap\fP ] [ \fB*\fP | \fIkey(s)\fP ]
+.fi
+.IP
+The \fBmacro\fP command binds the given \fIsequence\fP of keys to the given
 \fIkey\fP in the given \fImap\fP or maps.  For valid maps, see \fBbind\fP. To
 specify multiple maps, put only a comma between the maps.
+.IP
+\fBunmacro\fP is identical to \fBunbind\fP, except that \fBunbind works
+only for single key bindings, and \fBunmacro\fP works only on macro
+definitions.
 .PP
 .nf
 \fBcolor\fP \fIobject\fP \fIforeground\fP \fIbackground\fP [ \fI regexp\fP ]
diff -r 3306cb186f49 -r 44c56715ef8b init.h
--- a/init.h    Tue Oct 29 00:11:16 2013 -0700
+++ b/init.h    Wed Nov 27 16:53:40 2013 -0600
@@ -3599,10 +3599,12 @@
   { "unalias",         parse_unalias,          0 },
   { "unalternative_order",parse_unlist,                UL 
&AlternativeOrderList },
   { "unauto_view",     parse_unlist,           UL &AutoViewList },
+  { "unbind",          mutt_parse_unbind,      M_UNBIND },
   { "unhdr_order",     parse_unlist,           UL &HeaderOrderList },
   { "unhook",          mutt_parse_unhook,      0 },
   { "unignore",                parse_unignore,         0 },
   { "unlists",         parse_unlists,          0 },
+  { "unmacro",         mutt_parse_unbind,      M_UNMACRO },
   { "unmono",          mutt_parse_unmono,      0 },
   { "unmy_hdr",                parse_unmy_hdr,         0 },
   { "unscore",         mutt_parse_unscore,     0 },
diff -r 3306cb186f49 -r 44c56715ef8b keymap.c
--- a/keymap.c  Tue Oct 29 00:11:16 2013 -0700
+++ b/keymap.c  Wed Nov 27 16:53:40 2013 -0600
@@ -703,119 +703,172 @@
 #endif
 }
 
-void km_init (void)
+void km_init (int menu)
 {
-  memset (Keymaps, 0, sizeof (struct keymap_t *) * MENU_MAX);
+  if (menu == -1)
+    memset (Keymaps, 0, sizeof (struct keymap_t *) * MENU_MAX);
+  else
+    memset (&Keymaps[menu], 0, sizeof (struct keymap_t *));
 
-  create_bindings (OpAttach, MENU_ATTACH);
-  create_bindings (OpBrowser, MENU_FOLDER);
-  create_bindings (OpCompose, MENU_COMPOSE);
-  create_bindings (OpMain, MENU_MAIN);
-  create_bindings (OpPager, MENU_PAGER);
-  create_bindings (OpPost, MENU_POST);
-  create_bindings (OpQuery, MENU_QUERY);
-  create_bindings (OpAlias, MENU_ALIAS);
+  /* attach menu bindings */
+  if (menu == MENU_ATTACH || menu == -1)
+  {
+    create_bindings (OpAttach, MENU_ATTACH);
+    km_bindkey ("<enter>", MENU_ATTACH, OP_VIEW_ATTACH);
+  }
 
+  /* browser menu bindings */
+  if (menu == MENU_FOLDER || menu == -1)
+  {
+    create_bindings (OpBrowser, MENU_FOLDER);
+  }
 
-  if ((WithCrypto & APPLICATION_PGP))
+  /* compose menu bindings */
+  if (menu == MENU_COMPOSE || menu == -1)
+  {
+    create_bindings (OpCompose, MENU_COMPOSE);
+    km_bindkey ("<enter>", MENU_COMPOSE, OP_VIEW_ATTACH);
+
+    /* edit-to (default "t") hides generic tag-entry in Compose menu
+       This will bind tag-entry to  "T" in the Compose menu */
+    km_bindkey ("T", MENU_COMPOSE, OP_TAG);
+  }
+
+  /* main menu bindings */
+  if (menu == MENU_MAIN || menu == -1)
+  {
+    create_bindings (OpMain, MENU_MAIN);
+    km_bindkey (" ", MENU_MAIN, OP_DISPLAY_MESSAGE);
+    km_bindkey ("<up>", MENU_MAIN, OP_MAIN_PREV_UNDELETED);
+    km_bindkey ("<down>", MENU_MAIN, OP_MAIN_NEXT_UNDELETED);
+    km_bindkey ("J", MENU_MAIN, OP_NEXT_ENTRY);
+    km_bindkey ("K", MENU_MAIN, OP_PREV_ENTRY);
+    km_bindkey ("x", MENU_MAIN, OP_EXIT);
+    km_bindkey ("<enter>", MENU_MAIN, OP_DISPLAY_MESSAGE);
+  }
+
+  /* pager menu bindings */
+  if (menu == MENU_PAGER || menu == -1)
+  {
+    create_bindings (OpPager, MENU_PAGER);
+    km_bindkey ("x", MENU_PAGER, OP_EXIT);
+    km_bindkey ("i", MENU_PAGER, OP_EXIT);
+    km_bindkey ("<backspace>", MENU_PAGER, OP_PREV_LINE);
+    km_bindkey ("<pagedown>", MENU_PAGER, OP_NEXT_PAGE);
+    km_bindkey ("<pageup>", MENU_PAGER, OP_PREV_PAGE);
+    km_bindkey ("<up>", MENU_PAGER, OP_MAIN_PREV_UNDELETED);
+    km_bindkey ("<right>", MENU_PAGER, OP_MAIN_NEXT_UNDELETED);
+    km_bindkey ("<down>", MENU_PAGER, OP_MAIN_NEXT_UNDELETED);
+    km_bindkey ("<left>", MENU_PAGER, OP_MAIN_PREV_UNDELETED);
+    km_bindkey ("<home>", MENU_PAGER, OP_PAGER_TOP);
+    km_bindkey ("<end>", MENU_PAGER, OP_PAGER_BOTTOM);
+    km_bindkey ("1", MENU_PAGER, OP_JUMP);
+    km_bindkey ("2", MENU_PAGER, OP_JUMP);
+    km_bindkey ("3", MENU_PAGER, OP_JUMP);
+    km_bindkey ("4", MENU_PAGER, OP_JUMP);
+    km_bindkey ("5", MENU_PAGER, OP_JUMP);
+    km_bindkey ("6", MENU_PAGER, OP_JUMP);
+    km_bindkey ("7", MENU_PAGER, OP_JUMP);
+    km_bindkey ("8", MENU_PAGER, OP_JUMP);
+    km_bindkey ("9", MENU_PAGER, OP_JUMP);
+    km_bindkey ("<enter>", MENU_PAGER, OP_NEXT_LINE);
+  }
+
+  /* post menu bindings */
+  if (menu == MENU_POST || menu == -1)
+  {
+    create_bindings (OpPost, MENU_POST);
+  }
+
+  /* query menu bindings */
+  if (menu == MENU_QUERY || menu == -1)
+  {
+    create_bindings (OpQuery, MENU_QUERY);
+  }
+
+  /* alias menu bindings */
+  if (menu == MENU_ALIAS || menu == -1)
+  {
+    create_bindings (OpAlias, MENU_ALIAS);
+    km_bindkey ("<return>", MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
+    km_bindkey ("<enter>",  MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
+    km_bindkey ("<space>", MENU_ALIAS, OP_TAG);
+  }
+
+  /* pgp menu bindings */
+  if ((WithCrypto & APPLICATION_PGP) && (menu == MENU_PGP || menu == -1))
+  {
     create_bindings (OpPgp, MENU_PGP);
+  }
 
-  if ((WithCrypto & APPLICATION_SMIME))
+  /* s/mime menu bindings */
+  if ((WithCrypto & APPLICATION_SMIME) && (menu == MENU_SMIME || menu == -1))
+  {
     create_bindings (OpSmime, MENU_SMIME);
+  }
 
 #ifdef CRYPT_BACKEND_GPGME
-  create_bindings (OpPgp, MENU_KEY_SELECT_PGP);
-  create_bindings (OpSmime, MENU_KEY_SELECT_SMIME);
+  /* gpgme bindings */
+  if (menu == MENU_KEY_SELECT_PGP || menu == -1)
+  {
+    create_bindings (OpPgp, MENU_KEY_SELECT_PGP);
+  }
+  if (menu == MENU_KEY_SELECT_SMIME || menu == -1)
+  {
+    create_bindings (OpSmime, MENU_KEY_SELECT_SMIME);
+  }
 #endif
 
 #ifdef MIXMASTER
-  create_bindings (OpMix, MENU_MIX);
+  /* mixmaster bindings */
+  if (menu == MENU_MIX || menu == -1)
+  {
+    create_bindings (OpMix, MENU_MIX);
   
-  km_bindkey ("<space>", MENU_MIX, OP_GENERIC_SELECT_ENTRY);
-  km_bindkey ("h", MENU_MIX, OP_MIX_CHAIN_PREV);
-  km_bindkey ("l", MENU_MIX, OP_MIX_CHAIN_NEXT);
+    km_bindkey ("<space>", MENU_MIX, OP_GENERIC_SELECT_ENTRY);
+    km_bindkey ("h", MENU_MIX, OP_MIX_CHAIN_PREV);
+    km_bindkey ("l", MENU_MIX, OP_MIX_CHAIN_NEXT);
+  }
 #endif
   
   /* bindings for the line editor */
-  create_bindings (OpEditor, MENU_EDITOR);
-  
-  km_bindkey ("<up>", MENU_EDITOR, OP_EDITOR_HISTORY_UP);
-  km_bindkey ("<down>", MENU_EDITOR, OP_EDITOR_HISTORY_DOWN);
-  km_bindkey ("<left>", MENU_EDITOR, OP_EDITOR_BACKWARD_CHAR);
-  km_bindkey ("<right>", MENU_EDITOR, OP_EDITOR_FORWARD_CHAR);
-  km_bindkey ("<home>", MENU_EDITOR, OP_EDITOR_BOL);
-  km_bindkey ("<end>", MENU_EDITOR, OP_EDITOR_EOL);
-  km_bindkey ("<backspace>", MENU_EDITOR, OP_EDITOR_BACKSPACE);
-  km_bindkey ("<delete>", MENU_EDITOR, OP_EDITOR_BACKSPACE);
-  km_bindkey ("\177", MENU_EDITOR, OP_EDITOR_BACKSPACE);
-  
+  if (menu == MENU_EDITOR || menu == -1)
+  {
+    create_bindings (OpEditor, MENU_EDITOR);
+    km_bindkey ("<up>", MENU_EDITOR, OP_EDITOR_HISTORY_UP);
+    km_bindkey ("<down>", MENU_EDITOR, OP_EDITOR_HISTORY_DOWN);
+    km_bindkey ("<left>", MENU_EDITOR, OP_EDITOR_BACKWARD_CHAR);
+    km_bindkey ("<right>", MENU_EDITOR, OP_EDITOR_FORWARD_CHAR);
+    km_bindkey ("<home>", MENU_EDITOR, OP_EDITOR_BOL);
+    km_bindkey ("<end>", MENU_EDITOR, OP_EDITOR_EOL);
+    km_bindkey ("<backspace>", MENU_EDITOR, OP_EDITOR_BACKSPACE);
+    km_bindkey ("<delete>", MENU_EDITOR, OP_EDITOR_BACKSPACE);
+    km_bindkey ("\177", MENU_EDITOR, OP_EDITOR_BACKSPACE);
+  }
+
   /* generic menu keymap */
-  create_bindings (OpGeneric, MENU_GENERIC);
-  
-  km_bindkey ("<home>", MENU_GENERIC, OP_FIRST_ENTRY);
-  km_bindkey ("<end>", MENU_GENERIC, OP_LAST_ENTRY);
-  km_bindkey ("<pagedown>", MENU_GENERIC, OP_NEXT_PAGE);
-  km_bindkey ("<pageup>", MENU_GENERIC, OP_PREV_PAGE);
-  km_bindkey ("<right>", MENU_GENERIC, OP_NEXT_PAGE);
-  km_bindkey ("<left>", MENU_GENERIC, OP_PREV_PAGE);
-  km_bindkey ("<up>", MENU_GENERIC, OP_PREV_ENTRY);
-  km_bindkey ("<down>", MENU_GENERIC, OP_NEXT_ENTRY);
-  km_bindkey ("1", MENU_GENERIC, OP_JUMP);
-  km_bindkey ("2", MENU_GENERIC, OP_JUMP);
-  km_bindkey ("3", MENU_GENERIC, OP_JUMP);
-  km_bindkey ("4", MENU_GENERIC, OP_JUMP);
-  km_bindkey ("5", MENU_GENERIC, OP_JUMP);
-  km_bindkey ("6", MENU_GENERIC, OP_JUMP);
-  km_bindkey ("7", MENU_GENERIC, OP_JUMP);
-  km_bindkey ("8", MENU_GENERIC, OP_JUMP);
-  km_bindkey ("9", MENU_GENERIC, OP_JUMP);
-
-  km_bindkey ("<enter>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
-
-  /* Miscellaneous extra bindings */
-  
-  km_bindkey (" ", MENU_MAIN, OP_DISPLAY_MESSAGE);
-  km_bindkey ("<up>", MENU_MAIN, OP_MAIN_PREV_UNDELETED);
-  km_bindkey ("<down>", MENU_MAIN, OP_MAIN_NEXT_UNDELETED);
-  km_bindkey ("J", MENU_MAIN, OP_NEXT_ENTRY);
-  km_bindkey ("K", MENU_MAIN, OP_PREV_ENTRY);
-  km_bindkey ("x", MENU_MAIN, OP_EXIT);
-
-  km_bindkey ("<enter>", MENU_MAIN, OP_DISPLAY_MESSAGE);
-
-  km_bindkey ("x", MENU_PAGER, OP_EXIT);
-  km_bindkey ("i", MENU_PAGER, OP_EXIT);
-  km_bindkey ("<backspace>", MENU_PAGER, OP_PREV_LINE);
-  km_bindkey ("<pagedown>", MENU_PAGER, OP_NEXT_PAGE);
-  km_bindkey ("<pageup>", MENU_PAGER, OP_PREV_PAGE);
-  km_bindkey ("<up>", MENU_PAGER, OP_MAIN_PREV_UNDELETED);
-  km_bindkey ("<right>", MENU_PAGER, OP_MAIN_NEXT_UNDELETED);
-  km_bindkey ("<down>", MENU_PAGER, OP_MAIN_NEXT_UNDELETED);
-  km_bindkey ("<left>", MENU_PAGER, OP_MAIN_PREV_UNDELETED);
-  km_bindkey ("<home>", MENU_PAGER, OP_PAGER_TOP);
-  km_bindkey ("<end>", MENU_PAGER, OP_PAGER_BOTTOM);
-  km_bindkey ("1", MENU_PAGER, OP_JUMP);
-  km_bindkey ("2", MENU_PAGER, OP_JUMP);
-  km_bindkey ("3", MENU_PAGER, OP_JUMP);
-  km_bindkey ("4", MENU_PAGER, OP_JUMP);
-  km_bindkey ("5", MENU_PAGER, OP_JUMP);
-  km_bindkey ("6", MENU_PAGER, OP_JUMP);
-  km_bindkey ("7", MENU_PAGER, OP_JUMP);
-  km_bindkey ("8", MENU_PAGER, OP_JUMP);
-  km_bindkey ("9", MENU_PAGER, OP_JUMP);
-
-  km_bindkey ("<enter>", MENU_PAGER, OP_NEXT_LINE);
-  
-  km_bindkey ("<return>", MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
-  km_bindkey ("<enter>",  MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
-  km_bindkey ("<space>", MENU_ALIAS, OP_TAG);
-
-  km_bindkey ("<enter>", MENU_ATTACH, OP_VIEW_ATTACH);
-  km_bindkey ("<enter>", MENU_COMPOSE, OP_VIEW_ATTACH);
-
-  /* edit-to (default "t") hides generic tag-entry in Compose menu
-     This will bind tag-entry to  "T" in the Compose menu */
-  km_bindkey ("T", MENU_COMPOSE, OP_TAG);
+  if (menu == MENU_GENERIC || menu == -1)
+  {
+    create_bindings (OpGeneric, MENU_GENERIC);
+    km_bindkey ("<home>", MENU_GENERIC, OP_FIRST_ENTRY);
+    km_bindkey ("<end>", MENU_GENERIC, OP_LAST_ENTRY);
+    km_bindkey ("<pagedown>", MENU_GENERIC, OP_NEXT_PAGE);
+    km_bindkey ("<pageup>", MENU_GENERIC, OP_PREV_PAGE);
+    km_bindkey ("<right>", MENU_GENERIC, OP_NEXT_PAGE);
+    km_bindkey ("<left>", MENU_GENERIC, OP_PREV_PAGE);
+    km_bindkey ("<up>", MENU_GENERIC, OP_PREV_ENTRY);
+    km_bindkey ("<down>", MENU_GENERIC, OP_NEXT_ENTRY);
+    km_bindkey ("1", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("2", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("3", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("4", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("5", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("6", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("7", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("8", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("9", MENU_GENERIC, OP_JUMP);
+    km_bindkey ("<enter>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
+  }
 }
 
 void km_error_key (int menu)
@@ -860,7 +913,7 @@
 }
 
 /* expects to see: <menu-string>,<menu-string>,... <key-string> */
-static char *parse_keymap (int *menu, BUFFER *s, int maxmenus, int *nummenus, 
BUFFER *err)
+static char *parse_keymap (int *menu, BUFFER *s, int maxmenus, int *nummenus, 
BUFFER *err, int isunbind)
 {
   BUFFER buf;
   int i=0;
@@ -873,7 +926,13 @@
   p = buf.data;
   if (MoreArgs (s))
   {
-    while (i < maxmenus)
+    if (!strcmp(p, "*"))
+    {
+      /* choose all menus */
+      for (i = 0; i < maxmenus; i++)
+       menu[i] = i;
+    }
+    else while (i < maxmenus)
     {
       q = strchr(p,',');
       if (q)
@@ -891,14 +950,15 @@
         break;
     }
     *nummenus=i;
+
     /* key sequence */
     mutt_extract_token (&buf, s, 0);
-
     if (!*buf.data)
     {
       strfcpy (err->data, _("null key sequence"), err->dsize);
     }
-    else if (MoreArgs (s))
+    /* unbind and "bind map *" do not require more args  */
+    else if (isunbind || !mutt_strcmp(buf.data, "*") || MoreArgs (s))
       return (buf.data);
   }
   else
@@ -976,9 +1036,24 @@
   int menu[sizeof(Menus)/sizeof(struct mapping_t)-1], r = 0, nummenus, i;
 
   if ((key = parse_keymap (menu, s, sizeof (menu)/sizeof (menu[0]),
-                          &nummenus, err)) == NULL)
+                          &nummenus, err, FALSE)) == NULL)
     return (-1);
 
+  if (!MoreArgs (s) && mutt_strcmp(key, "*") == 0)
+  {
+    /* Reinitialize selected menus */
+    for (i = 0; i < nummenus; i++)
+    {
+      if (menu[i] != -1)
+      {
+       dprint(1, (debugfile, "bind %s *\n", mutt_getnamebyvalue(menu[i], 
Menus)));
+       km_init(menu[i]);
+      }
+    }
+    FREE (&key);
+    return (r);
+  }
+
   /* function to execute */
   mutt_extract_token (buf, s, 0);
   if (MoreArgs (s))
@@ -1016,6 +1091,127 @@
   return (r);
 }
 
+static int keycmp(keycode_t *code, char *keys, int codelen)
+{
+  keycode_t buf[MAX_SEQ];
+  int i, len;
+
+  len = parsekeys (keys, buf, MAX_SEQ);
+  for (i = 0; i < codelen && i < len && code[i] == buf[i]; i++);
+  if (i == codelen)
+    return 0;
+  return (code[i] < buf[i]) ? -1 : 1;
+}
+
+
+static void km_unbind(struct keymap_t **map, char *key, unsigned long mode)
+{
+  struct keymap_t *cur, *next, *first, *prev;
+
+  prev = NULL;
+  next = first = *map;
+
+  while ((cur = next))
+  {
+    next = cur->next;
+    if ((mode & M_UNBIND) && cur->macro != NULL)
+    {
+      prev = cur;
+      continue;
+    }
+
+    if ((mode & M_UNMACRO) && cur->macro == NULL)
+    {
+      prev = cur;
+      continue;
+    }
+
+    if (key == NULL || keycmp(cur->keys, key, cur->len) == 0)
+    {
+      FREE(&cur->macro);
+      FREE(&cur->keys);
+      FREE(&cur->descr);
+      FREE(&cur);
+
+      if (prev)
+       prev->next = next;
+      else
+       first = next;
+    }
+
+    else
+      prev = cur;
+  }
+
+  *map = first;
+}
+
+/* unbind menu-name '<key_sequence>' */
+/* Never unbind *everything*.  Leave an escape hatch. */
+int mutt_parse_unbind (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
+{
+  char *key;
+  int menu[sizeof(Menus)/sizeof(struct mapping_t)-1], r = 0, nummenus, i;
+
+  if ((key = parse_keymap (menu, s, sizeof (menu)/sizeof (menu[0]),
+                          &nummenus, err, TRUE)) == NULL)
+    return (-1);
+
+  if (MoreArgs (s))
+  {
+    strfcpy (err->data, _("unbind: too many arguments"), err->dsize);
+    FREE (&key);
+    return (-1);
+  }
+
+  if (mutt_strcmp(key, "*") == 0)
+  {
+    int neededitorbindings = 0;
+
+    /* Unbind all in selected menus */
+    for (i = 0; i < nummenus; ++i)
+    {
+      if (menu[i] == -1)
+       continue;
+      dprint(1, (debugfile, "unbind %s %s\n", mutt_getnamebyvalue(menu[i], 
Menus), key));
+      km_unbind (&Keymaps[menu[i]], NULL, data);
+
+      /* If we unbound * in generic, then rebind <enter-command> */
+      if ((menu[i] == MENU_GENERIC) && ((data & M_UNBIND) == M_UNBIND))
+      {
+       neededitorbindings++;
+       km_bindkey (":", MENU_GENERIC, OP_ENTER_COMMAND);
+      }
+
+      /* <enter-command> will need basic editor mappings.
+       * If editor bindings were removed, remember that. */
+      if (menu[i] == MENU_EDITOR)
+       neededitorbindings++;
+
+      /* pager needs at least an exit */
+      if (menu[i] == MENU_PAGER)
+       km_bindkey ("q", MENU_PAGER, OP_EXIT);
+    }
+    if (neededitorbindings == 2)
+      create_bindings (OpEditor, MENU_EDITOR);
+  }
+  else
+  {
+    /* Unbind designated key in each selected menu. */
+    for (i = 0; i < nummenus; ++i)
+    {
+      if (menu[i] != -1)
+      {
+       dprint(1, (debugfile, "unbind %s %s\n", mutt_getnamebyvalue(menu[i], 
Menus), key));
+       km_unbind (&Keymaps[menu[i]], key, data);
+      }
+    }
+  }
+
+  FREE (&key);
+  return (r);
+}
+
 /* macro <menu> <key> <macro> <description> */
 int mutt_parse_macro (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
 {
@@ -1023,7 +1219,7 @@
   char *seq = NULL;
   char *key;
 
-  if ((key = parse_keymap (menu, s, sizeof (menu) / sizeof (menu[0]), 
&nummenus, err)) == NULL)
+  if ((key = parse_keymap (menu, s, sizeof (menu) / sizeof (menu[0]), 
&nummenus, err, FALSE)) == NULL)
     return (-1);
 
   mutt_extract_token (buf, s, M_TOKEN_CONDENSE);
diff -r 3306cb186f49 -r 44c56715ef8b keymap.h
--- a/keymap.h  Tue Oct 29 00:11:16 2013 -0700
+++ b/keymap.h  Wed Nov 27 16:53:40 2013 -0600
@@ -47,7 +47,7 @@
 
 int km_expand_key (char *, size_t, struct keymap_t *);
 struct keymap_t *km_find_func (int, int);
-void km_init (void);
+void km_init (int);
 void km_error_key (int);
 void mutt_what_key (void);
 
diff -r 3306cb186f49 -r 44c56715ef8b main.c
--- a/main.c    Tue Oct 29 00:11:16 2013 -0700
+++ b/main.c    Wed Nov 27 16:53:40 2013 -0600
@@ -511,7 +511,7 @@
 
 static void start_curses (void)
 {
-  km_init (); /* must come before mutt_init */
+  km_init (-1); /* must come before mutt_init */
 
 #ifdef USE_SLANG_CURSES
   SLtt_Ignore_Beep = 1; /* don't do that #*$@^! annoying visual beep! */
diff -r 3306cb186f49 -r 44c56715ef8b mutt.h
--- a/mutt.h    Tue Oct 29 00:11:16 2013 -0700
+++ b/mutt.h    Wed Nov 27 16:53:40 2013 -0600
@@ -955,6 +955,10 @@
 
 #define M_PARTS_TOPLEVEL       (1<<0)  /* is the top-level part */
 
+/* Options for mutt_parse_unbind */
+#define M_UNBIND      1<<0
+#define M_UNMACRO     1<<1
+
 #include "ascii.h"
 #include "protos.h"
 #include "lib.h"
diff -r 3306cb186f49 -r 44c56715ef8b protos.h
--- a/protos.h  Tue Oct 29 00:11:16 2013 -0700
+++ b/protos.h  Wed Nov 27 16:53:40 2013 -0600
@@ -326,6 +326,7 @@
 int mutt_needs_mailcap (BODY *);
 int mutt_num_postponed (int);
 int mutt_parse_bind (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+int mutt_parse_unbind (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 int mutt_parse_exec (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 int mutt_parse_color (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 int mutt_parse_uncolor (BUFFER *, BUFFER *, unsigned long, BUFFER *);

Reply via email to