X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/df75b1a379309fcc6273081e18fa450b792b720d..534c20b22f89ffbe99a4d6a1035b74eacc544ee5:/src/keymap.c diff --git a/src/keymap.c b/src/keymap.c index 5bd628bc16..e56a21a735 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -1,5 +1,6 @@ /* Manipulation of keymaps - Copyright (C) 1985, 86,87,88,93,94,95,98,99 Free Software Foundation, Inc. + Copyright (C) 1985, 86,87,88,93,94,95,98,99, 2000, 2001 + Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -21,7 +22,6 @@ Boston, MA 02111-1307, USA. */ #include #include -#undef NULL #include "lisp.h" #include "commands.h" #include "buffer.h" @@ -31,8 +31,7 @@ Boston, MA 02111-1307, USA. */ #include "blockinput.h" #include "puresize.h" #include "intervals.h" - -#define min(a, b) ((a) < (b) ? (a) : (b)) +#include "keymap.h" /* The number of elements in keymap vectors. */ #define DENSE_TABLE_SIZE (0200) @@ -56,7 +55,7 @@ Lisp_Object Vminibuffer_local_map; minibuf */ /* was MinibufLocalNSMap */ -Lisp_Object Vminibuffer_local_ns_map; +Lisp_Object Vminibuffer_local_ns_map; /* The keymap used by the minibuf for local bindings when spaces are not encouraged in the minibuf */ @@ -90,7 +89,13 @@ Lisp_Object Vkey_translation_map; when Emacs starts up. t means don't record anything here. */ Lisp_Object Vdefine_key_rebound_commands; -Lisp_Object Qkeymapp, Qkeymap, Qnon_ascii, Qmenu_item; +Lisp_Object Qkeymapp, Qkeymap, Qnon_ascii, Qmenu_item, Qremap; + +/* Alist of elements like (DEL . "\d"). */ +static Lisp_Object exclude_keys; + +/* Pre-allocated 2-element vector for Fremap_command to use. */ +static Lisp_Object remap_command_vector; /* A char with the CHAR_META bit set in a vector or the 0200 bit set in a string key sequence is equivalent to prefixing with this @@ -99,22 +104,34 @@ extern Lisp_Object meta_prefix_char; extern Lisp_Object Voverriding_local_map; -static Lisp_Object define_as_prefix (); -static Lisp_Object describe_buffer_bindings (); -static void describe_command (), describe_translation (); -static void describe_map (); +/* Hash table used to cache a reverse-map to speed up calls to where-is. */ +static Lisp_Object where_is_cache; +/* Which keymaps are reverse-stored in the cache. */ +static Lisp_Object where_is_cache_keymaps; + +static Lisp_Object store_in_keymap P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); +static void fix_submap_inheritance P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); + +static Lisp_Object define_as_prefix P_ ((Lisp_Object, Lisp_Object)); +static void describe_command P_ ((Lisp_Object, Lisp_Object)); +static void describe_translation P_ ((Lisp_Object, Lisp_Object)); +static void describe_map P_ ((Lisp_Object, Lisp_Object, + void (*) P_ ((Lisp_Object, Lisp_Object)), + int, Lisp_Object, Lisp_Object*, int)); +static void silly_event_symbol_error P_ ((Lisp_Object)); /* Keymap object support - constructors and predicates. */ DEFUN ("make-keymap", Fmake_keymap, Smake_keymap, 0, 1, 0, - "Construct and return a new keymap, of the form (keymap CHARTABLE . ALIST).\n\ -CHARTABLE is a char-table that holds the bindings for the ASCII\n\ -characters. ALIST is an assoc-list which holds bindings for function keys,\n\ -mouse events, and any other things that appear in the input stream.\n\ -All entries in it are initially nil, meaning \"command undefined\".\n\n\ -The optional arg STRING supplies a menu name for the keymap\n\ -in case you use it as a menu with `x-popup-menu'.") - (string) + doc: /* Construct and return a new keymap, of the form (keymap CHARTABLE . ALIST). +CHARTABLE is a char-table that holds the bindings for the ASCII +characters. ALIST is an assoc-list which holds bindings for function keys, +mouse events, and any other things that appear in the input stream. +All entries in it are initially nil, meaning "command undefined". + +The optional arg STRING supplies a menu name for the keymap +in case you use it as a menu with `x-popup-menu'. */) + (string) Lisp_Object string; { Lisp_Object tail; @@ -127,14 +144,15 @@ in case you use it as a menu with `x-popup-menu'.") } DEFUN ("make-sparse-keymap", Fmake_sparse_keymap, Smake_sparse_keymap, 0, 1, 0, - "Construct and return a new sparse-keymap list.\n\ -Its car is `keymap' and its cdr is an alist of (CHAR . DEFINITION),\n\ -which binds the character CHAR to DEFINITION, or (SYMBOL . DEFINITION),\n\ -which binds the function key or mouse event SYMBOL to DEFINITION.\n\ -Initially the alist is nil.\n\n\ -The optional arg STRING supplies a menu name for the keymap\n\ -in case you use it as a menu with `x-popup-menu'.") - (string) + doc: /* Construct and return a new sparse keymap. +Its car is `keymap' and its cdr is an alist of (CHAR . DEFINITION), +which binds the character CHAR to DEFINITION, or (SYMBOL . DEFINITION), +which binds the function key or mouse event SYMBOL to DEFINITION. +Initially the alist is nil. + +The optional arg STRING supplies a menu name for the keymap +in case you use it as a menu with `x-popup-menu'. */) + (string) Lisp_Object string; { if (!NILP (string)) @@ -167,35 +185,36 @@ initial_define_lispy_key (keymap, keyname, defname) store_in_keymap (keymap, intern (keyname), intern (defname)); } -/* Define character fromchar in map frommap as an alias for character - tochar in map tomap. Subsequent redefinitions of the latter WILL - affect the former. */ - -#if 0 -void -synkey (frommap, fromchar, tomap, tochar) - struct Lisp_Vector *frommap, *tomap; - int fromchar, tochar; +DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0, + doc: /* Return t if OBJECT is a keymap. + +A keymap is a list (keymap . ALIST), +or a symbol whose function definition is itself a keymap. +ALIST elements look like (CHAR . DEFN) or (SYMBOL . DEFN); +a vector of densely packed bindings for small character codes +is also allowed as an element. */) + (object) + Lisp_Object object; { - Lisp_Object v, c; - XSETVECTOR (v, tomap); - XSETFASTINT (c, tochar); - frommap->contents[fromchar] = Fcons (v, c); + return (KEYMAPP (object) ? Qt : Qnil); } -#endif /* 0 */ -DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0, - "Return t if OBJECT is a keymap.\n\ -\n\ -A keymap is a list (keymap . ALIST),\n\ -or a symbol whose function definition is itself a keymap.\n\ -ALIST elements look like (CHAR . DEFN) or (SYMBOL . DEFN);\n\ -a vector of densely packed bindings for small character codes\n\ -is also allowed as an element.") - (object) - Lisp_Object object; +DEFUN ("keymap-prompt", Fkeymap_prompt, Skeymap_prompt, 1, 1, 0, + doc: /* Return the prompt-string of a keymap MAP. +If non-nil, the prompt is shown in the echo-area +when reading a key-sequence to be looked-up in this keymap. */) + (map) + Lisp_Object map; { - return (NILP (get_keymap_1 (object, 0, 0)) ? Qnil : Qt); + while (CONSP (map)) + { + register Lisp_Object tem; + tem = Fcar (map); + if (STRINGP (tem)) + return tem; + map = Fcdr (map); + } + return Qnil; } /* Check that OBJECT is a keymap (after dereferencing through any @@ -205,6 +224,9 @@ is also allowed as an element.") is an autoload form, do the autoload and try again. If AUTOLOAD is nonzero, callers must assume GC is possible. + If the map needs to be autoloaded, but AUTOLOAD is zero (and ERROR + is zero as well), return Qt. + ERROR controls how we respond if OBJECT isn't a keymap. If ERROR is non-zero, signal an error; otherwise, just return Qnil. @@ -218,7 +240,7 @@ is also allowed as an element.") do_autoload which can GC. */ Lisp_Object -get_keymap_1 (object, error, autoload) +get_keymap (object, error, autoload) Lisp_Object object; int error, autoload; { @@ -229,93 +251,112 @@ get_keymap_1 (object, error, autoload) goto end; if (CONSP (object) && EQ (XCAR (object), Qkeymap)) return object; - else - { - tem = indirect_function (object); - if (CONSP (tem) && EQ (XCAR (tem), Qkeymap)) - return tem; - } - /* Should we do an autoload? Autoload forms for keymaps have - Qkeymap as their fifth element. */ - if (autoload - && SYMBOLP (object) - && CONSP (tem) - && EQ (XCAR (tem), Qautoload)) + tem = indirect_function (object); + if (CONSP (tem)) { - Lisp_Object tail; + if (EQ (XCAR (tem), Qkeymap)) + return tem; - tail = Fnth (make_number (4), tem); - if (EQ (tail, Qkeymap)) + /* Should we do an autoload? Autoload forms for keymaps have + Qkeymap as their fifth element. */ + if ((autoload || !error) && EQ (XCAR (tem), Qautoload)) { - struct gcpro gcpro1, gcpro2; - - GCPRO2 (tem, object); - do_autoload (tem, object); - UNGCPRO; + Lisp_Object tail; - goto autoload_retry; + tail = Fnth (make_number (4), tem); + if (EQ (tail, Qkeymap)) + { + if (autoload) + { + struct gcpro gcpro1, gcpro2; + + GCPRO2 (tem, object); + do_autoload (tem, object); + UNGCPRO; + + goto autoload_retry; + } + else + return Qt; + } } } end: if (error) wrong_type_argument (Qkeymapp, object); - else - return Qnil; -} - - -/* Follow any symbol chaining, and return the keymap denoted by OBJECT. - If OBJECT doesn't denote a keymap at all, signal an error. */ -Lisp_Object -get_keymap (object) - Lisp_Object object; -{ - return get_keymap_1 (object, 1, 0); + return Qnil; } /* Return the parent map of the keymap MAP, or nil if it has none. We assume that MAP is a valid keymap. */ DEFUN ("keymap-parent", Fkeymap_parent, Skeymap_parent, 1, 1, 0, - "Return the parent keymap of KEYMAP.") - (keymap) + doc: /* Return the parent keymap of KEYMAP. */) + (keymap) Lisp_Object keymap; { Lisp_Object list; - keymap = get_keymap_1 (keymap, 1, 1); + keymap = get_keymap (keymap, 1, 1); /* Skip past the initial element `keymap'. */ list = XCDR (keymap); for (; CONSP (list); list = XCDR (list)) { /* See if there is another `keymap'. */ - if (EQ (Qkeymap, XCAR (list))) + if (KEYMAPP (list)) return list; } - return Qnil; + return get_keymap (list, 0, 1); +} + + +/* Check whether MAP is one of MAPS parents. */ +int +keymap_memberp (map, maps) + Lisp_Object map, maps; +{ + if (NILP (map)) return 0; + while (KEYMAPP (maps) && !EQ (map, maps)) + maps = Fkeymap_parent (maps); + return (EQ (map, maps)); } /* Set the parent keymap of MAP to PARENT. */ DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0, - "Modify KEYMAP to set its parent map to PARENT.\n\ -PARENT should be nil or another keymap.") - (keymap, parent) + doc: /* Modify KEYMAP to set its parent map to PARENT. +PARENT should be nil or another keymap. */) + (keymap, parent) Lisp_Object keymap, parent; { Lisp_Object list, prev; struct gcpro gcpro1; int i; - keymap = get_keymap_1 (keymap, 1, 1); + /* Force a keymap flush for the next call to where-is. + Since this can be called from within where-is, we don't set where_is_cache + directly but only where_is_cache_keymaps, since where_is_cache shouldn't + be changed during where-is, while where_is_cache_keymaps is only used at + the very beginning of where-is and can thus be changed here without any + adverse effect. + This is a very minor correctness (rather than safety) issue. */ + where_is_cache_keymaps = Qt; + + keymap = get_keymap (keymap, 1, 1); GCPRO1 (keymap); if (!NILP (parent)) - parent = get_keymap_1 (parent, 1, 1); + { + parent = get_keymap (parent, 1, 1); + + /* Check for cycles. */ + if (keymap_memberp (keymap, parent)) + error ("Cyclic keymap inheritance"); + } /* Skip past the initial element `keymap'. */ prev = keymap; @@ -324,14 +365,14 @@ PARENT should be nil or another keymap.") list = XCDR (prev); /* If there is a parent keymap here, replace it. If we came to the end, add the parent in PREV. */ - if (! CONSP (list) || EQ (Qkeymap, XCAR (list))) + if (!CONSP (list) || KEYMAPP (list)) { /* If we already have the right parent, return now so that we avoid the loops below. */ if (EQ (XCDR (prev), parent)) RETURN_UNGCPRO (parent); - XCDR (prev) = parent; + XSETCDR (prev, parent); break; } prev = list; @@ -373,7 +414,7 @@ PARENT should be nil or another keymap.") if EVENT is also a prefix in MAP's parent, make sure that SUBMAP inherits that definition as its own parent. */ -void +static void fix_submap_inheritance (map, event, submap) Lisp_Object map, event, submap; { @@ -382,52 +423,23 @@ fix_submap_inheritance (map, event, submap) /* SUBMAP is a cons that we found as a key binding. Discard the other things found in a menu key binding. */ - if (CONSP (submap)) - { - /* May be an old format menu item */ - if (STRINGP (XCAR (submap))) - { - submap = XCDR (submap); - /* Also remove a menu help string, if any, - following the menu item name. */ - if (CONSP (submap) && STRINGP (XCAR (submap))) - submap = XCDR (submap); - /* Also remove the sublist that caches key equivalences, if any. */ - if (CONSP (submap) - && CONSP (XCAR (submap))) - { - Lisp_Object carcar; - carcar = XCAR (XCAR (submap)); - if (NILP (carcar) || VECTORP (carcar)) - submap = XCDR (submap); - } - } - - /* Or a new format menu item */ - else if (EQ (XCAR (submap), Qmenu_item) - && CONSP (XCDR (submap))) - { - submap = XCDR (XCDR (submap)); - if (CONSP (submap)) - submap = XCAR (submap); - } - } + submap = get_keymap (get_keyelt (submap, 0), 0, 0); /* If it isn't a keymap now, there's no work to do. */ - if (! CONSP (submap) - || ! EQ (XCAR (submap), Qkeymap)) + if (!CONSP (submap)) return; map_parent = Fkeymap_parent (map); - if (! NILP (map_parent)) - parent_entry = access_keymap (map_parent, event, 0, 0); + if (!NILP (map_parent)) + parent_entry = + get_keymap (access_keymap (map_parent, event, 0, 0, 0), 0, 0); else parent_entry = Qnil; /* If MAP's parent has something other than a keymap, - our own submap shadows it completely, so use nil as SUBMAP's parent. */ - if (! (CONSP (parent_entry) && EQ (XCAR (parent_entry), Qkeymap))) - parent_entry = Qnil; + our own submap shadows it completely. */ + if (!CONSP (parent_entry)) + return; if (! EQ (parent_entry, submap)) { @@ -436,12 +448,16 @@ fix_submap_inheritance (map, event, submap) while (1) { Lisp_Object tem; + tem = Fkeymap_parent (submap_parent); - if (EQ (tem, parent_entry)) - return; - if (CONSP (tem) - && EQ (XCAR (tem), Qkeymap)) - submap_parent = tem; + + if (KEYMAPP (tem)) + { + if (keymap_memberp (tem, parent_entry)) + /* Fset_keymap_parent could create a cycle. */ + return; + submap_parent = tem; + } else break; } @@ -462,15 +478,18 @@ fix_submap_inheritance (map, event, submap) If NOINHERIT, don't accept a subkeymap found in an inherited keymap. */ Lisp_Object -access_keymap (map, idx, t_ok, noinherit) +access_keymap (map, idx, t_ok, noinherit, autoload) Lisp_Object map; Lisp_Object idx; int t_ok; int noinherit; + int autoload; { - int noprefix = 0; Lisp_Object val; + /* Qunbound in VAL means we have found no binding yet. */ + val = Qunbound; + /* If idx is a list (some sort of mouse click, perhaps?), the index we want to use is the car of the list, which ought to be a symbol. */ @@ -485,12 +504,47 @@ access_keymap (map, idx, t_ok, noinherit) with more than 24 bits of integer. */ XSETFASTINT (idx, XINT (idx) & (CHAR_META | (CHAR_META - 1))); + /* Handle the special meta -> esc mapping. */ + if (INTEGERP (idx) && XUINT (idx) & meta_modifier) + { + /* See if there is a meta-map. If there's none, there is + no binding for IDX, unless a default binding exists in MAP. */ + Lisp_Object meta_map = + get_keymap (access_keymap (map, meta_prefix_char, + t_ok, noinherit, autoload), + 0, autoload); + if (CONSP (meta_map)) + { + map = meta_map; + idx = make_number (XUINT (idx) & ~meta_modifier); + } + else if (t_ok) + /* Set IDX to t, so that we only find a default binding. */ + idx = Qt; + else + /* We know there is no binding. */ + return Qnil; + } + { Lisp_Object tail; - Lisp_Object t_binding; + /* t_binding is where we put a default binding that applies, + to use in case we do not find a binding specifically + for this key sequence. */ + + Lisp_Object t_binding; t_binding = Qnil; - for (tail = map; CONSP (tail); tail = XCDR (tail)) + + /* If `t_ok' is 2, both `t' and generic-char bindings are accepted. + If it is 1, only generic-char bindings are accepted. + Otherwise, neither are. */ + t_ok = t_ok ? 2 : 0; + + for (tail = XCDR (map); + (CONSP (tail) + || (tail = get_keymap (tail, 0, autoload), CONSP (tail))); + tail = XCDR (tail)) { Lisp_Object binding; @@ -499,58 +553,77 @@ access_keymap (map, idx, t_ok, noinherit) { /* If NOINHERIT, stop finding prefix definitions after we pass a second occurrence of the `keymap' symbol. */ - if (noinherit && EQ (binding, Qkeymap) && ! EQ (tail, map)) - noprefix = 1; + if (noinherit && EQ (binding, Qkeymap)) + return Qnil; } else if (CONSP (binding)) { - if (EQ (XCAR (binding), idx)) + Lisp_Object key = XCAR (binding); + + if (EQ (key, idx)) + val = XCDR (binding); + else if (t_ok + && INTEGERP (idx) + && (XINT (idx) & CHAR_MODIFIER_MASK) == 0 + && INTEGERP (key) + && (XINT (key) & CHAR_MODIFIER_MASK) == 0 + && !SINGLE_BYTE_CHAR_P (XINT (idx)) + && !SINGLE_BYTE_CHAR_P (XINT (key)) + && CHAR_VALID_P (XINT (key), 1) + && !CHAR_VALID_P (XINT (key), 0) + && (CHAR_CHARSET (XINT (key)) + == CHAR_CHARSET (XINT (idx)))) + { + /* KEY is the generic character of the charset of IDX. + Use KEY's binding if there isn't a binding for IDX + itself. */ + t_binding = XCDR (binding); + t_ok = 0; + } + else if (t_ok > 1 && EQ (key, Qt)) { - val = XCDR (binding); - if (noprefix && CONSP (val) && EQ (XCAR (val), Qkeymap)) - return Qnil; - if (CONSP (val)) - fix_submap_inheritance (map, idx, val); - return val; + t_binding = XCDR (binding); + t_ok = 1; } - if (t_ok && EQ (XCAR (binding), Qt)) - t_binding = XCDR (binding); } else if (VECTORP (binding)) { - if (NATNUMP (idx) && XFASTINT (idx) < XVECTOR (binding)->size) - { - val = XVECTOR (binding)->contents[XFASTINT (idx)]; - if (noprefix && CONSP (val) && EQ (XCAR (val), Qkeymap)) - return Qnil; - if (CONSP (val)) - fix_submap_inheritance (map, idx, val); - return val; - } + if (NATNUMP (idx) && XFASTINT (idx) < ASIZE (binding)) + val = AREF (binding, XFASTINT (idx)); } else if (CHAR_TABLE_P (binding)) { /* Character codes with modifiers are not included in a char-table. All character codes without modifiers are included. */ - if (NATNUMP (idx) - && ! (XFASTINT (idx) - & (CHAR_ALT | CHAR_SUPER | CHAR_HYPER - | CHAR_SHIFT | CHAR_CTL | CHAR_META))) + if (NATNUMP (idx) && (XFASTINT (idx) & CHAR_MODIFIER_MASK) == 0) { val = Faref (binding, idx); - if (noprefix && CONSP (val) && EQ (XCAR (val), Qkeymap)) - return Qnil; - if (CONSP (val)) - fix_submap_inheritance (map, idx, val); - return val; + /* `nil' has a special meaning for char-tables, so + we use something else to record an explicitly + unbound entry. */ + if (NILP (val)) + val = Qunbound; } } + /* If we found a binding, clean it up and return it. */ + if (!EQ (val, Qunbound)) + { + if (EQ (val, Qt)) + /* A Qt binding is just like an explicit nil binding + (i.e. it shadows any parent binding but not bindings in + keymaps of lower precedence). */ + val = Qnil; + val = get_keyelt (val, autoload); + if (KEYMAPP (val)) + fix_submap_inheritance (map, idx, val); + return val; + } QUIT; } - return t_binding; + return get_keyelt (t_binding, autoload); } } @@ -598,18 +671,14 @@ get_keyelt (object, autoload) /* If there's a `:filter FILTER', apply FILTER to the menu-item's definition to get the real definition to - use. Temporarily inhibit GC while evaluating FILTER, - because not functions calling get_keyelt are prepared - for a GC. */ + use. */ for (; CONSP (tem) && CONSP (XCDR (tem)); tem = XCDR (tem)) - if (EQ (XCAR (tem), QCfilter)) + if (EQ (XCAR (tem), QCfilter) && autoload) { - int count = inhibit_garbage_collection (); Lisp_Object filter; filter = XCAR (XCDR (tem)); filter = list2 (filter, list2 (Qquote, object)); object = menu_item_eval_property (filter); - unbind_to (count, Qnil); break; } } @@ -642,43 +711,30 @@ get_keyelt (object, autoload) else { Lisp_Object map; - - map = get_keymap_1 (Fcar_safe (object), 0, autoload); - if (NILP (map)) - /* Invalid keymap */ - return object; - else - { - Lisp_Object key; - key = Fcdr (object); - if (INTEGERP (key) && (XUINT (key) & meta_modifier)) - { - object = access_keymap (map, meta_prefix_char, 0, 0); - map = get_keymap_1 (object, 0, autoload); - object = access_keymap (map, make_number (XINT (key) - & ~meta_modifier), - 0, 0); - } - else - object = access_keymap (map, key, 0, 0); - } + map = get_keymap (Fcar_safe (object), 0, autoload); + return (!CONSP (map) ? object /* Invalid keymap */ + : access_keymap (map, Fcdr (object), 0, 0, autoload)); } } } -Lisp_Object +static Lisp_Object store_in_keymap (keymap, idx, def) Lisp_Object keymap; register Lisp_Object idx; register Lisp_Object def; { + /* Flush any reverse-map cache. */ + where_is_cache = Qnil; + where_is_cache_keymaps = Qt; + /* If we are preparing to dump, and DEF is a menu element with a menu item indicator, copy it to ensure it is not pure. */ if (CONSP (def) && PURE_P (def) && (EQ (XCAR (def), Qmenu_item) || STRINGP (XCAR (def)))) def = Fcons (XCAR (def), XCDR (def)); - if (!CONSP (keymap) || ! EQ (XCAR (keymap), Qkeymap)) + if (!CONSP (keymap) || !EQ (XCAR (keymap), Qkeymap)) error ("attempt to define a key in a non-keymap"); /* If idx is a list (some sort of mouse click, perhaps?), @@ -715,9 +771,9 @@ store_in_keymap (keymap, idx, def) elt = XCAR (tail); if (VECTORP (elt)) { - if (NATNUMP (idx) && XFASTINT (idx) < XVECTOR (elt)->size) + if (NATNUMP (idx) && XFASTINT (idx) < ASIZE (elt)) { - XVECTOR (elt)->contents[XFASTINT (idx)] = def; + ASET (elt, XFASTINT (idx), def); return def; } insertion_point = tail; @@ -727,12 +783,13 @@ store_in_keymap (keymap, idx, def) /* Character codes with modifiers are not included in a char-table. All character codes without modifiers are included. */ - if (NATNUMP (idx) - && ! (XFASTINT (idx) - & (CHAR_ALT | CHAR_SUPER | CHAR_HYPER - | CHAR_SHIFT | CHAR_CTL | CHAR_META))) + if (NATNUMP (idx) && !(XFASTINT (idx) & CHAR_MODIFIER_MASK)) { - Faset (elt, idx, def); + Faset (elt, idx, + /* `nil' has a special meaning for char-tables, so + we use something else to record an explicitly + unbound entry. */ + NILP (def) ? Qt : def); return def; } insertion_point = tail; @@ -741,19 +798,16 @@ store_in_keymap (keymap, idx, def) { if (EQ (idx, XCAR (elt))) { - XCDR (elt) = def; + XSETCDR (elt, def); return def; } } - else if (SYMBOLP (elt)) - { - /* If we find a 'keymap' symbol in the spine of KEYMAP, - then we must have found the start of a second keymap - being used as the tail of KEYMAP, and a binding for IDX - should be inserted before it. */ - if (EQ (elt, Qkeymap)) - goto keymap_end; - } + else if (EQ (elt, Qkeymap)) + /* If we find a 'keymap' symbol in the spine of KEYMAP, + then we must have found the start of a second keymap + being used as the tail of KEYMAP, and a binding for IDX + should be inserted before it. */ + goto keymap_end; QUIT; } @@ -761,34 +815,39 @@ store_in_keymap (keymap, idx, def) keymap_end: /* We have scanned the entire keymap, and not found a binding for IDX. Let's add one. */ - XCDR (insertion_point) - = Fcons (Fcons (idx, def), XCDR (insertion_point)); + XSETCDR (insertion_point, + Fcons (Fcons (idx, def), XCDR (insertion_point))); } - + return def; } +EXFUN (Fcopy_keymap, 1); + void copy_keymap_1 (chartable, idx, elt) Lisp_Object chartable, idx, elt; { - if (!SYMBOLP (elt) && ! NILP (Fkeymapp (elt))) + if (CONSP (elt) && EQ (XCAR (elt), Qkeymap)) Faset (chartable, idx, Fcopy_keymap (elt)); } DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 0, - "Return a copy of the keymap KEYMAP.\n\ -The copy starts out with the same definitions of KEYMAP,\n\ -but changing either the copy or KEYMAP does not affect the other.\n\ -Any key definitions that are subkeymaps are recursively copied.\n\ -However, a key definition which is a symbol whose definition is a keymap\n\ -is not copied.") - (keymap) + doc: /* Return a copy of the keymap KEYMAP. +The copy starts out with the same definitions of KEYMAP, +but changing either the copy or KEYMAP does not affect the other. +Any key definitions that are subkeymaps are recursively copied. +However, a key definition which is a symbol whose definition is a keymap +is not copied. */) + (keymap) Lisp_Object keymap; { + /* FIXME: This doesn't properly copy menu-items in vectors. */ + /* FIXME: This also copies the parent keymap. */ + register Lisp_Object copy, tail; - copy = Fcopy_alist (get_keymap (keymap)); + copy = Fcopy_alist (get_keymap (keymap, 1, 0)); for (tail = copy; CONSP (tail); tail = XCDR (tail)) { @@ -800,7 +859,7 @@ is not copied.") Lisp_Object indices[3]; elt = Fcopy_sequence (elt); - XCAR (tail) = elt; + XSETCAR (tail, elt); map_char_table (copy_keymap_1, Qnil, elt, elt, 0, indices); } @@ -809,13 +868,11 @@ is not copied.") int i; elt = Fcopy_sequence (elt); - XCAR (tail) = elt; + XSETCAR (tail, elt); - for (i = 0; i < XVECTOR (elt)->size; i++) - if (!SYMBOLP (XVECTOR (elt)->contents[i]) - && ! NILP (Fkeymapp (XVECTOR (elt)->contents[i]))) - XVECTOR (elt)->contents[i] - = Fcopy_keymap (XVECTOR (elt)->contents[i]); + for (i = 0; i < ASIZE (elt); i++) + if (CONSP (AREF (elt, i)) && EQ (XCAR (AREF (elt, i)), Qkeymap)) + ASET (elt, i, Fcopy_keymap (AREF (elt, i))); } else if (CONSP (elt) && CONSP (XCDR (elt))) { @@ -826,15 +883,15 @@ is not copied.") if (EQ (XCAR (tem),Qmenu_item)) { /* Copy cell with menu-item marker. */ - XCDR (elt) - = Fcons (XCAR (tem), XCDR (tem)); + XSETCDR (elt, + Fcons (XCAR (tem), XCDR (tem))); elt = XCDR (elt); tem = XCDR (elt); if (CONSP (tem)) { /* Copy cell with menu-item name. */ - XCDR (elt) - = Fcons (XCAR (tem), XCDR (tem)); + XSETCDR (elt, + Fcons (XCAR (tem), XCDR (tem))); elt = XCDR (elt); tem = XCDR (elt); }; @@ -842,16 +899,16 @@ is not copied.") { /* Copy cell with binding and if the binding is a keymap, copy that. */ - XCDR (elt) - = Fcons (XCAR (tem), XCDR (tem)); + XSETCDR (elt, + Fcons (XCAR (tem), XCDR (tem))); elt = XCDR (elt); tem = XCAR (elt); - if (!(SYMBOLP (tem) || NILP (Fkeymapp (tem)))) - XCAR (elt) = Fcopy_keymap (tem); + if (CONSP (tem) && EQ (XCAR (tem), Qkeymap)) + XSETCAR (elt, Fcopy_keymap (tem)); tem = XCDR (elt); if (CONSP (tem) && CONSP (XCAR (tem))) /* Delete cache for key equivalences. */ - XCDR (elt) = XCDR (tem); + XSETCDR (elt, XCDR (tem)); } } else @@ -862,15 +919,15 @@ is not copied.") if (STRINGP (XCAR (tem))) { /* Copy the cell, since copy-alist didn't go this deep. */ - XCDR (elt) - = Fcons (XCAR (tem), XCDR (tem)); + XSETCDR (elt, + Fcons (XCAR (tem), XCDR (tem))); elt = XCDR (elt); tem = XCDR (elt); /* Also skip the optional menu help string. */ if (CONSP (tem) && STRINGP (XCAR (tem))) { - XCDR (elt) - = Fcons (XCAR (tem), XCDR (tem)); + XSETCDR (elt, + Fcons (XCAR (tem), XCDR (tem))); elt = XCDR (elt); tem = XCDR (elt); } @@ -880,17 +937,17 @@ is not copied.") && CONSP (XCAR (tem)) && (NILP (XCAR (XCAR (tem))) || VECTORP (XCAR (XCAR (tem))))) - XCDR (elt) = XCDR (tem); + XSETCDR (elt, XCDR (tem)); } if (CONSP (elt) - && ! SYMBOLP (XCDR (elt)) - && ! NILP (Fkeymapp (XCDR (elt)))) - XCDR (elt) = Fcopy_keymap (XCDR (elt)); + && CONSP (XCDR (elt)) + && EQ (XCAR (XCDR (elt)), Qkeymap)) + XSETCDR (elt, Fcopy_keymap (XCDR (elt))); } } } - + return copy; } @@ -899,26 +956,28 @@ is not copied.") /* GC is possible in this function if it autoloads a keymap. */ DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0, - "Args KEYMAP, KEY, DEF. Define key sequence KEY, in KEYMAP, as DEF.\n\ -KEYMAP is a keymap. KEY is a string or a vector of symbols and characters\n\ -meaning a sequence of keystrokes and events.\n\ -Non-ASCII characters with codes above 127 (such as ISO Latin-1)\n\ -can be included if you use a vector.\n\ -DEF is anything that can be a key's definition:\n\ - nil (means key is undefined in this keymap),\n\ - a command (a Lisp function suitable for interactive calling)\n\ - a string (treated as a keyboard macro),\n\ - a keymap (to define a prefix key),\n\ - a symbol. When the key is looked up, the symbol will stand for its\n\ - function definition, which should at that time be one of the above,\n\ - or another symbol whose function definition is used, etc.\n\ - a cons (STRING . DEFN), meaning that DEFN is the definition\n\ - (DEFN should be a valid definition in its own right),\n\ - or a cons (KEYMAP . CHAR), meaning use definition of CHAR in map KEYMAP.\n\ -\n\ -If KEYMAP is a sparse keymap, the pair binding KEY to DEF is added at\n\ -the front of KEYMAP.") - (keymap, key, def) + doc: /* Args KEYMAP, KEY, DEF. Define key sequence KEY, in KEYMAP, as DEF. +KEYMAP is a keymap. + +KEY is a string or a vector of symbols and characters meaning a +sequence of keystrokes and events. Non-ASCII characters with codes +above 127 (such as ISO Latin-1) can be included if you use a vector. + +DEF is anything that can be a key's definition: + nil (means key is undefined in this keymap), + a command (a Lisp function suitable for interactive calling) + a string (treated as a keyboard macro), + a keymap (to define a prefix key), + a symbol. When the key is looked up, the symbol will stand for its + function definition, which should at that time be one of the above, + or another symbol whose function definition is used, etc. + a cons (STRING . DEFN), meaning that DEFN is the definition + (DEFN should be a valid definition in its own right), + or a cons (KEYMAP . CHAR), meaning use definition of CHAR in map KEYMAP. + +If KEYMAP is a sparse keymap, the pair binding KEY to DEF is added at +the front of KEYMAP. */) + (keymap, key, def) Lisp_Object keymap; Lisp_Object key; Lisp_Object def; @@ -931,15 +990,20 @@ the front of KEYMAP.") int length; struct gcpro gcpro1, gcpro2, gcpro3; - keymap = get_keymap_1 (keymap, 1, 1); + keymap = get_keymap (keymap, 1, 1); if (!VECTORP (key) && !STRINGP (key)) - key = wrong_type_argument (Qarrayp, key); + key = wrong_type_argument (Qarrayp, key); length = XFASTINT (Flength (key)); if (length == 0) return Qnil; + /* Check for valid [remap COMMAND] bindings. */ + if (VECTORP (key) && EQ (AREF (key, 0), Qremap) + && (length != 2 || !SYMBOLP (AREF (key, 1)))) + wrong_type_argument (Qvectorp, key); + if (SYMBOLP (def) && !EQ (Vdefine_key_rebound_commands, Qt)) Vdefine_key_rebound_commands = Fcons (def, Vdefine_key_rebound_commands); @@ -958,6 +1022,9 @@ the front of KEYMAP.") if (CONSP (c) && lucid_event_type_list_p (c)) c = Fevent_convert_list (c); + if (SYMBOLP (c)) + silly_event_symbol_error (c); + if (INTEGERP (c) && (XINT (c) & meta_bit) && !metized) @@ -974,20 +1041,20 @@ the front of KEYMAP.") idx++; } - if (! INTEGERP (c) && ! SYMBOLP (c) && ! CONSP (c)) - error ("Key sequence contains invalid events"); + if (!INTEGERP (c) && !SYMBOLP (c) && !CONSP (c)) + error ("Key sequence contains invalid event"); if (idx == length) RETURN_UNGCPRO (store_in_keymap (keymap, c, def)); - cmd = get_keyelt (access_keymap (keymap, c, 0, 1), 1); + cmd = access_keymap (keymap, c, 0, 1, 1); /* If this key is undefined, make it a prefix. */ if (NILP (cmd)) cmd = define_as_prefix (keymap, c); - keymap = get_keymap_1 (cmd, 0, 1); - if (NILP (keymap)) + keymap = get_keymap (cmd, 0, 1); + if (!CONSP (keymap)) /* We must use Fkey_description rather than just passing key to error; key might be a vector, not a string. */ error ("Key sequence %s uses invalid prefix characters", @@ -995,25 +1062,38 @@ the front of KEYMAP.") } } -/* Value is number if KEY is too long; NIL if valid but has no definition. */ +/* This function may GC (it calls Fkey_binding). */ + +DEFUN ("remap-command", Fremap_command, Sremap_command, 1, 1, 0, + doc: /* Return the remapping for command COMMAND in current keymaps. +Returns nil if COMMAND is not remapped. */) + (command) + Lisp_Object command; +{ + /* This will GCPRO the command argument. */ + ASET (remap_command_vector, 1, command); + return Fkey_binding (remap_command_vector, Qnil, Qt); +} + +/* Value is number if KEY is too long; nil if valid but has no definition. */ /* GC is possible in this function if it autoloads a keymap. */ DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0, - "In keymap KEYMAP, look up key sequence KEY. Return the definition.\n\ -nil means undefined. See doc of `define-key' for kinds of definitions.\n\ -\n\ -A number as value means KEY is \"too long\";\n\ -that is, characters or symbols in it except for the last one\n\ -fail to be a valid sequence of prefix characters in KEYMAP.\n\ -The number is how many characters at the front of KEY\n\ -it takes to reach a non-prefix command.\n\ -\n\ -Normally, `lookup-key' ignores bindings for t, which act as default\n\ -bindings, used when nothing else in the keymap applies; this makes it\n\ -usable as a general function for probing keymaps. However, if the\n\ -third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will\n\ -recognize the default bindings, just as `read-key-sequence' does.") - (keymap, key, accept_default) + doc: /* In keymap KEYMAP, look up key sequence KEY. Return the definition. +nil means undefined. See doc of `define-key' for kinds of definitions. + +A number as value means KEY is "too long"; +that is, characters or symbols in it except for the last one +fail to be a valid sequence of prefix characters in KEYMAP. +The number is how many characters at the front of KEY +it takes to reach a non-prefix command. + +Normally, `lookup-key' ignores bindings for t, which act as default +bindings, used when nothing else in the keymap applies; this makes it +usable as a general function for probing keymaps. However, if the +third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will +recognize the default bindings, just as `read-key-sequence' does. */) + (keymap, key, accept_default) register Lisp_Object keymap; Lisp_Object key; Lisp_Object accept_default; @@ -1021,13 +1101,25 @@ recognize the default bindings, just as `read-key-sequence' does.") register int idx; register Lisp_Object cmd; register Lisp_Object c; - int metized = 0; int length; - int t_ok = ! NILP (accept_default); - int meta_bit; + int t_ok = !NILP (accept_default); struct gcpro gcpro1; - keymap = get_keymap_1 (keymap, 1, 1); + keymap = get_keymap (keymap, 1, 1); + + /* Perform command remapping initiated by Fremap_command directly. + This is strictly not necessary, but it is faster and it returns + nil instead of 1 if KEYMAP doesn't contain command remappings. */ + if (EQ (key, remap_command_vector)) + { + /* KEY has format [remap COMMAND]. + Lookup `remap' in KEYMAP; result is nil or a keymap containing + command remappings. Then lookup COMMAND in that keymap. */ + if ((keymap = access_keymap (keymap, Qremap, t_ok, 0, 1), !NILP (keymap)) + && (keymap = get_keymap (keymap, 0, 1), CONSP (keymap))) + return access_keymap (keymap, AREF (key, 1), t_ok, 0, 1); + return Qnil; + } if (!VECTORP (key) && !STRINGP (key)) key = wrong_type_argument (Qarrayp, key); @@ -1036,43 +1128,31 @@ recognize the default bindings, just as `read-key-sequence' does.") if (length == 0) return keymap; - if (VECTORP (key)) - meta_bit = meta_modifier; - else - meta_bit = 0x80; - GCPRO1 (key); idx = 0; while (1) { - c = Faref (key, make_number (idx)); + c = Faref (key, make_number (idx++)); if (CONSP (c) && lucid_event_type_list_p (c)) c = Fevent_convert_list (c); - if (INTEGERP (c) - && (XINT (c) & meta_bit) - && !metized) - { - c = meta_prefix_char; - metized = 1; - } - else - { - if (INTEGERP (c)) - XSETINT (c, XINT (c) & ~meta_bit); + /* Turn the 8th bit of string chars into a meta modifier. */ + if (XINT (c) & 0x80 && STRINGP (key)) + XSETINT (c, (XINT (c) | meta_modifier) & ~0x80); - metized = 0; - idx++; - } + /* Allow string since binding for `menu-bar-select-buffer' + includes the buffer name in the key sequence. */ + if (!INTEGERP (c) && !SYMBOLP (c) && !CONSP (c) && !STRINGP (c)) + error ("Key sequence contains invalid event"); - cmd = get_keyelt (access_keymap (keymap, c, t_ok, 0), 1); + cmd = access_keymap (keymap, c, t_ok, 0, 1); if (idx == length) RETURN_UNGCPRO (cmd); - keymap = get_keymap_1 (cmd, 0, 1); - if (NILP (keymap)) + keymap = get_keymap (cmd, 0, 1); + if (!CONSP (keymap)) RETURN_UNGCPRO (make_number (idx)); QUIT; @@ -1087,44 +1167,13 @@ static Lisp_Object define_as_prefix (keymap, c) Lisp_Object keymap, c; { - Lisp_Object inherit, cmd; + Lisp_Object cmd; cmd = Fmake_sparse_keymap (Qnil); /* If this key is defined as a prefix in an inherited keymap, make it a prefix in this map, and make its definition inherit the other prefix definition. */ - inherit = access_keymap (keymap, c, 0, 0); -#if 0 - /* This code is needed to do the right thing in the following case: - keymap A inherits from B, - you define KEY as a prefix in A, - then later you define KEY as a prefix in B. - We want the old prefix definition in A to inherit from that in B. - It is hard to do that retroactively, so this code - creates the prefix in B right away. - - But it turns out that this code causes problems immediately - when the prefix in A is defined: it causes B to define KEY - as a prefix with no subcommands. - - So I took out this code. */ - if (NILP (inherit)) - { - /* If there's an inherited keymap - and it doesn't define this key, - make it define this key. */ - Lisp_Object tail; - - for (tail = Fcdr (keymap); CONSP (tail); tail = XCDR (tail)) - if (EQ (XCAR (tail), Qkeymap)) - break; - - if (!NILP (tail)) - inherit = define_as_prefix (tail, c); - } -#endif - - cmd = nconc2 (cmd, inherit); + cmd = nconc2 (cmd, access_keymap (keymap, c, 0, 0, 0)); store_in_keymap (keymap, c, cmd); return cmd; @@ -1144,6 +1193,52 @@ append_key (key_sequence, key) return Fvconcat (2, args); } +/* Given a event type C which is a symbol, + signal an error if is a mistake such as RET or M-RET or C-DEL, etc. */ + +static void +silly_event_symbol_error (c) + Lisp_Object c; +{ + Lisp_Object parsed, base, name, assoc; + int modifiers; + + parsed = parse_modifiers (c); + modifiers = (int) XUINT (XCAR (XCDR (parsed))); + base = XCAR (parsed); + name = Fsymbol_name (base); + /* This alist includes elements such as ("RET" . "\\r"). */ + assoc = Fassoc (name, exclude_keys); + + if (! NILP (assoc)) + { + char new_mods[sizeof ("\\A-\\C-\\H-\\M-\\S-\\s-")]; + char *p = new_mods; + Lisp_Object keystring; + if (modifiers & alt_modifier) + { *p++ = '\\'; *p++ = 'A'; *p++ = '-'; } + if (modifiers & ctrl_modifier) + { *p++ = '\\'; *p++ = 'C'; *p++ = '-'; } + if (modifiers & hyper_modifier) + { *p++ = '\\'; *p++ = 'H'; *p++ = '-'; } + if (modifiers & meta_modifier) + { *p++ = '\\'; *p++ = 'M'; *p++ = '-'; } + if (modifiers & shift_modifier) + { *p++ = '\\'; *p++ = 'S'; *p++ = '-'; } + if (modifiers & super_modifier) + { *p++ = '\\'; *p++ = 's'; *p++ = '-'; } + *p = 0; + + c = reorder_modifiers (c); + keystring = concat2 (build_string (new_mods), XCDR (assoc)); + + error ((modifiers & ~meta_modifier + ? "To bind the key %s, use [?%s], not [%s]" + : "To bind the key %s, use \"%s\", not [%s]"), + XSYMBOL (c)->name->data, XSTRING (keystring)->data, + XSYMBOL (c)->name->data); + } +} /* Global, local, and minor mode keymap stuff. */ @@ -1194,8 +1289,8 @@ current_minor_maps (modeptr, mapptr) alist = XCDR (alist)) if ((assoc = XCAR (alist), CONSP (assoc)) && (var = XCAR (assoc), SYMBOLP (var)) - && (val = find_symbol_value (var), ! EQ (val, Qunbound)) - && ! NILP (val)) + && (val = find_symbol_value (var), !EQ (val, Qunbound)) + && !NILP (val)) { Lisp_Object temp; @@ -1206,23 +1301,25 @@ current_minor_maps (modeptr, mapptr) { val = assq_no_quit (var, lists[0]); if (!NILP (val)) - break; + continue; } if (i >= cmm_size) { Lisp_Object *newmodes, *newmaps; + /* Use malloc/realloc here. See the comment above + this function. */ if (cmm_maps) { BLOCK_INPUT; cmm_size *= 2; newmodes = (Lisp_Object *) realloc (cmm_modes, - cmm_size * sizeof (Lisp_Object)); + cmm_size * sizeof *newmodes); newmaps = (Lisp_Object *) realloc (cmm_maps, - cmm_size * sizeof (Lisp_Object)); + cmm_size * sizeof *newmaps); UNBLOCK_INPUT; } else @@ -1230,18 +1327,18 @@ current_minor_maps (modeptr, mapptr) BLOCK_INPUT; cmm_size = 30; newmodes - = (Lisp_Object *) malloc (cmm_size * sizeof (Lisp_Object)); + = (Lisp_Object *) malloc (cmm_size * sizeof *newmodes); newmaps - = (Lisp_Object *) malloc (cmm_size * sizeof (Lisp_Object)); + = (Lisp_Object *) malloc (cmm_size * sizeof *newmaps); UNBLOCK_INPUT; } - if (newmaps && newmodes) - { - cmm_modes = newmodes; - cmm_maps = newmaps; - } - else + if (newmodes) + cmm_modes = newmodes; + if (newmaps) + cmm_maps = newmaps; + + if (newmodes == NULL || newmaps == NULL) break; } @@ -1262,20 +1359,66 @@ current_minor_maps (modeptr, mapptr) return i; } +DEFUN ("current-active-maps", Fcurrent_active_maps, Scurrent_active_maps, + 0, 1, 0, + doc: /* Return a list of the currently active keymaps. +OLP if non-nil indicates that we should obey `overriding-local-map' and +`overriding-terminal-local-map'. */) + (olp) + Lisp_Object olp; +{ + Lisp_Object keymaps = Fcons (current_global_map, Qnil); + + if (!NILP (olp)) + { + if (!NILP (Voverriding_local_map)) + keymaps = Fcons (Voverriding_local_map, keymaps); + if (!NILP (current_kboard->Voverriding_terminal_local_map)) + keymaps = Fcons (current_kboard->Voverriding_terminal_local_map, keymaps); + } + if (NILP (XCDR (keymaps))) + { + Lisp_Object local; + Lisp_Object *maps; + int nmaps, i; + + local = get_local_map (PT, current_buffer, Qlocal_map); + if (!NILP (local)) + keymaps = Fcons (local, keymaps); + + nmaps = current_minor_maps (0, &maps); + + for (i = --nmaps; i >= 0; i--) + if (!NILP (maps[i])) + keymaps = Fcons (maps[i], keymaps); + + local = get_local_map (PT, current_buffer, Qkeymap); + if (!NILP (local)) + keymaps = Fcons (local, keymaps); + } + + return keymaps; +} + /* GC is possible in this function if it autoloads a keymap. */ -DEFUN ("key-binding", Fkey_binding, Skey_binding, 1, 2, 0, - "Return the binding for command KEY in current keymaps.\n\ -KEY is a string or vector, a sequence of keystrokes.\n\ -The binding is probably a symbol with a function definition.\n\ -\n\ -Normally, `key-binding' ignores bindings for t, which act as default\n\ -bindings, used when nothing else in the keymap applies; this makes it\n\ -usable as a general function for probing keymaps. However, if the\n\ -optional second argument ACCEPT-DEFAULT is non-nil, `key-binding' does\n\ -recognize the default bindings, just as `read-key-sequence' does.") - (key, accept_default) - Lisp_Object key, accept_default; +DEFUN ("key-binding", Fkey_binding, Skey_binding, 1, 3, 0, + doc: /* Return the binding for command KEY in current keymaps. +KEY is a string or vector, a sequence of keystrokes. +The binding is probably a symbol with a function definition. + +Normally, `key-binding' ignores bindings for t, which act as default +bindings, used when nothing else in the keymap applies; this makes it +usable as a general function for probing keymaps. However, if the +optional second argument ACCEPT-DEFAULT is non-nil, `key-binding' does +recognize the default bindings, just as `read-key-sequence' does. + +Like the normal command loop, `key-binding' will remap the command +resulting from looking up KEY by looking up the command in the +currrent keymaps. However, if the optional third argument NO-REMAP +is non-nil, `key-binding' returns the unmapped command. */) + (key, accept_default, no_remap) + Lisp_Object key, accept_default, no_remap; { Lisp_Object *maps, value; int nmaps, i; @@ -1288,18 +1431,26 @@ recognize the default bindings, just as `read-key-sequence' does.") value = Flookup_key (current_kboard->Voverriding_terminal_local_map, key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } else if (!NILP (Voverriding_local_map)) { value = Flookup_key (Voverriding_local_map, key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } else { Lisp_Object local; + local = get_local_map (PT, current_buffer, Qkeymap); + if (! NILP (local)) + { + value = Flookup_key (local, key, accept_default); + if (! NILP (value) && !INTEGERP (value)) + goto done; + } + nmaps = current_minor_maps (0, &maps); /* Note that all these maps are GCPRO'd in the places where we found them. */ @@ -1309,45 +1460,48 @@ recognize the default bindings, just as `read-key-sequence' does.") { value = Flookup_key (maps[i], key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } - local = get_local_map (PT, current_buffer, keymap); - if (! NILP (local)) - { - value = Flookup_key (local, key, accept_default); - if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); - } - - local = get_local_map (PT, current_buffer, local_map); - + local = get_local_map (PT, current_buffer, Qlocal_map); if (! NILP (local)) { value = Flookup_key (local, key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } } value = Flookup_key (current_global_map, key, accept_default); + + done: UNGCPRO; - if (! NILP (value) && !INTEGERP (value)) - return value; + if (NILP (value) || INTEGERP (value)) + return Qnil; + + /* If the result of the ordinary keymap lookup is an interactive + command, look for a key binding (ie. remapping) for that command. */ + + if (NILP (no_remap) && SYMBOLP (value)) + { + Lisp_Object value1; + if (value1 = Fremap_command (value), !NILP (value1)) + value = value1; + } - return Qnil; + return value; } /* GC is possible in this function if it autoloads a keymap. */ DEFUN ("local-key-binding", Flocal_key_binding, Slocal_key_binding, 1, 2, 0, - "Return the binding for command KEYS in current local keymap only.\n\ -KEYS is a string, a sequence of keystrokes.\n\ -The binding is probably a symbol with a function definition.\n\ -\n\ -If optional argument ACCEPT-DEFAULT is non-nil, recognize default\n\ -bindings; see the description of `lookup-key' for more details about this.") - (keys, accept_default) + doc: /* Return the binding for command KEYS in current local keymap only. +KEYS is a string, a sequence of keystrokes. +The binding is probably a symbol with a function definition. + +If optional argument ACCEPT-DEFAULT is non-nil, recognize default +bindings; see the description of `lookup-key' for more details about this. */) + (keys, accept_default) Lisp_Object keys, accept_default; { register Lisp_Object map; @@ -1360,15 +1514,15 @@ bindings; see the description of `lookup-key' for more details about this.") /* GC is possible in this function if it autoloads a keymap. */ DEFUN ("global-key-binding", Fglobal_key_binding, Sglobal_key_binding, 1, 2, 0, - "Return the binding for command KEYS in current global keymap only.\n\ -KEYS is a string, a sequence of keystrokes.\n\ -The binding is probably a symbol with a function definition.\n\ -This function's return values are the same as those of lookup-key\n\ -\(which see).\n\ -\n\ -If optional argument ACCEPT-DEFAULT is non-nil, recognize default\n\ -bindings; see the description of `lookup-key' for more details about this.") - (keys, accept_default) + doc: /* Return the binding for command KEYS in current global keymap only. +KEYS is a string, a sequence of keystrokes. +The binding is probably a symbol with a function definition. +This function's return values are the same as those of lookup-key +\(which see). + +If optional argument ACCEPT-DEFAULT is non-nil, recognize default +bindings; see the description of `lookup-key' for more details about this. */) + (keys, accept_default) Lisp_Object keys, accept_default; { return Flookup_key (current_global_map, keys, accept_default); @@ -1377,18 +1531,18 @@ bindings; see the description of `lookup-key' for more details about this.") /* GC is possible in this function if it autoloads a keymap. */ DEFUN ("minor-mode-key-binding", Fminor_mode_key_binding, Sminor_mode_key_binding, 1, 2, 0, - "Find the visible minor mode bindings of KEY.\n\ -Return an alist of pairs (MODENAME . BINDING), where MODENAME is the\n\ -the symbol which names the minor mode binding KEY, and BINDING is\n\ -KEY's definition in that mode. In particular, if KEY has no\n\ -minor-mode bindings, return nil. If the first binding is a\n\ -non-prefix, all subsequent bindings will be omitted, since they would\n\ -be ignored. Similarly, the list doesn't include non-prefix bindings\n\ -that come after prefix bindings.\n\ -\n\ -If optional argument ACCEPT-DEFAULT is non-nil, recognize default\n\ -bindings; see the description of `lookup-key' for more details about this.") - (key, accept_default) + doc: /* Find the visible minor mode bindings of KEY. +Return an alist of pairs (MODENAME . BINDING), where MODENAME is the +the symbol which names the minor mode binding KEY, and BINDING is +KEY's definition in that mode. In particular, if KEY has no +minor-mode bindings, return nil. If the first binding is a +non-prefix, all subsequent bindings will be omitted, since they would +be ignored. Similarly, the list doesn't include non-prefix bindings +that come after prefix bindings. + +If optional argument ACCEPT-DEFAULT is non-nil, recognize default +bindings; see the description of `lookup-key' for more details about this. */) + (key, accept_default) Lisp_Object key, accept_default; { Lisp_Object *modes, *maps; @@ -1405,11 +1559,11 @@ bindings; see the description of `lookup-key' for more details about this.") GCPRO2 (key, binding); for (i = j = 0; i < nmaps; i++) - if (! NILP (maps[i]) - && ! NILP (binding = Flookup_key (maps[i], key, accept_default)) + if (!NILP (maps[i]) + && !NILP (binding = Flookup_key (maps[i], key, accept_default)) && !INTEGERP (binding)) { - if (! NILP (get_keymap (binding))) + if (KEYMAPP (binding)) maps[j++] = Fcons (modes[i], binding); else if (j == 0) RETURN_UNGCPRO (Fcons (Fcons (modes[i], binding), Qnil)); @@ -1420,14 +1574,14 @@ bindings; see the description of `lookup-key' for more details about this.") } DEFUN ("define-prefix-command", Fdefine_prefix_command, Sdefine_prefix_command, 1, 3, 0, - "Define COMMAND as a prefix command. COMMAND should be a symbol.\n\ -A new sparse keymap is stored as COMMAND's function definition and its value.\n\ -If a second optional argument MAPVAR is given, the map is stored as\n\ -its value instead of as COMMAND's value; but COMMAND is still defined\n\ -as a function.\n\ -The third optional argument NAME, if given, supplies a menu name\n\ -string for the map. This is required to use the keymap as a menu.") - (command, mapvar, name) + doc: /* Define COMMAND as a prefix command. COMMAND should be a symbol. +A new sparse keymap is stored as COMMAND's function definition and its value. +If a second optional argument MAPVAR is given, the map is stored as +its value instead of as COMMAND's value; but COMMAND is still defined +as a function. +The third optional argument NAME, if given, supplies a menu name +string for the map. This is required to use the keymap as a menu. */) + (command, mapvar, name) Lisp_Object command, mapvar, name; { Lisp_Object map; @@ -1441,24 +1595,24 @@ string for the map. This is required to use the keymap as a menu.") } DEFUN ("use-global-map", Fuse_global_map, Suse_global_map, 1, 1, 0, - "Select KEYMAP as the global keymap.") - (keymap) + doc: /* Select KEYMAP as the global keymap. */) + (keymap) Lisp_Object keymap; { - keymap = get_keymap (keymap); + keymap = get_keymap (keymap, 1, 1); current_global_map = keymap; return Qnil; } DEFUN ("use-local-map", Fuse_local_map, Suse_local_map, 1, 1, 0, - "Select KEYMAP as the local keymap.\n\ -If KEYMAP is nil, that means no local keymap.") - (keymap) + doc: /* Select KEYMAP as the local keymap. +If KEYMAP is nil, that means no local keymap. */) + (keymap) Lisp_Object keymap; { if (!NILP (keymap)) - keymap = get_keymap (keymap); + keymap = get_keymap (keymap, 1, 1); current_buffer->keymap = keymap; @@ -1466,22 +1620,22 @@ If KEYMAP is nil, that means no local keymap.") } DEFUN ("current-local-map", Fcurrent_local_map, Scurrent_local_map, 0, 0, 0, - "Return current buffer's local keymap, or nil if it has none.") - () + doc: /* Return current buffer's local keymap, or nil if it has none. */) + () { return current_buffer->keymap; } DEFUN ("current-global-map", Fcurrent_global_map, Scurrent_global_map, 0, 0, 0, - "Return the current global keymap.") - () + doc: /* Return the current global keymap. */) + () { return current_global_map; } DEFUN ("current-minor-mode-maps", Fcurrent_minor_mode_maps, Scurrent_minor_mode_maps, 0, 0, 0, - "Return a list of keymaps for the minor modes of the current buffer.") - () + doc: /* Return a list of keymaps for the minor modes of the current buffer. */) + () { Lisp_Object *maps; int nmaps = current_minor_maps (0, &maps); @@ -1491,19 +1645,76 @@ DEFUN ("current-minor-mode-maps", Fcurrent_minor_mode_maps, Scurrent_minor_mode_ /* Help functions for describing and documenting keymaps. */ -static void accessible_keymaps_char_table (); + +static void +accessible_keymaps_1 (key, cmd, maps, tail, thisseq, is_metized) + Lisp_Object maps, tail, thisseq, key, cmd; + int is_metized; /* If 1, `key' is assumed to be INTEGERP. */ +{ + Lisp_Object tem; + + cmd = get_keyelt (cmd, 0); + if (NILP (cmd)) + return; + + tem = get_keymap (cmd, 0, 0); + if (CONSP (tem)) + { + cmd = tem; + /* Ignore keymaps that are already added to maps. */ + tem = Frassq (cmd, maps); + if (NILP (tem)) + { + /* If the last key in thisseq is meta-prefix-char, + turn it into a meta-ized keystroke. We know + that the event we're about to append is an + ascii keystroke since we're processing a + keymap table. */ + if (is_metized) + { + int meta_bit = meta_modifier; + Lisp_Object last = make_number (XINT (Flength (thisseq)) - 1); + tem = Fcopy_sequence (thisseq); + + Faset (tem, last, make_number (XINT (key) | meta_bit)); + + /* This new sequence is the same length as + thisseq, so stick it in the list right + after this one. */ + XSETCDR (tail, + Fcons (Fcons (tem, cmd), XCDR (tail))); + } + else + { + tem = append_key (thisseq, key); + nconc2 (tail, Fcons (Fcons (tem, cmd), Qnil)); + } + } + } +} + +static void +accessible_keymaps_char_table (args, index, cmd) + Lisp_Object args, index, cmd; +{ + accessible_keymaps_1 (index, cmd, + XCAR (XCAR (args)), + XCAR (XCDR (args)), + XCDR (XCDR (args)), + XINT (XCDR (XCAR (args)))); +} /* This function cannot GC. */ DEFUN ("accessible-keymaps", Faccessible_keymaps, Saccessible_keymaps, - 1, 2, 0, - "Find all keymaps accessible via prefix characters from KEYMAP.\n\ -Returns a list of elements of the form (KEYS . MAP), where the sequence\n\ -KEYS starting from KEYMAP gets you to MAP. These elements are ordered\n\ -so that the KEYS increase in length. The first element is ([] . KEYMAP).\n\ -An optional argument PREFIX, if non-nil, should be a key sequence;\n\ -then the value includes only maps for prefixes that start with PREFIX.") - (keymap, prefix) + 1, 2, 0, + doc: /* Find all keymaps accessible via prefix characters from KEYMAP. +Returns a list of elements of the form (KEYS . MAP), where the sequence +KEYS starting from KEYMAP gets you to MAP. These elements are ordered +so that the KEYS increase in length. The first element is ([] . KEYMAP). +An optional argument PREFIX, if non-nil, should be a key sequence; +then the value includes only maps for prefixes that start with PREFIX. */) + (keymap, prefix) Lisp_Object keymap, prefix; { Lisp_Object maps, good_maps, tail; @@ -1523,8 +1734,8 @@ then the value includes only maps for prefixes that start with PREFIX.") /* Flookup_key may give us nil, or a number, if the prefix is not defined in this particular map. It might even give us a list that isn't a keymap. */ - tem = get_keymap_1 (tem, 0, 0); - if (!NILP (tem)) + tem = get_keymap (tem, 0, 0); + if (CONSP (tem)) { /* Convert PREFIX to a vector now, so that later on we don't have to deal with the possibility of a string. */ @@ -1541,7 +1752,7 @@ then the value includes only maps for prefixes that start with PREFIX.") FETCH_STRING_CHAR_ADVANCE (c, prefix, i, i_byte); if (SINGLE_BYTE_CHAR_P (c) && (c & 0200)) c ^= 0200 | meta_modifier; - XVECTOR (copy)->contents[i_before] = make_number (c); + ASET (copy, i_before, make_number (c)); } prefix = copy; } @@ -1552,7 +1763,7 @@ then the value includes only maps for prefixes that start with PREFIX.") } else maps = Fcons (Fcons (Fmake_vector (make_number (0), Qnil), - get_keymap (keymap)), + get_keymap (keymap, 1, 0)), Qnil); /* For each map in the list maps, @@ -1590,7 +1801,8 @@ then the value includes only maps for prefixes that start with PREFIX.") Lisp_Object indices[3]; map_char_table (accessible_keymaps_char_table, Qnil, - elt, Fcons (maps, Fcons (tail, thisseq)), + elt, Fcons (Fcons (maps, make_number (is_metized)), + Fcons (tail, thisseq)), 0, indices); } else if (VECTORP (elt)) @@ -1598,90 +1810,16 @@ then the value includes only maps for prefixes that start with PREFIX.") register int i; /* Vector keymap. Scan all the elements. */ - for (i = 0; i < XVECTOR (elt)->size; i++) - { - register Lisp_Object tem; - register Lisp_Object cmd; - - cmd = get_keyelt (XVECTOR (elt)->contents[i], 0); - if (NILP (cmd)) continue; - tem = Fkeymapp (cmd); - if (!NILP (tem)) - { - cmd = get_keymap (cmd); - /* Ignore keymaps that are already added to maps. */ - tem = Frassq (cmd, maps); - if (NILP (tem)) - { - /* If the last key in thisseq is meta-prefix-char, - turn it into a meta-ized keystroke. We know - that the event we're about to append is an - ascii keystroke since we're processing a - keymap table. */ - if (is_metized) - { - int meta_bit = meta_modifier; - tem = Fcopy_sequence (thisseq); - - Faset (tem, last, make_number (i | meta_bit)); - - /* This new sequence is the same length as - thisseq, so stick it in the list right - after this one. */ - XCDR (tail) - = Fcons (Fcons (tem, cmd), XCDR (tail)); - } - else - { - tem = append_key (thisseq, make_number (i)); - nconc2 (tail, Fcons (Fcons (tem, cmd), Qnil)); - } - } - } - } + for (i = 0; i < ASIZE (elt); i++) + accessible_keymaps_1 (make_number (i), AREF (elt, i), + maps, tail, thisseq, is_metized); + } else if (CONSP (elt)) - { - register Lisp_Object cmd, tem; - - cmd = get_keyelt (XCDR (elt), 0); - /* Ignore definitions that aren't keymaps themselves. */ - tem = Fkeymapp (cmd); - if (!NILP (tem)) - { - /* Ignore keymaps that have been seen already. */ - cmd = get_keymap (cmd); - tem = Frassq (cmd, maps); - if (NILP (tem)) - { - /* Let elt be the event defined by this map entry. */ - elt = XCAR (elt); - - /* If the last key in thisseq is meta-prefix-char, and - this entry is a binding for an ascii keystroke, - turn it into a meta-ized keystroke. */ - if (is_metized && INTEGERP (elt)) - { - Lisp_Object element; - - element = thisseq; - tem = Fvconcat (1, &element); - XSETFASTINT (XVECTOR (tem)->contents[XINT (last)], - XINT (elt) | meta_modifier); - - /* This new sequence is the same length as - thisseq, so stick it in the list right - after this one. */ - XCDR (tail) - = Fcons (Fcons (tem, cmd), XCDR (tail)); - } - else - nconc2 (tail, - Fcons (Fcons (append_key (thisseq, elt), cmd), - Qnil)); - } - } - } + accessible_keymaps_1 (XCAR (elt), XCDR (elt), + maps, tail, thisseq, + is_metized && INTEGERP (XCAR (elt))); + } } @@ -1715,50 +1853,22 @@ then the value includes only maps for prefixes that start with PREFIX.") return Fnreverse (good_maps); } - -static void -accessible_keymaps_char_table (args, index, cmd) - Lisp_Object args, index, cmd; -{ - Lisp_Object tem; - Lisp_Object maps, tail, thisseq; - - if (NILP (cmd)) - return; - - maps = XCAR (args); - tail = XCAR (XCDR (args)); - thisseq = XCDR (XCDR (args)); - - tem = Fkeymapp (cmd); - if (!NILP (tem)) - { - cmd = get_keymap (cmd); - /* Ignore keymaps that are already added to maps. */ - tem = Frassq (cmd, maps); - if (NILP (tem)) - { - tem = append_key (thisseq, index); - nconc2 (tail, Fcons (Fcons (tem, cmd), Qnil)); - } - } -} Lisp_Object Qsingle_key_description, Qkey_description; /* This function cannot GC. */ DEFUN ("key-description", Fkey_description, Skey_description, 1, 1, 0, - "Return a pretty description of key-sequence KEYS.\n\ -Control characters turn into \"C-foo\" sequences, meta into \"M-foo\"\n\ -spaces are put between sequence elements, etc.") - (keys) + doc: /* Return a pretty description of key-sequence KEYS. +Control characters turn into "C-foo" sequences, meta into "M-foo" +spaces are put between sequence elements, etc. */) + (keys) Lisp_Object keys; { - int len; + int len = 0; int i, i_byte; Lisp_Object sep; - Lisp_Object *args; + Lisp_Object *args = NULL; if (STRINGP (keys)) { @@ -1772,7 +1882,7 @@ spaces are put between sequence elements, etc.") FETCH_STRING_CHAR_ADVANCE (c, keys, i, i_byte); if (SINGLE_BYTE_CHAR_P (c) && (c & 0200)) c ^= 0200 | meta_modifier; - XSETFASTINT (XVECTOR (vector)->contents[i_before], c); + XSETFASTINT (AREF (vector, i_before), c); } keys = vector; } @@ -1790,7 +1900,7 @@ spaces are put between sequence elements, etc.") for (i = 0; i < len; i++) { - args[i * 2] = Fsingle_key_description (XVECTOR (keys)->contents[i]); + args[i * 2] = Fsingle_key_description (AREF (keys, i), Qnil); args[i * 2 + 1] = sep; } } @@ -1807,7 +1917,7 @@ spaces are put between sequence elements, etc.") for (i = 0; i < len; i++) { - args[i * 2] = Fsingle_key_description (XCAR (keys)); + args[i * 2] = Fsingle_key_description (XCAR (keys), Qnil); args[i * 2 + 1] = sep; keys = XCDR (keys); } @@ -1815,16 +1925,23 @@ spaces are put between sequence elements, etc.") else keys = wrong_type_argument (Qarrayp, keys); + if (len == 0) + return empty_string; return Fconcat (len * 2 - 1, args); } char * -push_key_description (c, p) +push_key_description (c, p, force_multibyte) register unsigned int c; register char *p; + int force_multibyte; { + unsigned c2; + /* Clear all the meaningless bits above the meta bit. */ c &= meta_modifier | ~ - meta_modifier; + c2 = c & ~(alt_modifier | ctrl_modifier | hyper_modifier + | meta_modifier | shift_modifier | super_modifier); if (c & alt_modifier) { @@ -1832,11 +1949,12 @@ push_key_description (c, p) *p++ = '-'; c -= alt_modifier; } - if (c & ctrl_modifier) + if ((c & ctrl_modifier) != 0 + || (c2 < ' ' && c2 != 27 && c2 != '\t' && c2 != Ctl ('M'))) { *p++ = 'C'; *p++ = '-'; - c -= ctrl_modifier; + c &= ~ctrl_modifier; } if (c & hyper_modifier) { @@ -1884,8 +2002,7 @@ push_key_description (c, p) } else { - *p++ = 'C'; - *p++ = '-'; + /* `C-' already added above. */ if (c > 0 && c <= Ctl ('Z')) *p++ = c + 0140; else @@ -1906,16 +2023,23 @@ push_key_description (c, p) } else if (c < 128 || (NILP (current_buffer->enable_multibyte_characters) - && SINGLE_BYTE_CHAR_P (c))) - *p++ = c; + && SINGLE_BYTE_CHAR_P (c) + && !force_multibyte)) + { + *p++ = c; + } else { - if (! NILP (current_buffer->enable_multibyte_characters)) - c = unibyte_char_to_multibyte (c); - - if (NILP (current_buffer->enable_multibyte_characters) - || SINGLE_BYTE_CHAR_P (c) - || ! char_valid_p (c, 0)) + int valid_p = SINGLE_BYTE_CHAR_P (c) || char_valid_p (c, 0); + + if (force_multibyte && valid_p) + { + if (SINGLE_BYTE_CHAR_P (c)) + c = unibyte_char_to_multibyte (c); + p += CHAR_STRING (c, p); + } + else if (NILP (current_buffer->enable_multibyte_characters) + || valid_p) { int bit_offset; *p++ = '\\'; @@ -1927,21 +2051,22 @@ push_key_description (c, p) } } else - { - p += CHAR_STRING (c, p); - } + p += CHAR_STRING (c, p); } - return p; + return p; } /* This function cannot GC. */ -DEFUN ("single-key-description", Fsingle_key_description, Ssingle_key_description, 1, 1, 0, - "Return a pretty description of command character KEY.\n\ -Control characters turn into C-whatever, etc.") - (key) - Lisp_Object key; +DEFUN ("single-key-description", Fsingle_key_description, + Ssingle_key_description, 1, 2, 0, + doc: /* Return a pretty description of command character KEY. +Control characters turn into C-whatever, etc. +Optional argument NO-ANGLES non-nil means don't put angle brackets +around function keys and event symbols. */) + (key, no_angles) + Lisp_Object key, no_angles; { if (CONSP (key) && lucid_event_type_list_p (key)) key = Fevent_convert_list (key); @@ -1966,27 +2091,45 @@ Control characters turn into C-whatever, etc.") /* Handle a generic character. */ Lisp_Object name; name = CHARSET_TABLE_INFO (charset, CHARSET_LONG_NAME_IDX); - CHECK_STRING (name, 0); + CHECK_STRING (name); return concat2 (build_string ("Character set "), name); } else { - char tem[KEY_DESCRIPTION_SIZE]; - - *push_key_description (XUINT (key), tem) = 0; - return build_string (tem); + char tem[KEY_DESCRIPTION_SIZE], *end; + int nbytes, nchars; + Lisp_Object string; + + end = push_key_description (XUINT (key), tem, 1); + nbytes = end - tem; + nchars = multibyte_chars_in_text (tem, nbytes); + if (nchars == nbytes) + { + *end = '\0'; + string = build_string (tem); + } + else + string = make_multibyte_string (tem, nchars, nbytes); + return string; } } else if (SYMBOLP (key)) /* Function key or event-symbol */ { - char *buffer = (char *) alloca (STRING_BYTES (XSYMBOL (key)->name) + 5); - sprintf (buffer, "<%s>", XSYMBOL (key)->name->data); - return build_string (buffer); + if (NILP (no_angles)) + { + char *buffer + = (char *) alloca (STRING_BYTES (XSYMBOL (key)->name) + 5); + sprintf (buffer, "<%s>", XSYMBOL (key)->name->data); + return build_string (buffer); + } + else + return Fsymbol_name (key); } else if (STRINGP (key)) /* Buffer names in the menubar. */ return Fcopy_sequence (key); else error ("KEY must be an integer, cons, symbol, or string"); + return Qnil; } char * @@ -2012,22 +2155,22 @@ push_text_char_description (c, p) } else *p++ = c; - return p; + return p; } /* This function cannot GC. */ DEFUN ("text-char-description", Ftext_char_description, Stext_char_description, 1, 1, 0, - "Return a pretty description of file-character CHARACTER.\n\ -Control characters turn into \"^char\", etc.") - (character) + doc: /* Return a pretty description of file-character CHARACTER. +Control characters turn into "^char", etc. */) + (character) Lisp_Object character; { /* Currently MAX_MULTIBYTE_LENGTH is 4 (< 6). */ unsigned char str[6]; int c; - CHECK_NUMBER (character, 0); + CHECK_NUMBER (character); c = XINT (character); if (!SINGLE_BYTE_CHAR_P (c)) @@ -2069,79 +2212,60 @@ ascii_sequence_p (seq) /* where-is - finding a command in a set of keymaps. */ +static Lisp_Object where_is_internal (); static Lisp_Object where_is_internal_1 (); static void where_is_internal_2 (); +/* Like Flookup_key, but uses a list of keymaps SHADOW instead of a single map. + Returns the first non-nil binding found in any of those maps. */ + +static Lisp_Object +shadow_lookup (shadow, key, flag) + Lisp_Object shadow, key, flag; +{ + Lisp_Object tail, value; + + for (tail = shadow; CONSP (tail); tail = XCDR (tail)) + { + value = Flookup_key (XCAR (tail), key, flag); + if (!NILP (value) && !NATNUMP (value)) + return value; + } + return Qnil; +} + /* This function can GC if Flookup_key autoloads any keymaps. */ -DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 4, 0, - "Return list of keys that invoke DEFINITION.\n\ -If KEYMAP is non-nil, search only KEYMAP and the global keymap.\n\ -If KEYMAP is nil, search all the currently active keymaps.\n\ -\n\ -If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found,\n\ -rather than a list of all possible key sequences.\n\ -If FIRSTONLY is the symbol `non-ascii', return the first binding found,\n\ -no matter what it is.\n\ -If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters,\n\ -and entirely reject menu bindings.\n\ -\n\ -If optional 4th arg NOINDIRECT is non-nil, don't follow indirections\n\ -to other keymaps or slots. This makes it possible to search for an\n\ -indirect definition itself.") - (definition, xkeymap, firstonly, noindirect) - Lisp_Object definition, xkeymap; - Lisp_Object firstonly, noindirect; +static Lisp_Object +where_is_internal (definition, keymaps, firstonly, noindirect, no_remap) + Lisp_Object definition, keymaps; + Lisp_Object firstonly, noindirect, no_remap; { - Lisp_Object maps; + Lisp_Object maps = Qnil; Lisp_Object found, sequences; - Lisp_Object keymap1; - int keymap_specified = !NILP (xkeymap); struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; /* 1 means ignore all menu bindings entirely. */ int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii); - /* Find keymaps accessible from `keymap' or the current - context. But don't muck with the value of `keymap', - because `where_is_internal_1' uses it to check for - shadowed bindings. */ - keymap1 = xkeymap; - if (! keymap_specified) - keymap1 = get_local_map (PT, current_buffer, keymap); - - if (!NILP (keymap1)) - maps = nconc2 (Faccessible_keymaps (get_keymap (keymap1), Qnil), - Faccessible_keymaps (get_keymap (current_global_map), - Qnil)); - else + /* If this command is remapped, then it has no key bindings + of its own. */ + if (NILP (no_remap) && SYMBOLP (definition)) { - keymap1 = xkeymap; - if (! keymap_specified) - keymap1 = get_local_map (PT, current_buffer, local_map); - - if (!NILP (keymap1)) - maps = nconc2 (Faccessible_keymaps (get_keymap (keymap1), Qnil), - Faccessible_keymaps (get_keymap (current_global_map), - Qnil)); - else - maps = Faccessible_keymaps (get_keymap (current_global_map), Qnil); + Lisp_Object tem; + if (tem = Fremap_command (definition), !NILP (tem)) + return Qnil; } - /* Put the minor mode keymaps on the front. */ - if (! keymap_specified) + found = keymaps; + while (CONSP (found)) { - Lisp_Object minors; - minors = Fnreverse (Fcurrent_minor_mode_maps ()); - while (!NILP (minors)) - { - maps = nconc2 (Faccessible_keymaps (get_keymap (XCAR (minors)), - Qnil), - maps); - minors = XCDR (minors); - } + maps = + nconc2 (maps, + Faccessible_keymaps (get_keymap (XCAR (found), 1, 0), Qnil)); + found = XCDR (found); } - - GCPRO5 (definition, xkeymap, maps, found, sequences); + + GCPRO5 (definition, keymaps, maps, found, sequences); found = Qnil; sequences = Qnil; @@ -2162,6 +2286,14 @@ indirect definition itself.") last_is_meta = (XINT (last) >= 0 && EQ (Faref (this, last), meta_prefix_char)); + /* if (nomenus && !ascii_sequence_p (this)) */ + if (nomenus && XINT (last) >= 0 + && !INTEGERP (Faref (this, make_number (0)))) + /* If no menu entries should be returned, skip over the + keymaps bound to `menu-bar' and `tool-bar' and other + non-ascii prefixes like `C-down-mouse-2'. */ + continue; + QUIT; while (CONSP (map)) @@ -2191,10 +2323,10 @@ indirect definition itself.") /* In a vector, look at each element. */ for (i = 0; i < XVECTOR (elt)->size; i++) { - binding = XVECTOR (elt)->contents[i]; + binding = AREF (elt, i); XSETFASTINT (key, i); sequence = where_is_internal_1 (binding, key, definition, - noindirect, xkeymap, this, + noindirect, this, last, nomenus, last_is_meta); if (!NILP (sequence)) sequences = Fcons (sequence, sequences); @@ -2206,13 +2338,13 @@ indirect definition itself.") Lisp_Object args; args = Fcons (Fcons (Fcons (definition, noindirect), - Fcons (xkeymap, Qnil)), + Qnil), /* Result accumulator. */ Fcons (Fcons (this, last), Fcons (make_number (nomenus), make_number (last_is_meta)))); map_char_table (where_is_internal_2, Qnil, elt, args, 0, indices); - sequences = XCDR (XCDR (XCAR (args))); + sequences = XCDR (XCAR (args)); } else if (CONSP (elt)) { @@ -2222,19 +2354,57 @@ indirect definition itself.") binding = XCDR (elt); sequence = where_is_internal_1 (binding, key, definition, - noindirect, xkeymap, this, + noindirect, this, last, nomenus, last_is_meta); if (!NILP (sequence)) sequences = Fcons (sequence, sequences); } - for (; ! NILP (sequences); sequences = XCDR (sequences)) + while (!NILP (sequences)) { - Lisp_Object sequence; + Lisp_Object sequence, remapped, function; sequence = XCAR (sequences); + sequences = XCDR (sequences); + + /* If the current sequence is a command remapping with + format [remap COMMAND], find the key sequences + which run COMMAND, and use those sequences instead. */ + remapped = Qnil; + if (NILP (no_remap) + && VECTORP (sequence) && XVECTOR (sequence)->size == 2 + && EQ (AREF (sequence, 0), Qremap) + && (function = AREF (sequence, 1), SYMBOLP (function))) + { + Lisp_Object remapped1; + + remapped1 = where_is_internal (function, keymaps, firstonly, noindirect, Qt); + if (CONSP (remapped1)) + { + /* Verify that this key binding actually maps to the + remapped command (see below). */ + if (!EQ (shadow_lookup (keymaps, XCAR (remapped1), Qnil), function)) + continue; + sequence = XCAR (remapped1); + remapped = XCDR (remapped1); + goto record_sequence; + } + } + /* Verify that this key binding is not shadowed by another + binding for the same key, before we say it exists. + + Mechanism: look for local definition of this key and if + it is defined and does not match what we found then + ignore this key. + + Either nil or number as value from Flookup_key + means undefined. */ + if (!EQ (shadow_lookup (keymaps, sequence, Qnil), definition)) + continue; + + record_sequence: /* It is a true unshadowed match. Record it, unless it's already been seen (as could happen when inheriting keymaps). */ if (NILP (Fmember (sequence, found))) @@ -2246,8 +2416,15 @@ indirect definition itself.") we find. */ if (EQ (firstonly, Qnon_ascii)) RETURN_UNGCPRO (sequence); - else if (! NILP (firstonly) && ascii_sequence_p (sequence)) + else if (!NILP (firstonly) && ascii_sequence_p (sequence)) RETURN_UNGCPRO (sequence); + + if (CONSP (remapped)) + { + sequence = XCAR (remapped); + remapped = XCDR (remapped); + goto record_sequence; + } } } } @@ -2259,12 +2436,113 @@ indirect definition itself.") /* firstonly may have been t, but we may have gone all the way through the keymaps without finding an all-ASCII key sequence. So just return the best we could find. */ - if (! NILP (firstonly)) + if (!NILP (firstonly)) return Fcar (found); return found; } +DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 5, 0, + doc: /* Return list of keys that invoke DEFINITION. +If KEYMAP is non-nil, search only KEYMAP and the global keymap. +If KEYMAP is nil, search all the currently active keymaps. +If KEYMAP is a list of keymaps, search only those keymaps. + +If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found, +rather than a list of all possible key sequences. +If FIRSTONLY is the symbol `non-ascii', return the first binding found, +no matter what it is. +If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters, +and entirely reject menu bindings. + +If optional 4th arg NOINDIRECT is non-nil, don't follow indirections +to other keymaps or slots. This makes it possible to search for an +indirect definition itself. + +If optional 5th arg NO-REMAP is non-nil, don't search for key sequences +that invoke a command which is remapped to DEFINITION, but include the +remapped command in the returned list. */) + (definition, keymap, firstonly, noindirect, no_remap) + Lisp_Object definition, keymap; + Lisp_Object firstonly, noindirect, no_remap; +{ + Lisp_Object sequences, keymaps; + /* 1 means ignore all menu bindings entirely. */ + int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii); + Lisp_Object result; + + /* Find the relevant keymaps. */ + if (CONSP (keymap) && KEYMAPP (XCAR (keymap))) + keymaps = keymap; + else if (!NILP (keymap)) + keymaps = Fcons (keymap, Fcons (current_global_map, Qnil)); + else + keymaps = Fcurrent_active_maps (Qnil); + + /* Only use caching for the menubar (i.e. called with (def nil t nil). + We don't really need to check `keymap'. */ + if (nomenus && NILP (noindirect) && NILP (keymap)) + { + Lisp_Object *defns; + int i, j, n; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; + + /* Check heuristic-consistency of the cache. */ + if (NILP (Fequal (keymaps, where_is_cache_keymaps))) + where_is_cache = Qnil; + + if (NILP (where_is_cache)) + { + /* We need to create the cache. */ + Lisp_Object args[2]; + where_is_cache = Fmake_hash_table (0, args); + where_is_cache_keymaps = Qt; + + /* Fill in the cache. */ + GCPRO5 (definition, keymaps, firstonly, noindirect, no_remap); + where_is_internal (definition, keymaps, firstonly, noindirect, no_remap); + UNGCPRO; + + where_is_cache_keymaps = keymaps; + } + + /* We want to process definitions from the last to the first. + Instead of consing, copy definitions to a vector and step + over that vector. */ + sequences = Fgethash (definition, where_is_cache, Qnil); + n = XINT (Flength (sequences)); + defns = (Lisp_Object *) alloca (n * sizeof *defns); + for (i = 0; CONSP (sequences); sequences = XCDR (sequences)) + defns[i++] = XCAR (sequences); + + /* Verify that the key bindings are not shadowed. Note that + the following can GC. */ + GCPRO2 (definition, keymaps); + result = Qnil; + j = -1; + for (i = n - 1; i >= 0; --i) + if (EQ (shadow_lookup (keymaps, defns[i], Qnil), definition)) + { + if (ascii_sequence_p (defns[i])) + break; + else if (j < 0) + j = i; + } + + result = i >= 0 ? defns[i] : (j >= 0 ? defns[j] : Qnil); + UNGCPRO; + } + else + { + /* Kill the cache so that where_is_internal_1 doesn't think + we're filling it up. */ + where_is_cache = Qnil; + result = where_is_internal (definition, keymaps, firstonly, noindirect, no_remap); + } + + return result; +} + /* This is the function that Fwhere_is_internal calls using map_char_table. ARGS has the form (((DEFINITION . NOINDIRECT) . (KEYMAP . RESULT)) @@ -2280,86 +2558,54 @@ static void where_is_internal_2 (args, key, binding) Lisp_Object args, key, binding; { - Lisp_Object definition, noindirect, keymap, this, last; + Lisp_Object definition, noindirect, this, last; Lisp_Object result, sequence; int nomenus, last_is_meta; struct gcpro gcpro1, gcpro2, gcpro3; GCPRO3 (args, key, binding); - result = XCDR (XCDR (XCAR (args))); + result = XCDR (XCAR (args)); definition = XCAR (XCAR (XCAR (args))); noindirect = XCDR (XCAR (XCAR (args))); - keymap = XCAR (XCDR (XCAR (args))); this = XCAR (XCAR (XCDR (args))); last = XCDR (XCAR (XCDR (args))); nomenus = XFASTINT (XCAR (XCDR (XCDR (args)))); last_is_meta = XFASTINT (XCDR (XCDR (XCDR (args)))); - sequence = where_is_internal_1 (binding, key, definition, noindirect, keymap, + sequence = where_is_internal_1 (binding, key, definition, noindirect, this, last, nomenus, last_is_meta); if (!NILP (sequence)) - XCDR (XCDR (XCAR (args))) = Fcons (sequence, result); + XSETCDR (XCAR (args), Fcons (sequence, result)); UNGCPRO; } -/* This function can GC.because Flookup_key calls get_keymap_1 with - non-zero argument AUTOLOAD. */ +/* This function cannot GC. */ static Lisp_Object -where_is_internal_1 (binding, key, definition, noindirect, keymap, this, last, +where_is_internal_1 (binding, key, definition, noindirect, this, last, nomenus, last_is_meta) - Lisp_Object binding, key, definition, noindirect, keymap, this, last; + Lisp_Object binding, key, definition, noindirect, this, last; int nomenus, last_is_meta; { Lisp_Object sequence; - int keymap_specified = !NILP (keymap); - struct gcpro gcpro1, gcpro2; /* Search through indirections unless that's not wanted. */ if (NILP (noindirect)) - { - if (nomenus) - { - while (1) - { - Lisp_Object map, tem; - /* If the contents are (KEYMAP . ELEMENT), go indirect. */ - map = get_keymap_1 (Fcar_safe (definition), 0, 0); - tem = Fkeymapp (map); - if (!NILP (tem)) - definition = access_keymap (map, Fcdr (definition), 0, 0); - else - break; - } - /* If the contents are (menu-item ...) or (STRING ...), reject. */ - if (CONSP (definition) - && (EQ (XCAR (definition),Qmenu_item) - || STRINGP (XCAR (definition)))) - return Qnil; - } - else - binding = get_keyelt (binding, 0); - } + binding = get_keyelt (binding, 0); /* End this iteration if this element does not match the target. */ - if (CONSP (definition)) - { - Lisp_Object tem; - tem = Fequal (binding, definition); - if (NILP (tem)) - return Qnil; - } - else - if (!EQ (binding, definition)) - return Qnil; + if (!(!NILP (where_is_cache) /* everything "matches" during cache-fill. */ + || EQ (binding, definition) + || (CONSP (definition) && !NILP (Fequal (binding, definition))))) + /* Doesn't match. */ + return Qnil; - /* We have found a match. - Construct the key sequence where we found it. */ + /* We have found a match. Construct the key sequence where we found it. */ if (INTEGERP (key) && last_is_meta) { sequence = Fcopy_sequence (this); @@ -2368,72 +2614,31 @@ where_is_internal_1 (binding, key, definition, noindirect, keymap, this, last, else sequence = append_key (this, key); - /* Verify that this key binding is not shadowed by another - binding for the same key, before we say it exists. - - Mechanism: look for local definition of this key and if - it is defined and does not match what we found then - ignore this key. - - Either nil or number as value from Flookup_key - means undefined. */ - GCPRO2 (sequence, binding); - if (keymap_specified) + if (!NILP (where_is_cache)) { - binding = Flookup_key (keymap, sequence, Qnil); - if (!NILP (binding) && !INTEGERP (binding)) - { - if (CONSP (definition)) - { - Lisp_Object tem; - tem = Fequal (binding, definition); - if (NILP (tem)) - RETURN_UNGCPRO (Qnil); - } - else - if (!EQ (binding, definition)) - RETURN_UNGCPRO (Qnil); - } + Lisp_Object sequences = Fgethash (binding, where_is_cache, Qnil); + Fputhash (binding, Fcons (sequence, sequences), where_is_cache); + return Qnil; } else - { - binding = Fkey_binding (sequence, Qnil); - if (!EQ (binding, definition)) - RETURN_UNGCPRO (Qnil); - } - - RETURN_UNGCPRO (sequence); + return sequence; } /* describe-bindings - summarizing all the bindings in a set of keymaps. */ -DEFUN ("describe-bindings-internal", Fdescribe_bindings_internal, Sdescribe_bindings_internal, 0, 2, "", - "Show a list of all defined keys, and their definitions.\n\ -We put that list in a buffer, and display the buffer.\n\ -\n\ -The optional argument MENUS, if non-nil, says to mention menu bindings.\n\ -\(Ordinarily these are omitted from the output.)\n\ -The optional argument PREFIX, if non-nil, should be a key sequence;\n\ -then we display only bindings that start with that prefix.") - (menus, prefix) - Lisp_Object menus, prefix; +DEFUN ("describe-buffer-bindings", Fdescribe_buffer_bindings, Sdescribe_buffer_bindings, 1, 3, 0, + doc: /* Insert the list of all defined keys and their definitions. +The list is inserted in the current buffer, while the bindings are +looked up in BUFFER. +The optional argument PREFIX, if non-nil, should be a key sequence; +then we display only bindings that start with that prefix. +The optional argument MENUS, if non-nil, says to mention menu bindings. +\(Ordinarily these are omitted from the output.) */) + (buffer, prefix, menus) + Lisp_Object buffer, prefix, menus; { - register Lisp_Object thisbuf; - XSETBUFFER (thisbuf, current_buffer); - internal_with_output_to_temp_buffer ("*Help*", - describe_buffer_bindings, - list3 (thisbuf, prefix, menus)); - return Qnil; -} - -/* ARG is (BUFFER PREFIX MENU-FLAG). */ - -static Lisp_Object -describe_buffer_bindings (arg) - Lisp_Object arg; -{ - Lisp_Object descbuf, prefix, shadow; - int nomenu; + Lisp_Object outbuf, shadow; + int nomenu = NILP (menus); register Lisp_Object start1; struct gcpro gcpro1; @@ -2443,16 +2648,10 @@ Keyboard translations:\n\n\ You type Translation\n\ -------- -----------\n"; - descbuf = XCAR (arg); - arg = XCDR (arg); - prefix = XCAR (arg); - arg = XCDR (arg); - nomenu = NILP (XCAR (arg)); - shadow = Qnil; GCPRO1 (shadow); - Fset_buffer (Vstandard_output); + outbuf = Fcurrent_buffer (); /* Report on alternates for keys. */ if (STRINGP (Vkeyboard_translate_table) && !NILP (prefix)) @@ -2473,10 +2672,10 @@ You type Translation\n\ alternate_heading = 0; } - bufend = push_key_description (translate[c], buf); + bufend = push_key_description (translate[c], buf, 1); insert (buf, bufend - buf); Findent_to (make_number (16), make_number (1)); - bufend = push_key_description (c, buf); + bufend = push_key_description (c, buf, 1); insert (buf, bufend - buf); insert ("\n", 1); @@ -2489,64 +2688,85 @@ You type Translation\n\ describe_map_tree (Vkey_translation_map, 0, Qnil, prefix, "Key translations", nomenu, 1, 0); - { - int i, nmaps; - Lisp_Object *modes, *maps; - - /* Temporarily switch to descbuf, so that we can get that buffer's - minor modes correctly. */ - Fset_buffer (descbuf); - - if (!NILP (current_kboard->Voverriding_terminal_local_map) - || !NILP (Voverriding_local_map)) - nmaps = 0; - else - nmaps = current_minor_maps (&modes, &maps); - Fset_buffer (Vstandard_output); - - /* Print the minor mode maps. */ - for (i = 0; i < nmaps; i++) - { - /* The title for a minor mode keymap - is constructed at run time. - We let describe_map_tree do the actual insertion - because it takes care of other features when doing so. */ - char *title, *p; - - if (!SYMBOLP (modes[i])) - abort(); - - p = title = (char *) alloca (42 + XSYMBOL (modes[i])->name->size); - *p++ = '\f'; - *p++ = '\n'; - *p++ = '`'; - bcopy (XSYMBOL (modes[i])->name->data, p, - XSYMBOL (modes[i])->name->size); - p += XSYMBOL (modes[i])->name->size; - *p++ = '\''; - bcopy (" Minor Mode Bindings", p, sizeof (" Minor Mode Bindings") - 1); - p += sizeof (" Minor Mode Bindings") - 1; - *p = 0; - - describe_map_tree (maps[i], 1, shadow, prefix, title, nomenu, 0, 0); - shadow = Fcons (maps[i], shadow); - } - } /* Print the (major mode) local map. */ + start1 = Qnil; if (!NILP (current_kboard->Voverriding_terminal_local_map)) start1 = current_kboard->Voverriding_terminal_local_map; else if (!NILP (Voverriding_local_map)) start1 = Voverriding_local_map; - else - start1 = XBUFFER (descbuf)->keymap; if (!NILP (start1)) { describe_map_tree (start1, 1, shadow, prefix, - "\f\nMajor Mode Bindings", nomenu, 0, 0); + "\f\nOverriding Bindings", nomenu, 0, 0); shadow = Fcons (start1, shadow); } + else + { + /* Print the minor mode and major mode keymaps. */ + int i, nmaps; + Lisp_Object *modes, *maps; + + /* Temporarily switch to `buffer', so that we can get that buffer's + minor modes correctly. */ + Fset_buffer (buffer); + + nmaps = current_minor_maps (&modes, &maps); + Fset_buffer (outbuf); + + start1 = get_local_map (BUF_PT (XBUFFER (buffer)), + XBUFFER (buffer), Qkeymap); + if (!NILP (start1)) + { + describe_map_tree (start1, 1, shadow, prefix, + "\f\n`keymap' Property Bindings", nomenu, 0, 0); + shadow = Fcons (start1, shadow); + } + + /* Print the minor mode maps. */ + for (i = 0; i < nmaps; i++) + { + /* The title for a minor mode keymap + is constructed at run time. + We let describe_map_tree do the actual insertion + because it takes care of other features when doing so. */ + char *title, *p; + + if (!SYMBOLP (modes[i])) + abort(); + + p = title = (char *) alloca (42 + XSYMBOL (modes[i])->name->size); + *p++ = '\f'; + *p++ = '\n'; + *p++ = '`'; + bcopy (XSYMBOL (modes[i])->name->data, p, + XSYMBOL (modes[i])->name->size); + p += XSYMBOL (modes[i])->name->size; + *p++ = '\''; + bcopy (" Minor Mode Bindings", p, sizeof (" Minor Mode Bindings") - 1); + p += sizeof (" Minor Mode Bindings") - 1; + *p = 0; + + describe_map_tree (maps[i], 1, shadow, prefix, title, nomenu, 0, 0); + shadow = Fcons (maps[i], shadow); + } + + start1 = get_local_map (BUF_PT (XBUFFER (buffer)), + XBUFFER (buffer), Qlocal_map); + if (!NILP (start1)) + { + if (EQ (start1, XBUFFER (buffer)->keymap)) + describe_map_tree (start1, 1, shadow, prefix, + "\f\nMajor Mode Bindings", nomenu, 0, 0); + else + describe_map_tree (start1, 1, shadow, prefix, + "\f\n`local-map' Property Bindings", + nomenu, 0, 0); + + shadow = Fcons (start1, shadow); + } + } describe_map_tree (current_global_map, 1, shadow, prefix, "\f\nGlobal Bindings", nomenu, 0, 1); @@ -2556,8 +2776,6 @@ You type Translation\n\ describe_map_tree (Vfunction_key_map, 0, Qnil, prefix, "\f\nFunction key map translations", nomenu, 1, 0); - call0 (intern ("help-mode")); - Fset_buffer (descbuf); UNGCPRO; return Qnil; } @@ -2671,7 +2889,7 @@ key binding\n\ /* If shmap is not nil and not a keymap, it completely shadows this map, so don't describe this map at all. */ - if (!NILP (shmap) && NILP (Fkeymapp (shmap))) + if (!NILP (shmap) && !KEYMAPP (shmap)) goto skip; if (!NILP (shmap)) @@ -2679,11 +2897,11 @@ key binding\n\ } /* Maps we have already listed in this loop shadow this map. */ - for (tail = orig_maps; ! EQ (tail, maps); tail = XCDR (tail)) + for (tail = orig_maps; !EQ (tail, maps); tail = XCDR (tail)) { Lisp_Object tem; tem = Fequal (Fcar (XCAR (tail)), prefix); - if (! NILP (tem)) + if (!NILP (tem)) sub_shadows = Fcons (XCDR (XCAR (tail)), sub_shadows); } @@ -2703,8 +2921,8 @@ key binding\n\ static int previous_description_column; static void -describe_command (definition) - Lisp_Object definition; +describe_command (definition, args) + Lisp_Object definition, args; { register Lisp_Object tem1; int column = current_column (); @@ -2733,19 +2951,15 @@ describe_command (definition) } else if (STRINGP (definition) || VECTORP (definition)) insert_string ("Keyboard Macro\n"); + else if (KEYMAPP (definition)) + insert_string ("Prefix Command\n"); else - { - tem1 = Fkeymapp (definition); - if (!NILP (tem1)) - insert_string ("Prefix Command\n"); - else - insert_string ("??\n"); - } + insert_string ("??\n"); } static void -describe_translation (definition) - Lisp_Object definition; +describe_translation (definition, args) + Lisp_Object definition, args; { register Lisp_Object tem1; @@ -2762,32 +2976,10 @@ describe_translation (definition) insert1 (Fkey_description (definition)); insert_string ("\n"); } + else if (KEYMAPP (definition)) + insert_string ("Prefix Command\n"); else - { - tem1 = Fkeymapp (definition); - if (!NILP (tem1)) - insert_string ("Prefix Command\n"); - else - insert_string ("??\n"); - } -} - -/* Like Flookup_key, but uses a list of keymaps SHADOW instead of a single map. - Returns the first non-nil binding found in any of those maps. */ - -static Lisp_Object -shadow_lookup (shadow, key, flag) - Lisp_Object shadow, key, flag; -{ - Lisp_Object tail, value; - - for (tail = shadow; CONSP (tail); tail = XCDR (tail)) - { - value = Flookup_key (XCAR (tail), key, flag); - if (!NILP (value)) - return value; - } - return Qnil; + insert_string ("??\n"); } /* Describe the contents of map MAP, assuming that this map itself is @@ -2798,7 +2990,7 @@ static void describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu) register Lisp_Object map; Lisp_Object keys; - void (*elt_describer) P_ ((Lisp_Object)); + void (*elt_describer) P_ ((Lisp_Object, Lisp_Object)); int partial; Lisp_Object shadow; Lisp_Object *seen; @@ -2812,6 +3004,8 @@ describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu) int first = 1; struct gcpro gcpro1, gcpro2, gcpro3; + suppress = Qnil; + if (!NILP (keys) && XFASTINT (Flength (keys)) > 0) { /* Call Fkey_description first, to avoid GC bug for the other string. */ @@ -2839,7 +3033,7 @@ describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu) if (VECTORP (XCAR (tail)) || CHAR_TABLE_P (XCAR (tail))) describe_vector (XCAR (tail), - elt_prefix, elt_describer, partial, shadow, map, + elt_prefix, Qnil, elt_describer, partial, shadow, map, (int *)0, 0); else if (CONSP (XCAR (tail))) { @@ -2847,7 +3041,7 @@ describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu) /* Ignore bindings whose "keys" are not really valid events. (We get these in the frames and buffers menu.) */ - if (! (SYMBOLP (event) || INTEGERP (event))) + if (!(SYMBOLP (event) || INTEGERP (event))) continue; if (nomenu && EQ (event, Qmenu_bar)) @@ -2867,7 +3061,7 @@ describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu) /* Don't show a command that isn't really visible because a local definition of the same key shadows it. */ - XVECTOR (kludge)->contents[0] = event; + ASET (kludge, 0, event); if (!NILP (shadow)) { tem = shadow_lookup (shadow, kludge, Qt); @@ -2875,7 +3069,7 @@ describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu) } tem = Flookup_key (map, kludge, Qt); - if (! EQ (tem, definition)) continue; + if (!EQ (tem, definition)) continue; if (first) { @@ -2888,12 +3082,12 @@ describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu) insert1 (elt_prefix); /* THIS gets the string to describe the character EVENT. */ - insert1 (Fsingle_key_description (event)); + insert1 (Fsingle_key_description (event, Qnil)); /* Print a description of the definition of this character. elt_describer will take care of spacing out far enough for alignment purposes. */ - (*elt_describer) (definition); + (*elt_describer) (definition, Qnil); } else if (EQ (XCAR (tail), Qkeymap)) { @@ -2911,25 +3105,26 @@ describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu) } static void -describe_vector_princ (elt) - Lisp_Object elt; +describe_vector_princ (elt, fun) + Lisp_Object elt, fun; { Findent_to (make_number (16), make_number (1)); - Fprinc (elt, Qnil); + call1 (fun, elt); Fterpri (Qnil); } -DEFUN ("describe-vector", Fdescribe_vector, Sdescribe_vector, 1, 1, 0, - "Insert a description of contents of VECTOR.\n\ -This is text showing the elements of vector matched against indices.") - (vector) - Lisp_Object vector; +DEFUN ("describe-vector", Fdescribe_vector, Sdescribe_vector, 1, 2, 0, + doc: /* Insert a description of contents of VECTOR. +This is text showing the elements of vector matched against indices. */) + (vector, describer) + Lisp_Object vector, describer; { int count = specpdl_ptr - specpdl; - + if (NILP (describer)) + describer = intern ("princ"); specbind (Qstandard_output, Fcurrent_buffer ()); - CHECK_VECTOR_OR_CHAR_TABLE (vector, 0); - describe_vector (vector, Qnil, describe_vector_princ, 0, + CHECK_VECTOR_OR_CHAR_TABLE (vector); + describe_vector (vector, Qnil, describer, describe_vector_princ, 0, Qnil, Qnil, (int *)0, 0); return unbind_to (count, Qnil); @@ -2963,15 +3158,17 @@ This is text showing the elements of vector matched against indices.") When describing a sub-char-table, INDICES is a list of indices at higher levels in this char-table, - and CHAR_TABLE_DEPTH says how many levels down we have gone. */ + and CHAR_TABLE_DEPTH says how many levels down we have gone. + + ARGS is simply passed as the second argument to ELT_DESCRIBER. */ void -describe_vector (vector, elt_prefix, elt_describer, +describe_vector (vector, elt_prefix, args, elt_describer, partial, shadow, entire_map, indices, char_table_depth) register Lisp_Object vector; - Lisp_Object elt_prefix; - void (*elt_describer) P_ ((Lisp_Object)); + Lisp_Object elt_prefix, args; + void (*elt_describer) P_ ((Lisp_Object, Lisp_Object)); int partial; Lisp_Object shadow; Lisp_Object entire_map; @@ -2993,6 +3190,8 @@ describe_vector (vector, elt_prefix, elt_describer, int character; int starting_i; + suppress = Qnil; + if (indices == 0) indices = (int *) alloca (3 * sizeof (int)); @@ -3060,9 +3259,9 @@ describe_vector (vector, elt_prefix, elt_describer, = get_keyelt (XCHAR_TABLE (vector)->contents[i], 0); } else - definition = get_keyelt (XVECTOR (vector)->contents[i], 0); + definition = get_keyelt (AREF (vector, i), 0); - if (NILP (definition)) continue; + if (NILP (definition)) continue; /* Don't mention suppressed commands. */ if (SYMBOLP (definition) && partial) @@ -3100,7 +3299,7 @@ describe_vector (vector, elt_prefix, elt_describer, { Lisp_Object tem; - XVECTOR (kludge)->contents[0] = make_number (character); + ASET (kludge, 0, make_number (character)); tem = shadow_lookup (shadow, kludge, Qt); if (!NILP (tem)) continue; @@ -3112,10 +3311,10 @@ describe_vector (vector, elt_prefix, elt_describer, { Lisp_Object tem; - XVECTOR (kludge)->contents[0] = make_number (character); + ASET (kludge, 0, make_number (character)); tem = Flookup_key (entire_map, kludge, Qt); - if (! EQ (tem, definition)) + if (!EQ (tem, definition)) continue; } @@ -3153,7 +3352,7 @@ describe_vector (vector, elt_prefix, elt_describer, else if (CHAR_TABLE_P (vector)) { if (complete_char) - insert1 (Fsingle_key_description (make_number (character))); + insert1 (Fsingle_key_description (make_number (character), Qnil)); else { /* Print the information for this character set. */ @@ -3169,7 +3368,7 @@ describe_vector (vector, elt_prefix, elt_describer, } else { - insert1 (Fsingle_key_description (make_number (character))); + insert1 (Fsingle_key_description (make_number (character), Qnil)); } /* If we find a sub char-table within a char-table, @@ -3178,7 +3377,7 @@ describe_vector (vector, elt_prefix, elt_describer, if (CHAR_TABLE_P (vector) && SUB_CHAR_TABLE_P (definition)) { insert ("\n", 1); - describe_vector (definition, elt_prefix, elt_describer, + describe_vector (definition, elt_prefix, args, elt_describer, partial, shadow, entire_map, indices, char_table_depth + 1); continue; @@ -3205,7 +3404,7 @@ describe_vector (vector, elt_prefix, elt_describer, } else while (i + 1 < to - && (tem2 = get_keyelt (XVECTOR (vector)->contents[i + 1], 0), + && (tem2 = get_keyelt (AREF (vector, i + 1), 0), !NILP (tem2)) && !NILP (Fequal (tem2, definition))) i++; @@ -3225,7 +3424,7 @@ describe_vector (vector, elt_prefix, elt_describer, { if (char_table_depth == 0) { - insert1 (Fsingle_key_description (make_number (i))); + insert1 (Fsingle_key_description (make_number (i), Qnil)); } else if (complete_char) { @@ -3244,14 +3443,14 @@ describe_vector (vector, elt_prefix, elt_describer, } else { - insert1 (Fsingle_key_description (make_number (i))); + insert1 (Fsingle_key_description (make_number (i), Qnil)); } } /* Print a description of the definition of this character. elt_describer will take care of spacing out far enough for alignment purposes. */ - (*elt_describer) (definition); + (*elt_describer) (definition, args); } /* For (sub) char-table, print `defalt' slot at last. */ @@ -3259,7 +3458,7 @@ describe_vector (vector, elt_prefix, elt_describer, { insert (" ", char_table_depth * 2); insert_string ("<>"); - (*elt_describer) (XCHAR_TABLE (vector)->defalt); + (*elt_describer) (XCHAR_TABLE (vector)->defalt, args); } UNGCPRO; @@ -3283,15 +3482,15 @@ apropos_accum (symbol, string) } DEFUN ("apropos-internal", Fapropos_internal, Sapropos_internal, 1, 2, 0, - "Show all symbols whose names contain match for REGEXP.\n\ -If optional 2nd arg PREDICATE is non-nil, (funcall PREDICATE SYMBOL) is done\n\ -for each symbol and a symbol is mentioned only if that returns non-nil.\n\ -Return list of symbols found.") - (regexp, predicate) + doc: /* Show all symbols whose names contain match for REGEXP. +If optional 2nd arg PREDICATE is non-nil, (funcall PREDICATE SYMBOL) is done +for each symbol and a symbol is mentioned only if that returns non-nil. +Return list of symbols found. */) + (regexp, predicate) Lisp_Object regexp, predicate; { struct gcpro gcpro1, gcpro2; - CHECK_STRING (regexp, 0); + CHECK_STRING (regexp); apropos_predicate = predicate; GCPRO2 (apropos_predicate, apropos_accumulate); apropos_accumulate = Qnil; @@ -3330,68 +3529,81 @@ syms_of_keymap () Fset (intern ("ctl-x-map"), control_x_map); Ffset (intern ("Control-X-prefix"), control_x_map); + exclude_keys + = Fcons (Fcons (build_string ("DEL"), build_string ("\\d")), + Fcons (Fcons (build_string ("TAB"), build_string ("\\t")), + Fcons (Fcons (build_string ("RET"), build_string ("\\r")), + Fcons (Fcons (build_string ("ESC"), build_string ("\\e")), + Fcons (Fcons (build_string ("SPC"), build_string (" ")), + Qnil))))); + staticpro (&exclude_keys); + DEFVAR_LISP ("define-key-rebound-commands", &Vdefine_key_rebound_commands, - "List of commands given new key bindings recently.\n\ -This is used for internal purposes during Emacs startup;\n\ -don't alter it yourself."); + doc: /* List of commands given new key bindings recently. +This is used for internal purposes during Emacs startup; +don't alter it yourself. */); Vdefine_key_rebound_commands = Qt; DEFVAR_LISP ("minibuffer-local-map", &Vminibuffer_local_map, - "Default keymap to use when reading from the minibuffer."); + doc: /* Default keymap to use when reading from the minibuffer. */); Vminibuffer_local_map = Fmake_sparse_keymap (Qnil); DEFVAR_LISP ("minibuffer-local-ns-map", &Vminibuffer_local_ns_map, - "Local keymap for the minibuffer when spaces are not allowed."); + doc: /* Local keymap for the minibuffer when spaces are not allowed. */); Vminibuffer_local_ns_map = Fmake_sparse_keymap (Qnil); + Fset_keymap_parent (Vminibuffer_local_ns_map, Vminibuffer_local_map); DEFVAR_LISP ("minibuffer-local-completion-map", &Vminibuffer_local_completion_map, - "Local keymap for minibuffer input with completion."); + doc: /* Local keymap for minibuffer input with completion. */); Vminibuffer_local_completion_map = Fmake_sparse_keymap (Qnil); + Fset_keymap_parent (Vminibuffer_local_completion_map, Vminibuffer_local_map); DEFVAR_LISP ("minibuffer-local-must-match-map", &Vminibuffer_local_must_match_map, - "Local keymap for minibuffer input with completion, for exact match."); + doc: /* Local keymap for minibuffer input with completion, for exact match. */); Vminibuffer_local_must_match_map = Fmake_sparse_keymap (Qnil); + Fset_keymap_parent (Vminibuffer_local_must_match_map, + Vminibuffer_local_completion_map); DEFVAR_LISP ("minor-mode-map-alist", &Vminor_mode_map_alist, - "Alist of keymaps to use for minor modes.\n\ -Each element looks like (VARIABLE . KEYMAP); KEYMAP is used to read\n\ -key sequences and look up bindings iff VARIABLE's value is non-nil.\n\ -If two active keymaps bind the same key, the keymap appearing earlier\n\ -in the list takes precedence."); + doc: /* Alist of keymaps to use for minor modes. +Each element looks like (VARIABLE . KEYMAP); KEYMAP is used to read +key sequences and look up bindings iff VARIABLE's value is non-nil. +If two active keymaps bind the same key, the keymap appearing earlier +in the list takes precedence. */); Vminor_mode_map_alist = Qnil; DEFVAR_LISP ("minor-mode-overriding-map-alist", &Vminor_mode_overriding_map_alist, - "Alist of keymaps to use for minor modes, in current major mode.\n\ -This variable is a alist just like `minor-mode-map-alist', and it is\n\ -used the same way (and before `minor-mode-map-alist'); however,\n\ -it is provided for major modes to bind locally."); + doc: /* Alist of keymaps to use for minor modes, in current major mode. +This variable is a alist just like `minor-mode-map-alist', and it is +used the same way (and before `minor-mode-map-alist'); however, +it is provided for major modes to bind locally. */); Vminor_mode_overriding_map_alist = Qnil; DEFVAR_LISP ("function-key-map", &Vfunction_key_map, - "Keymap mapping ASCII function key sequences onto their preferred forms.\n\ -This allows Emacs to recognize function keys sent from ASCII\n\ -terminals at any point in a key sequence.\n\ -\n\ -The `read-key-sequence' function replaces any subsequence bound by\n\ -`function-key-map' with its binding. More precisely, when the active\n\ -keymaps have no binding for the current key sequence but\n\ -`function-key-map' binds a suffix of the sequence to a vector or string,\n\ -`read-key-sequence' replaces the matching suffix with its binding, and\n\ -continues with the new sequence.\n\ -\n\ -The events that come from bindings in `function-key-map' are not\n\ -themselves looked up in `function-key-map'.\n\ -\n\ -For example, suppose `function-key-map' binds `ESC O P' to [f1].\n\ -Typing `ESC O P' to `read-key-sequence' would return [f1]. Typing\n\ -`C-x ESC O P' would return [?\\C-x f1]. If [f1] were a prefix\n\ -key, typing `ESC O P x' would return [f1 x]."); + doc: /* Keymap mapping ASCII function key sequences onto their preferred forms. +This allows Emacs to recognize function keys sent from ASCII +terminals at any point in a key sequence. + +The `read-key-sequence' function replaces any subsequence bound by +`function-key-map' with its binding. More precisely, when the active +keymaps have no binding for the current key sequence but +`function-key-map' binds a suffix of the sequence to a vector or string, +`read-key-sequence' replaces the matching suffix with its binding, and +continues with the new sequence. + +The events that come from bindings in `function-key-map' are not +themselves looked up in `function-key-map'. + +For example, suppose `function-key-map' binds `ESC O P' to [f1]. +Typing `ESC O P' to `read-key-sequence' would return [f1]. Typing +`C-x ESC O P' would return [?\\C-x f1]. If [f1] were a prefix +key, typing `ESC O P x' would return [f1 x]. */); Vfunction_key_map = Fmake_sparse_keymap (Qnil); DEFVAR_LISP ("key-translation-map", &Vkey_translation_map, - "Keymap of key translations that can override keymaps.\n\ -This keymap works like `function-key-map', but comes after that,\n\ -and applies even for keys that have ordinary bindings."); + doc: /* Keymap of key translations that can override keymaps. +This keymap works like `function-key-map', but comes after that, +and applies even for keys that have ordinary bindings. */); Vkey_translation_map = Qnil; Qsingle_key_description = intern ("single-key-description"); @@ -3409,12 +3621,25 @@ and applies even for keys that have ordinary bindings."); Qmenu_item = intern ("menu-item"); staticpro (&Qmenu_item); + Qremap = intern ("remap"); + staticpro (&Qremap); + + remap_command_vector = Fmake_vector (make_number (2), Qremap); + staticpro (&remap_command_vector); + + where_is_cache_keymaps = Qt; + where_is_cache = Qnil; + staticpro (&where_is_cache); + staticpro (&where_is_cache_keymaps); + defsubr (&Skeymapp); defsubr (&Skeymap_parent); + defsubr (&Skeymap_prompt); defsubr (&Sset_keymap_parent); defsubr (&Smake_keymap); defsubr (&Smake_sparse_keymap); defsubr (&Scopy_keymap); + defsubr (&Sremap_command); defsubr (&Skey_binding); defsubr (&Slocal_key_binding); defsubr (&Sglobal_key_binding); @@ -3427,13 +3652,14 @@ and applies even for keys that have ordinary bindings."); defsubr (&Scurrent_local_map); defsubr (&Scurrent_global_map); defsubr (&Scurrent_minor_mode_maps); + defsubr (&Scurrent_active_maps); defsubr (&Saccessible_keymaps); defsubr (&Skey_description); defsubr (&Sdescribe_vector); defsubr (&Ssingle_key_description); defsubr (&Stext_char_description); defsubr (&Swhere_is_internal); - defsubr (&Sdescribe_bindings_internal); + defsubr (&Sdescribe_buffer_bindings); defsubr (&Sapropos_internal); }