diff options
Diffstat (limited to 'src/keymap.c')
-rw-r--r-- | src/keymap.c | 1900 |
1 files changed, 811 insertions, 1089 deletions
diff --git a/src/keymap.c b/src/keymap.c index ccf8ce79175..506b755e5da 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -1,5 +1,5 @@ /* Manipulation of keymaps - Copyright (C) 1985-1988, 1993-1995, 1998-2017 Free Software + Copyright (C) 1985-1988, 1993-1995, 1998-2022 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -59,41 +59,24 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ Lisp_Object current_global_map; /* Current global keymap. */ -Lisp_Object global_map; /* Default global key bindings. */ - -Lisp_Object meta_map; /* The keymap used for globally bound - ESC-prefixed default commands. */ - -Lisp_Object control_x_map; /* The keymap used for globally bound - C-x-prefixed default commands. */ - - /* The keymap used by the minibuf for local - bindings when spaces are allowed in the - minibuf. */ - - /* The keymap used by the minibuf for local - bindings when spaces are not encouraged - in the minibuf. */ - /* Alist of elements like (DEL . "\d"). */ static Lisp_Object exclude_keys; /* Pre-allocated 2-element vector for Fcommand_remapping to use. */ static Lisp_Object command_remapping_vector; +/* Char table for the backwards-compatibility part in Flookup_key. */ +static Lisp_Object unicode_case_table; + /* 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 (Lisp_Object, Lisp_Object, Lisp_Object); +static Lisp_Object store_in_keymap (Lisp_Object, Lisp_Object, Lisp_Object, + bool); static Lisp_Object define_as_prefix (Lisp_Object, Lisp_Object); -static void describe_command (Lisp_Object, Lisp_Object); -static void describe_translation (Lisp_Object, Lisp_Object); -static void describe_map (Lisp_Object, Lisp_Object, - void (*) (Lisp_Object, Lisp_Object), - bool, Lisp_Object, Lisp_Object *, bool, bool); static void describe_vector (Lisp_Object, Lisp_Object, Lisp_Object, void (*) (Lisp_Object, Lisp_Object), bool, Lisp_Object, Lisp_Object, bool, bool); @@ -120,11 +103,7 @@ The optional arg STRING supplies a menu name for the keymap in case you use it as a menu with `x-popup-menu'. */) (Lisp_Object string) { - Lisp_Object tail; - if (!NILP (string)) - tail = list1 (string); - else - tail = Qnil; + Lisp_Object tail = !NILP (string) ? list1 (string) : Qnil; return Fcons (Qkeymap, Fcons (Fmake_char_table (Qkeymap, Qnil), tail)); } @@ -149,23 +128,11 @@ in case you use it as a menu with `x-popup-menu'. */) return list1 (Qkeymap); } -/* This function is used for installing the standard key bindings - at initialization time. - - For example: - - initial_define_key (control_x_map, Ctl('X'), "exchange-point-and-mark"); */ - -void -initial_define_key (Lisp_Object keymap, int key, const char *defname) -{ - store_in_keymap (keymap, make_number (key), intern_c_string (defname)); -} - void initial_define_lispy_key (Lisp_Object keymap, const char *keyname, const char *defname) { - store_in_keymap (keymap, intern_c_string (keyname), intern_c_string (defname)); + store_in_keymap (keymap, intern_c_string (keyname), + intern_c_string (defname), false); } DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0, @@ -227,15 +194,13 @@ when reading a key-sequence to be looked-up in this keymap. */) Lisp_Object get_keymap (Lisp_Object object, bool error_if_not_keymap, bool autoload) { - Lisp_Object tem; - autoload_retry: if (NILP (object)) goto end; if (CONSP (object) && EQ (XCAR (object), Qkeymap)) return object; - tem = indirect_function (object); + Lisp_Object tem = indirect_function (object); if (CONSP (tem)) { if (EQ (XCAR (tem), Qkeymap)) @@ -248,7 +213,7 @@ get_keymap (Lisp_Object object, bool error_if_not_keymap, bool autoload) { Lisp_Object tail; - tail = Fnth (make_number (4), tem); + tail = Fnth (make_fixnum (4), tem); if (EQ (tail, Qkeymap)) { if (autoload) @@ -274,12 +239,10 @@ get_keymap (Lisp_Object object, bool error_if_not_keymap, bool autoload) static Lisp_Object keymap_parent (Lisp_Object keymap, bool autoload) { - Lisp_Object list; - keymap = get_keymap (keymap, 1, autoload); /* Skip past the initial element `keymap'. */ - list = XCDR (keymap); + Lisp_Object list = XCDR (keymap); for (; CONSP (list); list = XCDR (list)) { /* See if there is another `keymap'. */ @@ -315,8 +278,6 @@ DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0, Return PARENT. PARENT should be nil or another keymap. */) (Lisp_Object keymap, Lisp_Object parent) { - Lisp_Object list, prev; - /* Flush any reverse-map cache. */ where_is_cache = Qnil; where_is_cache_keymaps = Qt; @@ -332,10 +293,10 @@ Return PARENT. PARENT should be nil or another keymap. */) } /* Skip past the initial element `keymap'. */ - prev = keymap; + Lisp_Object prev = keymap; while (1) { - list = XCDR (prev); + Lisp_Object 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) || KEYMAPP (list)) @@ -379,28 +340,28 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx, be put in the canonical order. */ if (SYMBOLP (idx)) idx = reorder_modifiers (idx); - else if (INTEGERP (idx)) + else if (FIXNUMP (idx)) /* Clobber the high bits that can be present on a machine with more than 24 bits of integer. */ - XSETFASTINT (idx, XINT (idx) & (CHAR_META | (CHAR_META - 1))); + XSETFASTINT (idx, XFIXNUM (idx) & (CHAR_META | (CHAR_META - 1))); /* Handle the special meta -> esc mapping. */ - if (INTEGERP (idx) && XFASTINT (idx) & meta_modifier) + if (FIXNUMP (idx) && XFIXNAT (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 event_meta_binding, event_meta_map; /* A strange value in which Meta is set would cause infinite recursion. Protect against that. */ - if (XINT (meta_prefix_char) & CHAR_META) - meta_prefix_char = make_number (27); + if (XFIXNUM (meta_prefix_char) & CHAR_META) + meta_prefix_char = make_fixnum (27); event_meta_binding = access_keymap_1 (map, meta_prefix_char, t_ok, noinherit, autoload); event_meta_map = get_keymap (event_meta_binding, 0, autoload); if (CONSP (event_meta_map)) { map = event_meta_map; - idx = make_number (XFASTINT (idx) & ~meta_modifier); + idx = make_fixnum (XFIXNAT (idx) & ~meta_modifier); } else if (t_ok) /* Set IDX to t, so that we only find a default binding. */ @@ -434,7 +395,7 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx, if (noinherit || NILP (retval)) /* If NOINHERIT, stop here, the rest is inherited. */ break; - else if (!EQ (retval, Qunbound)) + else if (!BASE_EQ (retval, Qunbound)) { Lisp_Object parent_entry; eassert (KEYMAPP (retval)); @@ -473,15 +434,15 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx, } else if (VECTORP (binding)) { - if (INTEGERP (idx) && XFASTINT (idx) < ASIZE (binding)) - val = AREF (binding, XFASTINT (idx)); + if (FIXNUMP (idx) && XFIXNAT (idx) < ASIZE (binding)) + val = AREF (binding, XFIXNAT (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 (INTEGERP (idx) && (XFASTINT (idx) & CHAR_MODIFIER_MASK) == 0) + if (FIXNUMP (idx) && (XFIXNAT (idx) & CHAR_MODIFIER_MASK) == 0) { val = Faref (binding, idx); /* nil has a special meaning for char-tables, so @@ -493,7 +454,7 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx, } /* If we found a binding, clean it up and return it. */ - if (!EQ (val, Qunbound)) + if (!BASE_EQ (val, Qunbound)) { if (EQ (val, Qt)) /* A Qt binding is just like an explicit nil binding @@ -505,12 +466,12 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx, if (!KEYMAPP (val)) { - if (NILP (retval) || EQ (retval, Qunbound)) + if (NILP (retval) || BASE_EQ (retval, Qunbound)) retval = val; if (!NILP (val)) break; /* Shadows everything that follows. */ } - else if (NILP (retval) || EQ (retval, Qunbound)) + else if (NILP (retval) || BASE_EQ (retval, Qunbound)) retval = val; else if (CONSP (retval_tail)) { @@ -526,7 +487,8 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx, maybe_quit (); } - return EQ (Qunbound, retval) ? get_keyelt (t_binding, autoload) : retval; + return BASE_EQ (Qunbound, retval) + ? get_keyelt (t_binding, autoload) : retval; } } @@ -535,7 +497,7 @@ access_keymap (Lisp_Object map, Lisp_Object idx, bool t_ok, bool noinherit, bool autoload) { Lisp_Object val = access_keymap_1 (map, idx, t_ok, noinherit, autoload); - return EQ (val, Qunbound) ? Qnil : val; + return BASE_EQ (val, Qunbound) ? Qnil : val; } static void @@ -546,19 +508,29 @@ map_keymap_item (map_keymap_function_t fun, Lisp_Object args, Lisp_Object key, L (*fun) (key, val, args, data); } +union map_keymap +{ + struct + { + map_keymap_function_t fun; + Lisp_Object args; + void *data; + } s; + GCALIGNED_UNION_MEMBER +}; +verify (GCALIGNED (union map_keymap)); + static void map_keymap_char_table_item (Lisp_Object args, Lisp_Object key, Lisp_Object val) { if (!NILP (val)) { - map_keymap_function_t fun - = (map_keymap_function_t) XSAVE_FUNCPOINTER (args, 0); /* If the key is a range, make a copy since map_char_table modifies it in place. */ if (CONSP (key)) key = Fcons (XCAR (key), XCDR (key)); - map_keymap_item (fun, XSAVE_OBJECT (args, 2), key, - val, XSAVE_POINTER (args, 1)); + union map_keymap *md = XFIXNUMPTR (args); + map_keymap_item (md->s.fun, md->s.args, key, val, md->s.data); } } @@ -594,9 +566,11 @@ map_keymap_internal (Lisp_Object map, } } else if (CHAR_TABLE_P (binding)) - map_char_table (map_keymap_char_table_item, Qnil, binding, - make_save_funcptr_ptr_obj ((voidfuncptr) fun, data, - args)); + { + union map_keymap mapdata = {{fun, args, data}}; + map_char_table (map_keymap_char_table_item, Qnil, binding, + make_pointer_integer (&mapdata)); + } } return tail; @@ -661,6 +635,9 @@ the definition it is bound to. The event may be a character range. If KEYMAP has a parent, the parent's bindings are included as well. This works recursively: if the parent has itself a parent, then the grandparent's bindings are also included and so on. + +For more information, see Info node `(elisp) Keymaps'. + usage: (map-keymap FUNCTION KEYMAP) */) (Lisp_Object function, Lisp_Object keymap, Lisp_Object sort_first) { @@ -671,6 +648,23 @@ usage: (map-keymap FUNCTION KEYMAP) */) return Qnil; } +DEFUN ("keymap--get-keyelt", Fkeymap__get_keyelt, Skeymap__get_keyelt, 2, 2, 0, + doc: /* Given OBJECT which was found in a slot in a keymap, +trace indirect definitions to get the actual definition of that slot. +An indirect definition is a list of the form +(KEYMAP . INDEX), where KEYMAP is a keymap or a symbol defined as one +and INDEX is the object to look up in KEYMAP to yield the definition. + +Also if OBJECT has a menu string as the first element, +remove that. Also remove a menu help string as second element. + +If AUTOLOAD, load autoloadable keymaps +that are referred to with indirection. */) + (Lisp_Object object, Lisp_Object autoload) +{ + return get_keyelt (object, NILP (autoload) ? false : true); +} + /* Given OBJECT which was found in a slot in a keymap, trace indirect definitions to get the actual definition of that slot. An indirect definition is a list of the form @@ -738,7 +732,8 @@ get_keyelt (Lisp_Object object, bool autoload) } static Lisp_Object -store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def) +store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, + Lisp_Object def, bool remove) { /* Flush any reverse-map cache. */ where_is_cache = Qnil; @@ -770,10 +765,10 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def) be put in the canonical order. */ if (SYMBOLP (idx)) idx = reorder_modifiers (idx); - else if (INTEGERP (idx)) + else if (FIXNUMP (idx)) /* Clobber the high bits that can be present on a machine with more than 24 bits of integer. */ - XSETFASTINT (idx, XINT (idx) & (CHAR_META | (CHAR_META - 1))); + XSETFASTINT (idx, XFIXNUM (idx) & (CHAR_META | (CHAR_META - 1))); /* Scan the keymap for a binding of idx. */ { @@ -785,32 +780,28 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def) towards the front of the alist and character lookups in dense keymaps will remain fast. Otherwise, this just points at the front of the keymap. */ - Lisp_Object insertion_point; - - insertion_point = keymap; + Lisp_Object insertion_point = keymap; for (tail = XCDR (keymap); CONSP (tail); tail = XCDR (tail)) { - Lisp_Object elt; - - elt = XCAR (tail); + Lisp_Object elt = XCAR (tail); if (VECTORP (elt)) { - if (NATNUMP (idx) && XFASTINT (idx) < ASIZE (elt)) + if (FIXNATP (idx) && XFIXNAT (idx) < ASIZE (elt)) { CHECK_IMPURE (elt, XVECTOR (elt)); - ASET (elt, XFASTINT (idx), def); + ASET (elt, XFIXNAT (idx), def); return def; } else if (CONSP (idx) && CHARACTERP (XCAR (idx))) { - int from = XFASTINT (XCAR (idx)); - int to = XFASTINT (XCDR (idx)); + int from = XFIXNAT (XCAR (idx)); + int to = XFIXNAT (XCDR (idx)); if (to >= ASIZE (elt)) to = ASIZE (elt) - 1; for (; from <= to; from++) ASET (elt, from, def); - if (to == XFASTINT (XCDR (idx))) + if (to == XFIXNAT (XCDR (idx))) /* We have defined all keys in IDX. */ return def; } @@ -818,21 +809,26 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def) } else if (CHAR_TABLE_P (elt)) { + Lisp_Object sdef = def; + if (remove) + sdef = Qnil; + /* nil has a special meaning for char-tables, so + we use something else to record an explicitly + unbound entry. */ + else if (NILP (sdef)) + sdef = Qt; + /* Character codes with modifiers are not included in a char-table. All character codes without modifiers are included. */ - if (NATNUMP (idx) && !(XFASTINT (idx) & CHAR_MODIFIER_MASK)) + if (FIXNATP (idx) && !(XFIXNAT (idx) & CHAR_MODIFIER_MASK)) { - 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); + Faset (elt, idx, sdef); return def; } else if (CONSP (idx) && CHARACTERP (XCAR (idx))) { - Fset_char_table_range (elt, idx, NILP (def) ? Qt : def); + Fset_char_table_range (elt, idx, sdef); return def; } insertion_point = tail; @@ -851,20 +847,28 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def) else if (EQ (idx, XCAR (elt))) { CHECK_IMPURE (elt, XCONS (elt)); - XSETCDR (elt, def); + if (remove) + /* Remove the element. */ + insertion_point = Fdelq (elt, insertion_point); + else + /* Just set the definition. */ + XSETCDR (elt, def); return def; } else if (CONSP (idx) && CHARACTERP (XCAR (idx)) && CHARACTERP (XCAR (elt))) { - int from = XFASTINT (XCAR (idx)); - int to = XFASTINT (XCDR (idx)); + int from = XFIXNAT (XCAR (idx)); + int to = XFIXNAT (XCDR (idx)); - if (from <= XFASTINT (XCAR (elt)) - && to >= XFASTINT (XCAR (elt))) + if (from <= XFIXNAT (XCAR (elt)) + && to >= XFIXNAT (XCAR (elt))) { - XSETCDR (elt, def); + if (remove) + insertion_point = Fdelq (elt, insertion_point); + else + XSETCDR (elt, def); if (from == to) return def; } @@ -904,8 +908,10 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def) return def; } +static Lisp_Object copy_keymap_1 (Lisp_Object keymap, int depth); + static Lisp_Object -copy_keymap_item (Lisp_Object elt) +copy_keymap_item (Lisp_Object elt, int depth) { Lisp_Object res, tem; @@ -935,7 +941,7 @@ copy_keymap_item (Lisp_Object elt) elt = XCDR (elt); tem = XCAR (elt); if (CONSP (tem) && EQ (XCAR (tem), Qkeymap)) - XSETCAR (elt, Fcopy_keymap (tem)); + XSETCAR (elt, copy_keymap_1 (tem, depth)); tem = XCDR (elt); } } @@ -956,40 +962,31 @@ copy_keymap_item (Lisp_Object elt) tem = XCDR (elt); } if (CONSP (tem) && EQ (XCAR (tem), Qkeymap)) - XSETCDR (elt, Fcopy_keymap (tem)); + XSETCDR (elt, copy_keymap_1 (tem, depth)); } else if (EQ (XCAR (tem), Qkeymap)) - res = Fcopy_keymap (elt); + res = copy_keymap_1 (elt, depth); } return res; } static void -copy_keymap_1 (Lisp_Object chartable, Lisp_Object idx, Lisp_Object elt) +copy_keymap_set_char_table (Lisp_Object chartable_and_depth, Lisp_Object idx, + Lisp_Object elt) { - Fset_char_table_range (chartable, idx, copy_keymap_item (elt)); + Fset_char_table_range + (XCAR (chartable_and_depth), idx, + copy_keymap_item (elt, XFIXNUM (XCDR (chartable_and_depth)))); } -DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 0, - doc: /* Return a copy of the keymap KEYMAP. - -Note that this is almost never needed. If you want a keymap that's like -another yet with a few changes, you should use map inheritance rather -than copying. I.e. something like: - - (let ((map (make-sparse-keymap))) - (set-keymap-parent map <theirmap>) - (define-key map ...) - ...) - -After performing `copy-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. */) - (Lisp_Object keymap) +static Lisp_Object +copy_keymap_1 (Lisp_Object keymap, int depth) { Lisp_Object copy, tail; + + if (depth > 100) + error ("Possible infinite recursion when copying keymap"); + keymap = get_keymap (keymap, 1, 0); copy = tail = list1 (Qkeymap); keymap = XCDR (keymap); /* Skip the `keymap' symbol. */ @@ -1000,22 +997,22 @@ is not copied. */) if (CHAR_TABLE_P (elt)) { elt = Fcopy_sequence (elt); - map_char_table (copy_keymap_1, Qnil, elt, elt); + map_char_table (copy_keymap_set_char_table, Qnil, elt, + Fcons (elt, make_fixnum (depth + 1))); } else if (VECTORP (elt)) { - int i; elt = Fcopy_sequence (elt); - for (i = 0; i < ASIZE (elt); i++) - ASET (elt, i, copy_keymap_item (AREF (elt, i))); + for (int i = 0; i < ASIZE (elt); i++) + ASET (elt, i, copy_keymap_item (AREF (elt, i), depth + 1)); } else if (CONSP (elt)) { if (EQ (XCAR (elt), Qkeymap)) /* This is a sub keymap. */ - elt = Fcopy_keymap (elt); + elt = copy_keymap_1 (elt, depth + 1); else - elt = Fcons (XCAR (elt), copy_keymap_item (XCDR (elt))); + elt = Fcons (XCAR (elt), copy_keymap_item (XCDR (elt), depth + 1)); } XSETCDR (tail, list1 (elt)); tail = XCDR (tail); @@ -1024,13 +1021,67 @@ is not copied. */) XSETCDR (tail, keymap); return copy; } + +DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 0, + doc: /* Return a copy of the keymap KEYMAP. + +Note that this is almost never needed. If you want a keymap that's like +another yet with a few changes, you should use keymap inheritance rather +than copying. That is, something like: + + (defvar-keymap foo-map + :parent <theirmap> + ...) + +Or, if you need to support Emacs versions older than 29: + + (let ((map (make-sparse-keymap))) + (set-keymap-parent map <theirmap>) + (define-key map ...) + ...) + +After performing `copy-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. */) + (Lisp_Object keymap) +{ + return copy_keymap_1 (keymap, 0); +} + /* Simple Keymap mutators and accessors. */ +static Lisp_Object +possibly_translate_key_sequence (Lisp_Object key, ptrdiff_t *length) +{ + if (VECTORP (key) && ASIZE (key) == 1 && STRINGP (AREF (key, 0))) + { + /* KEY is on the ["C-c"] format, so translate to internal + format. */ + if (NILP (Ffboundp (Qkey_valid_p))) + xsignal2 (Qerror, + build_string ("`key-valid-p' is not defined, so this syntax can't be used: %s"), + key); + if (NILP (call1 (Qkey_valid_p, AREF (key, 0)))) + xsignal2 (Qerror, build_string ("Invalid `key-parse' syntax: %S"), key); + key = call1 (Qkey_parse, AREF (key, 0)); + *length = CHECK_VECTOR_OR_STRING (key); + if (*length == 0) + xsignal2 (Qerror, build_string ("Invalid `key-parse' syntax: %S"), key); + } + + return key; +} + /* GC is possible in this function if it autoloads a keymap. */ -DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0, +DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 4, 0, doc: /* In KEYMAP, define key sequence KEY as DEF. +This is a legacy function; see `keymap-set' for the recommended +function to use instead. + KEYMAP is a keymap. KEY is a string or a vector of symbols and characters, representing a @@ -1050,38 +1101,38 @@ DEF is anything that can be a key's definition: 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), + (DEFN should be a valid definition in its own right) and + STRING is the menu item name (which is used only if the containing + keymap has been created with a menu name, see `make-keymap'), or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP, or an extended menu item definition. (See info node `(elisp)Extended Menu Items'.) +If REMOVE is non-nil, the definition will be removed. This is almost +the same as setting the definition to nil, but makes a difference if +the KEYMAP has a parent, and KEY is shadowing the same binding in the +parent. With REMOVE, subsequent lookups will return the binding in +the parent, and with a nil DEF, the lookups will return nil. + If KEYMAP is a sparse keymap with a binding for KEY, the existing binding is altered. If there is no binding for KEY, the new pair binding KEY to DEF is added at the front of KEYMAP. */) - (Lisp_Object keymap, Lisp_Object key, Lisp_Object def) + (Lisp_Object keymap, Lisp_Object key, Lisp_Object def, Lisp_Object remove) { - ptrdiff_t idx; - Lisp_Object c; - Lisp_Object cmd; - bool metized = 0; - int meta_bit; - ptrdiff_t length; + bool metized = false; keymap = get_keymap (keymap, 1, 1); - length = CHECK_VECTOR_OR_STRING (key); + ptrdiff_t length = CHECK_VECTOR_OR_STRING (key); if (length == 0) return Qnil; - if (SYMBOLP (def) && !EQ (Vdefine_key_rebound_commands, Qt)) - Vdefine_key_rebound_commands = Fcons (def, Vdefine_key_rebound_commands); - - meta_bit = (VECTORP (key) || (STRINGP (key) && STRING_MULTIBYTE (key)) - ? meta_modifier : 0x80); + int meta_bit = (VECTORP (key) || (STRINGP (key) && STRING_MULTIBYTE (key)) + ? meta_modifier : 0x80); if (VECTORP (def) && ASIZE (def) > 0 && CONSP (AREF (def, 0))) { /* DEF is apparently an XEmacs-style keyboard macro. */ - Lisp_Object tmp = Fmake_vector (make_number (ASIZE (def)), Qnil); + Lisp_Object tmp = make_nil_vector (ASIZE (def)); ptrdiff_t i = ASIZE (def); while (--i >= 0) { @@ -1093,10 +1144,12 @@ binding KEY to DEF is added at the front of KEYMAP. */) def = tmp; } - idx = 0; + key = possibly_translate_key_sequence (key, &length); + + ptrdiff_t idx = 0; while (1) { - c = Faref (key, make_number (idx)); + Lisp_Object c = Faref (key, make_fixnum (idx)); if (CONSP (c)) { @@ -1111,32 +1164,32 @@ binding KEY to DEF is added at the front of KEYMAP. */) if (SYMBOLP (c)) silly_event_symbol_error (c); - if (INTEGERP (c) - && (XINT (c) & meta_bit) + if (FIXNUMP (c) + && (XFIXNUM (c) & meta_bit) && !metized) { c = meta_prefix_char; - metized = 1; + metized = true; } else { - if (INTEGERP (c)) - XSETINT (c, XINT (c) & ~meta_bit); + if (FIXNUMP (c)) + XSETINT (c, XFIXNUM (c) & ~meta_bit); - metized = 0; + metized = false; idx++; } - if (!INTEGERP (c) && !SYMBOLP (c) + if (!FIXNUMP (c) && !SYMBOLP (c) && (!CONSP (c) /* If C is a range, it must be a leaf. */ - || (INTEGERP (XCAR (c)) && idx != length))) + || (FIXNUMP (XCAR (c)) && idx != length))) message_with_string ("Key sequence contains invalid event %s", c, 1); if (idx == length) - return store_in_keymap (keymap, c, def); + return store_in_keymap (keymap, c, def, !NILP (remove)); - cmd = access_keymap (keymap, c, 0, 1, 1); + Lisp_Object cmd = access_keymap (keymap, c, 0, 1, 1); /* If this key is undefined, make it a prefix. */ if (NILP (cmd)) @@ -1153,8 +1206,8 @@ binding KEY to DEF is added at the front of KEYMAP. */) error; key might be a vector, not a string. */ error ("Key sequence %s starts with non-prefix key %s%s", SDATA (Fkey_description (key, Qnil)), - SDATA (Fkey_description (Fsubstring (key, make_number (0), - make_number (idx)), + SDATA (Fkey_description (Fsubstring (key, make_fixnum (0), + make_fixnum (idx)), Qnil)), trailing_esc); } @@ -1174,7 +1227,7 @@ number or marker, in which case the keymap properties at the specified buffer position instead of point are used. The KEYMAPS argument is ignored if POSITION is non-nil. -If the optional argument KEYMAPS is non-nil, it should be a list of +If the optional argument KEYMAPS is non-nil, it should be a keymap or list of keymaps to search for command remapping. Otherwise, search for the remapping in all currently active keymaps. */) (Lisp_Object command, Lisp_Object position, Lisp_Object keymaps) @@ -1187,16 +1240,61 @@ remapping in all currently active keymaps. */) if (NILP (keymaps)) command = Fkey_binding (command_remapping_vector, Qnil, Qt, position); else - command = Flookup_key (Fcons (Qkeymap, keymaps), - command_remapping_vector, Qnil); - return INTEGERP (command) ? Qnil : command; + command = Flookup_key (keymaps, command_remapping_vector, Qnil); + return FIXNUMP (command) ? Qnil : command; +} + +static Lisp_Object +lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default) +{ + bool t_ok = !NILP (accept_default); + + if (!CONSP (keymap) && !NILP (keymap)) + keymap = get_keymap (keymap, true, true); + + ptrdiff_t length = CHECK_VECTOR_OR_STRING (key); + if (length == 0) + return keymap; + + key = possibly_translate_key_sequence (key, &length); + + ptrdiff_t idx = 0; + while (1) + { + Lisp_Object c = Faref (key, make_fixnum (idx++)); + + if (CONSP (c) && lucid_event_type_list_p (c)) + c = Fevent_convert_list (c); + + /* Turn the 8th bit of string chars into a meta modifier. */ + if (STRINGP (key) && XFIXNUM (c) & 0x80 && !STRING_MULTIBYTE (key)) + XSETINT (c, (XFIXNUM (c) | meta_modifier) & ~0x80); + + /* Allow string since binding for `menu-bar-select-buffer' + includes the buffer name in the key sequence. */ + if (!FIXNUMP (c) && !SYMBOLP (c) && !CONSP (c) && !STRINGP (c)) + message_with_string ("Key sequence contains invalid event %s", c, 1); + + Lisp_Object cmd = access_keymap (keymap, c, t_ok, 0, 1); + if (idx == length) + return cmd; + + keymap = get_keymap (cmd, 0, 1); + if (!CONSP (keymap)) + return make_fixnum (idx); + + maybe_quit (); + } } /* Value is number if KEY is too long; nil if valid but has no definition. */ /* GC is possible in this function. */ DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0, - doc: /* In keymap KEYMAP, look up key sequence KEY. Return the definition. + doc: /* Look up key sequence KEY in KEYMAP. Return the definition. +This is a legacy function; see `keymap-lookup' for the recommended +function to use instead. + A value of nil means undefined. See doc of `define-key' for kinds of definitions. @@ -1205,6 +1303,7 @@ 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 key. +KEYMAP can also be a list of keymaps. Normally, `lookup-key' ignores bindings for t, which act as default bindings, used when nothing else in the keymap applies; this makes it @@ -1213,45 +1312,132 @@ third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will recognize the default bindings, just as `read-key-sequence' does. */) (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default) { - ptrdiff_t idx; - Lisp_Object cmd; - Lisp_Object c; - ptrdiff_t length; - bool t_ok = !NILP (accept_default); + Lisp_Object found = lookup_key_1 (keymap, key, accept_default); + if (!NILP (found) && !NUMBERP (found)) + return found; - keymap = get_keymap (keymap, 1, 1); + /* Menu definitions might use mixed case symbols (notably in old + versions of `easy-menu-define'), or use " " instead of "-". + The rest of this function is about accepting these variations for + backwards-compatibility. (Bug#50752) */ - length = CHECK_VECTOR_OR_STRING (key); - if (length == 0) - return keymap; + /* Just skip everything below unless this is a menu item. */ + if (!VECTORP (key) || !(ASIZE (key) > 0) + || !EQ (AREF (key, 0), Qmenu_bar)) + return found; - idx = 0; - while (1) + /* Initialize the unicode case table, if it wasn't already. */ + if (NILP (unicode_case_table)) { - c = Faref (key, make_number (idx++)); + unicode_case_table = uniprop_table (intern ("lowercase")); + /* uni-lowercase.el might be unavailable during bootstrap. */ + if (NILP (unicode_case_table)) + return found; + staticpro (&unicode_case_table); + } - if (CONSP (c) && lucid_event_type_list_p (c)) - c = Fevent_convert_list (c); + ptrdiff_t key_len = ASIZE (key); + Lisp_Object new_key = make_vector (key_len, Qnil); - /* Turn the 8th bit of string chars into a meta modifier. */ - if (STRINGP (key) && XINT (c) & 0x80 && !STRING_MULTIBYTE (key)) - XSETINT (c, (XINT (c) | meta_modifier) & ~0x80); + /* Try both the Unicode case table, and the buffer local one. + Otherwise, we will fail for e.g. the "Turkish" language + environment where 'I' does not downcase to 'i'. */ + Lisp_Object tables[2] = {unicode_case_table, Fcurrent_case_table ()}; + for (int tbl_num = 0; tbl_num < 2; tbl_num++) + { + /* First, let's try converting all symbols like "Foo-Bar-Baz" to + "foo-bar-baz". */ + for (int i = 0; i < key_len; i++) + { + Lisp_Object item = AREF (key, i); + if (!SYMBOLP (item)) + ASET (new_key, i, item); + else + { + Lisp_Object key_item = Fsymbol_name (item); + Lisp_Object new_item; + if (!STRING_MULTIBYTE (key_item)) + new_item = Fdowncase (key_item); + else + { + USE_SAFE_ALLOCA; + ptrdiff_t size = SCHARS (key_item), n; + if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n)) + n = PTRDIFF_MAX; + unsigned char *dst = SAFE_ALLOCA (n); + unsigned char *p = dst; + ptrdiff_t j_char = 0, j_byte = 0; + + while (j_char < size) + { + int ch = fetch_string_char_advance (key_item, + &j_char, &j_byte); + Lisp_Object ch_conv = CHAR_TABLE_REF (tables[tbl_num], + ch); + if (!NILP (ch_conv)) + CHAR_STRING (XFIXNUM (ch_conv), p); + else + CHAR_STRING (ch, p); + p = dst + j_byte; + } + new_item = make_multibyte_string ((char *) dst, + SCHARS (key_item), + SBYTES (key_item)); + SAFE_FREE (); + } + ASET (new_key, i, Fintern (new_item, Qnil)); + } + } - /* 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)) - message_with_string ("Key sequence contains invalid event %s", c, 1); + /* Check for match. */ + found = lookup_key_1 (keymap, new_key, accept_default); + if (!NILP (found) && !NUMBERP (found)) + break; - cmd = access_keymap (keymap, c, t_ok, 0, 1); - if (idx == length) - return cmd; + /* If we still don't have a match, let's convert any spaces in + our lowercased string into dashes, e.g. "foo bar baz" to + "foo-bar-baz". */ + for (int i = 0; i < key_len; i++) + { + if (!SYMBOLP (AREF (new_key, i))) + continue; - keymap = get_keymap (cmd, 0, 1); - if (!CONSP (keymap)) - return make_number (idx); + Lisp_Object lc_key = Fsymbol_name (AREF (new_key, i)); - maybe_quit (); + /* If there are no spaces in this symbol, just skip it. */ + if (!strstr (SSDATA (lc_key), " ")) + continue; + + USE_SAFE_ALLOCA; + ptrdiff_t size = SCHARS (lc_key), n; + if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n)) + n = PTRDIFF_MAX; + unsigned char *dst = SAFE_ALLOCA (n); + + /* We can walk the string data byte by byte, because UTF-8 + encoding ensures that no other byte of any multibyte + sequence will ever include a 7-bit byte equal to an ASCII + single-byte character. */ + memcpy (dst, SSDATA (lc_key), SBYTES (lc_key)); + for (int i = 0; i < SBYTES (lc_key); ++i) + { + if (dst[i] == ' ') + dst[i] = '-'; + } + Lisp_Object new_it = + make_multibyte_string ((char *) dst, + SCHARS (lc_key), SBYTES (lc_key)); + ASET (new_key, i, Fintern (new_it, Qnil)); + SAFE_FREE (); + } + + /* Check for match. */ + found = lookup_key_1 (keymap, new_key, accept_default); + if (!NILP (found) && !NUMBERP (found)) + break; } + + return found; } /* Make KEYMAP define event C as a keymap (i.e., as a prefix). @@ -1261,10 +1447,8 @@ recognize the default bindings, just as `read-key-sequence' does. */) static Lisp_Object define_as_prefix (Lisp_Object keymap, Lisp_Object c) { - Lisp_Object cmd; - - cmd = Fmake_sparse_keymap (Qnil); - store_in_keymap (keymap, c, cmd); + Lisp_Object cmd = Fmake_sparse_keymap (Qnil); + store_in_keymap (keymap, c, cmd, false); return cmd; } @@ -1278,21 +1462,18 @@ append_key (Lisp_Object key_sequence, Lisp_Object key) return CALLN (Fvconcat, key_sequence, key_list); } -/* Given a event type C which is a symbol, +/* Given an 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 (Lisp_Object c) { - Lisp_Object parsed, base, name, assoc; - int modifiers; - - parsed = parse_modifiers (c); - modifiers = XFASTINT (XCAR (XCDR (parsed))); - base = XCAR (parsed); - name = Fsymbol_name (base); + Lisp_Object parsed = parse_modifiers (c); + int modifiers = XFIXNAT (XCAR (XCDR (parsed))); + Lisp_Object base = XCAR (parsed); + Lisp_Object name = Fsymbol_name (base); /* This alist includes elements such as ("RET" . "\\r"). */ - assoc = Fassoc (name, exclude_keys, Qnil); + Lisp_Object assoc = Fassoc (name, exclude_keys, Qnil); if (! NILP (assoc)) { @@ -1353,16 +1534,14 @@ ptrdiff_t current_minor_maps (Lisp_Object **modeptr, Lisp_Object **mapptr) { ptrdiff_t i = 0; - int list_number = 0; Lisp_Object alist, assoc, var, val; - Lisp_Object emulation_alists; + Lisp_Object emulation_alists = Vemulation_mode_map_alists; Lisp_Object lists[2]; - emulation_alists = Vemulation_mode_map_alists; lists[0] = Vminor_mode_overriding_map_alist; lists[1] = Vminor_mode_map_alist; - for (list_number = 0; list_number < 2; list_number++) + for (int list_number = 0; list_number < 2; list_number++) { if (CONSP (emulation_alists)) { @@ -1378,7 +1557,7 @@ current_minor_maps (Lisp_Object **modeptr, Lisp_Object **mapptr) for ( ; CONSP (alist); alist = XCDR (alist)) if ((assoc = XCAR (alist), CONSP (assoc)) && (var = XCAR (assoc), SYMBOLP (var)) - && (val = find_symbol_value (var), !EQ (val, Qunbound)) + && (val = find_symbol_value (var), !BASE_EQ (val, Qunbound)) && !NILP (val)) { Lisp_Object temp; @@ -1462,7 +1641,7 @@ current_minor_maps (Lisp_Object **modeptr, Lisp_Object **mapptr) static ptrdiff_t click_position (Lisp_Object position) { - EMACS_INT pos = (INTEGERP (position) ? XINT (position) + EMACS_INT pos = (FIXNUMP (position) ? XFIXNUM (position) : MARKERP (position) ? marker_position (position) : PT); if (! (BEGV <= pos && pos <= ZV)) @@ -1478,7 +1657,7 @@ OLP if non-nil indicates that we should obey `overriding-local-map' and like in the respective argument of `key-binding'. */) (Lisp_Object olp, Lisp_Object position) { - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); Lisp_Object keymaps = list1 (current_global_map); @@ -1488,9 +1667,7 @@ like in the respective argument of `key-binding'. */) if (CONSP (position)) { - Lisp_Object window; - - window = POSN_WINDOW (position); + Lisp_Object window = POSN_WINDOW (position); if (WINDOWP (window) && BUFFERP (XWINDOW (window)->contents) @@ -1519,7 +1696,7 @@ like in the respective argument of `key-binding'. */) if (NILP (XCDR (keymaps))) { Lisp_Object *maps; - int nmaps, i; + int nmaps; ptrdiff_t pt = click_position (position); /* This usually returns the buffer's local map, but that can be overridden by a `local-map' property. */ @@ -1537,16 +1714,14 @@ like in the respective argument of `key-binding'. */) if (POSN_INBUFFER_P (position)) { - Lisp_Object pos; - - pos = POSN_BUFFER_POSN (position); - if (INTEGERP (pos) - && XINT (pos) >= BEG && XINT (pos) <= Z) + Lisp_Object pos = POSN_BUFFER_POSN (position); + if (FIXNUMP (pos) + && XFIXNUM (pos) >= BEG && XFIXNUM (pos) <= Z) { - local_map = get_local_map (XINT (pos), + local_map = get_local_map (XFIXNUM (pos), current_buffer, Qlocal_map); - keymap = get_local_map (XINT (pos), + keymap = get_local_map (XFIXNUM (pos), current_buffer, Qkeymap); } } @@ -1559,15 +1734,13 @@ like in the respective argument of `key-binding'. */) if (CONSP (string) && STRINGP (XCAR (string))) { - Lisp_Object pos, map; - - pos = XCDR (string); + Lisp_Object pos = XCDR (string); string = XCAR (string); - if (INTEGERP (pos) - && XINT (pos) >= 0 - && XINT (pos) < SCHARS (string)) + if (FIXNUMP (pos) + && XFIXNUM (pos) >= 0 + && XFIXNUM (pos) < SCHARS (string)) { - map = Fget_text_property (pos, Qlocal_map, string); + Lisp_Object map = Fget_text_property (pos, Qlocal_map, string); if (!NILP (map)) local_map = map; @@ -1585,7 +1758,7 @@ like in the respective argument of `key-binding'. */) /* Now put all the minor mode keymaps on the list. */ nmaps = current_minor_maps (0, &maps); - for (i = --nmaps; i >= 0; i--) + for (int i = --nmaps; i >= 0; i--) if (!NILP (maps[i])) keymaps = Fcons (maps[i], keymaps); @@ -1596,9 +1769,7 @@ like in the respective argument of `key-binding'. */) keymaps = Fcons (otlp, keymaps); } - unbind_to (count, Qnil); - - return keymaps; + return unbind_to (count, keymaps); } /* GC is possible in this function if it autoloads a keymap. */ @@ -1631,18 +1802,15 @@ specified buffer position instead of point are used. */) (Lisp_Object key, Lisp_Object accept_default, Lisp_Object no_remap, Lisp_Object position) { - Lisp_Object value; - if (NILP (position) && VECTORP (key)) { - Lisp_Object event; - if (ASIZE (key) == 0) return Qnil; /* mouse events may have a symbolic prefix indicating the scrollbar or mode line */ - event = AREF (key, SYMBOLP (AREF (key, 0)) && ASIZE (key) > 1 ? 1 : 0); + Lisp_Object event + = AREF (key, SYMBOLP (AREF (key, 0)) && ASIZE (key) > 1 ? 1 : 0); /* We are not interested in locations without event data */ @@ -1654,10 +1822,10 @@ specified buffer position instead of point are used. } } - value = Flookup_key (Fcons (Qkeymap, Fcurrent_active_maps (Qt, position)), - key, accept_default); + Lisp_Object value = Flookup_key (Fcurrent_active_maps (Qt, position), + key, accept_default); - if (NILP (value) || INTEGERP (value)) + if (NILP (value) || FIXNUMP (value)) return Qnil; /* If the result of the ordinary keymap lookup is an interactive @@ -1675,40 +1843,6 @@ specified buffer position instead of point are used. /* GC is possible in this function if it autoloads a keymap. */ -DEFUN ("local-key-binding", Flocal_key_binding, Slocal_key_binding, 1, 2, 0, - doc: /* Return the binding for command KEYS in current local keymap only. -KEYS is a string or vector, 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. */) - (Lisp_Object keys, Lisp_Object accept_default) -{ - register Lisp_Object map; - map = BVAR (current_buffer, keymap); - if (NILP (map)) - return Qnil; - return Flookup_key (map, keys, accept_default); -} - -/* GC is possible in this function if it autoloads a keymap. */ - -DEFUN ("global-key-binding", Fglobal_key_binding, Sglobal_key_binding, 1, 2, 0, - doc: /* Return the binding for command KEYS in current global keymap only. -KEYS is a string or vector, 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. */) - (Lisp_Object keys, Lisp_Object accept_default) -{ - return Flookup_key (current_global_map, keys, accept_default); -} - -/* 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, doc: /* Find the visible minor mode bindings of KEY. Return an alist of pairs (MODENAME . BINDING), where MODENAME is @@ -1724,18 +1858,14 @@ bindings; see the description of `lookup-key' for more details about this. */) (Lisp_Object key, Lisp_Object accept_default) { Lisp_Object *modes, *maps; - int nmaps; - Lisp_Object binding; - int i, j; - - nmaps = current_minor_maps (&modes, &maps); + int nmaps = current_minor_maps (&modes, &maps); + Lisp_Object binding = Qnil; - binding = Qnil; - - for (i = j = 0; i < nmaps; i++) + int j; + for (int i = j = 0; i < nmaps; i++) if (!NILP (maps[i]) && !NILP (binding = Flookup_key (maps[i], key, accept_default)) - && !INTEGERP (binding)) + && !FIXNUMP (binding)) { if (KEYMAPP (binding)) maps[j++] = Fcons (modes[i], binding); @@ -1746,29 +1876,6 @@ bindings; see the description of `lookup-key' for more details about this. */) return Flist (j, maps); } -DEFUN ("define-prefix-command", Fdefine_prefix_command, Sdefine_prefix_command, 1, 3, 0, - 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. -This prepares COMMAND for use as a prefix key's binding. -If a second optional argument MAPVAR is given, it should be a symbol. -The map is then stored as MAPVAR's 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. -This function returns COMMAND. */) - (Lisp_Object command, Lisp_Object mapvar, Lisp_Object name) -{ - Lisp_Object map; - map = Fmake_sparse_keymap (name); - Ffset (command, map); - if (!NILP (mapvar)) - Fset (mapvar, map); - else - Fset (command, map); - return command; -} - DEFUN ("use-global-map", Fuse_global_map, Suse_global_map, 1, 1, 0, doc: /* Select KEYMAP as the global keymap. */) (Lisp_Object keymap) @@ -1833,7 +1940,7 @@ accessible_keymaps_1 (Lisp_Object key, Lisp_Object cmd, Lisp_Object args, void * Lisp_Object maps = d->maps; Lisp_Object tail = d->tail; Lisp_Object thisseq = d->thisseq; - bool is_metized = d->is_metized && INTEGERP (key); + bool is_metized = d->is_metized && FIXNUMP (key); Lisp_Object tem; cmd = get_keymap (get_keyelt (cmd, 0), 0, 0); @@ -1844,12 +1951,12 @@ accessible_keymaps_1 (Lisp_Object key, Lisp_Object cmd, Lisp_Object args, void * while (!NILP (tem = Frassq (cmd, maps))) { Lisp_Object prefix = XCAR (tem); - ptrdiff_t lim = XINT (Flength (XCAR (tem))); - if (lim <= XINT (Flength (thisseq))) + ptrdiff_t lim = XFIXNUM (Flength (XCAR (tem))); + if (lim <= XFIXNUM (Flength (thisseq))) { /* This keymap was already seen with a smaller prefix. */ ptrdiff_t i = 0; - while (i < lim && EQ (Faref (prefix, make_number (i)), - Faref (thisseq, make_number (i)))) + while (i < lim && EQ (Faref (prefix, make_fixnum (i)), + Faref (thisseq, make_fixnum (i)))) i++; if (i >= lim) /* `prefix' is a prefix of `thisseq' => there's a cycle. */ @@ -1869,10 +1976,10 @@ accessible_keymaps_1 (Lisp_Object key, Lisp_Object cmd, Lisp_Object args, void * if (is_metized) { int meta_bit = meta_modifier; - Lisp_Object last = make_number (XINT (Flength (thisseq)) - 1); + Lisp_Object last = make_fixnum (XFIXNUM (Flength (thisseq)) - 1); tem = Fcopy_sequence (thisseq); - Faset (tem, last, make_number (XINT (key) | meta_bit)); + Faset (tem, last, make_fixnum (XFIXNUM (key) | meta_bit)); /* This new sequence is the same length as thisseq, so stick it in the list right @@ -1900,14 +2007,13 @@ then the value includes only maps for prefixes that start with PREFIX. */) (Lisp_Object keymap, Lisp_Object prefix) { Lisp_Object maps, tail; - EMACS_INT prefixlen = XFASTINT (Flength (prefix)); + EMACS_INT prefixlen = XFIXNAT (Flength (prefix)); if (!NILP (prefix)) { /* If a prefix was specified, start with the keymap (if any) for that prefix, so we don't waste time considering other prefixes. */ - Lisp_Object tem; - tem = Flookup_key (keymap, prefix, Qt); + Lisp_Object tem = Flookup_key (keymap, prefix, Qt); /* 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. */ @@ -1920,18 +2026,15 @@ then the value includes only maps for prefixes that start with PREFIX. */) we don't have to deal with the possibility of a string. */ if (STRINGP (prefix)) { - int i, i_byte, c; - Lisp_Object copy; - - copy = Fmake_vector (make_number (SCHARS (prefix)), Qnil); - for (i = 0, i_byte = 0; i < SCHARS (prefix);) + ptrdiff_t i_byte = 0; + Lisp_Object copy = make_nil_vector (SCHARS (prefix)); + for (ptrdiff_t i = 0; i < SCHARS (prefix); ) { - int i_before = i; - - FETCH_STRING_CHAR_ADVANCE (c, prefix, i, i_byte); + ptrdiff_t i_before = i; + int c = fetch_string_char_advance (prefix, &i, &i_byte); if (SINGLE_BYTE_CHAR_P (c) && (c & 0200)) c ^= 0200 | meta_modifier; - ASET (copy, i_before, make_number (c)); + ASET (copy, i_before, make_fixnum (c)); } prefix = copy; } @@ -1959,11 +2062,11 @@ then the value includes only maps for prefixes that start with PREFIX. */) data.thisseq = Fcar (XCAR (tail)); data.maps = maps; data.tail = tail; - last = make_number (XINT (Flength (data.thisseq)) - 1); + last = make_fixnum (XFIXNUM (Flength (data.thisseq)) - 1); /* Does the current sequence end in the meta-prefix-char? */ - data.is_metized = (XINT (last) >= 0 + data.is_metized = (XFIXNUM (last) >= 0 /* Don't metize the last char of PREFIX. */ - && XINT (last) >= prefixlen + && XFIXNUM (last) >= prefixlen && EQ (Faref (data.thisseq, last), meta_prefix_char)); /* Since we can't run lisp code, we can't scan autoloaded maps. */ @@ -1978,29 +2081,22 @@ then the value includes only maps for prefixes that start with PREFIX. */) DEFUN ("key-description", Fkey_description, Skey_description, 1, 2, 0, doc: /* Return a pretty description of key-sequence KEYS. Optional arg PREFIX is the sequence of keys leading up to KEYS. -For example, [?\C-x ?l] is converted into the string \"C-x l\". +For example, [?\\C-x ?l] is converted into the string \"C-x l\". For an approximate inverse of this, see `kbd'. */) (Lisp_Object keys, Lisp_Object prefix) { ptrdiff_t len = 0; - EMACS_INT i; - ptrdiff_t i_byte; Lisp_Object *args; - EMACS_INT size = XINT (Flength (keys)); - Lisp_Object list; + EMACS_INT nkeys = XFIXNUM (Flength (keys)); + EMACS_INT nprefix = XFIXNUM (Flength (prefix)); Lisp_Object sep = build_string (" "); - Lisp_Object key; - Lisp_Object result; - bool add_meta = 0; + bool add_meta = false; USE_SAFE_ALLOCA; - if (!NILP (prefix)) - size += XINT (Flength (prefix)); - /* This has one extra element at the end that we don't pass to Fconcat. */ - EMACS_INT size4; - if (INT_MULTIPLY_WRAPV (size, 4, &size4)) + ptrdiff_t size4; + if (INT_MULTIPLY_WRAPV (nkeys + nprefix, 4, &size4)) memory_full (SIZE_MAX); SAFE_ALLOCA_LISP (args, size4); @@ -2008,82 +2104,76 @@ For an approximate inverse of this, see `kbd'. */) (mapconcat 'single-key-description keys " ") but we shouldn't use mapconcat because it can do GC. */ - next_list: - if (!NILP (prefix)) - list = prefix, prefix = Qnil; - else if (!NILP (keys)) - list = keys, keys = Qnil; - else + Lisp_Object lists[2] = { prefix, keys }; + ptrdiff_t listlens[2] = { nprefix, nkeys }; + for (int li = 0; li < ARRAYELTS (lists); li++) { - if (add_meta) - { - args[len] = Fsingle_key_description (meta_prefix_char, Qnil); - result = Fconcat (len + 1, args); - } - else if (len == 0) - result = empty_unibyte_string; - else - result = Fconcat (len - 1, args); - SAFE_FREE (); - return result; - } + Lisp_Object list = lists[li]; + ptrdiff_t listlen = listlens[li], i_byte = 0; - if (STRINGP (list)) - size = SCHARS (list); - else if (VECTORP (list)) - size = ASIZE (list); - else if (CONSP (list)) - size = XINT (Flength (list)); - else - wrong_type_argument (Qarrayp, list); - - i = i_byte = 0; + if (! (NILP (list) || STRINGP (list) || VECTORP (list) || CONSP (list))) + wrong_type_argument (Qarrayp, list); - while (i < size) - { - if (STRINGP (list)) + for (ptrdiff_t i = 0; i < listlen; ) { - int c; - FETCH_STRING_CHAR_ADVANCE (c, list, i, i_byte); - if (SINGLE_BYTE_CHAR_P (c) && (c & 0200)) - c ^= 0200 | meta_modifier; - XSETFASTINT (key, c); - } - else if (VECTORP (list)) - { - key = AREF (list, i); i++; - } - else - { - key = XCAR (list); - list = XCDR (list); - i++; - } - - if (add_meta) - { - if (!INTEGERP (key) - || EQ (key, meta_prefix_char) - || (XINT (key) & meta_modifier)) + Lisp_Object key; + if (STRINGP (list)) { - args[len++] = Fsingle_key_description (meta_prefix_char, Qnil); - args[len++] = sep; - if (EQ (key, meta_prefix_char)) - continue; + int c = fetch_string_char_advance (list, &i, &i_byte); + if (SINGLE_BYTE_CHAR_P (c) && (c & 0200)) + c ^= 0200 | meta_modifier; + key = make_fixnum (c); + } + else if (VECTORP (list)) + { + key = AREF (list, i); + i++; } else - XSETINT (key, XINT (key) | meta_modifier); - add_meta = 0; - } - else if (EQ (key, meta_prefix_char)) - { - add_meta = 1; - continue; + { + key = XCAR (list); + list = XCDR (list); + i++; + } + + if (add_meta) + { + if (!FIXNUMP (key) + || EQ (key, meta_prefix_char) + || (XFIXNUM (key) & meta_modifier)) + { + args[len++] = Fsingle_key_description (meta_prefix_char, + Qnil); + args[len++] = sep; + if (EQ (key, meta_prefix_char)) + continue; + } + else + key = make_fixnum (XFIXNUM (key) | meta_modifier); + add_meta = false; + } + else if (EQ (key, meta_prefix_char)) + { + add_meta = true; + continue; + } + args[len++] = Fsingle_key_description (key, Qnil); + args[len++] = sep; } - args[len++] = Fsingle_key_description (key, Qnil); - args[len++] = sep; } - goto next_list; + + Lisp_Object result; + if (add_meta) + { + args[len] = Fsingle_key_description (meta_prefix_char, Qnil); + result = Fconcat (len + 1, args); + } + else if (len == 0) + result = empty_unibyte_string; + else + result = Fconcat (len - 1, args); + SAFE_FREE (); + return result; } @@ -2098,7 +2188,7 @@ push_key_description (EMACS_INT ch, char *p) c2 = c & ~(alt_modifier | ctrl_modifier | hyper_modifier | meta_modifier | shift_modifier | super_modifier); - if (! CHARACTERP (make_number (c2))) + if (! CHARACTERP (make_fixnum (c2))) { /* KEY_DESCRIPTION_SIZE is large enough for this. */ p += sprintf (p, "[%d]", c); @@ -2205,10 +2295,12 @@ push_key_description (EMACS_INT ch, char *p) DEFUN ("single-key-description", Fsingle_key_description, Ssingle_key_description, 1, 2, 0, - doc: /* Return a pretty description of command character KEY. + doc: /* Return a pretty description of a character event 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. */) +around function keys and event symbols. + +See `text-char-description' for describing character codes. */) (Lisp_Object key, Lisp_Object no_angles) { USE_SAFE_ALLOCA; @@ -2216,7 +2308,7 @@ around function keys and event symbols. */) if (CONSP (key) && lucid_event_type_list_p (key)) key = Fevent_convert_list (key); - if (CONSP (key) && INTEGERP (XCAR (key)) && INTEGERP (XCDR (key))) + if (CONSP (key) && FIXNUMP (XCAR (key)) && FIXNUMP (XCDR (key))) /* An interval from a map-char-table. */ { AUTO_STRING (dot_dot, ".."); @@ -2227,10 +2319,10 @@ around function keys and event symbols. */) key = EVENT_HEAD (key); - if (INTEGERP (key)) /* Normal character. */ + if (FIXNUMP (key)) /* Normal character. */ { char tem[KEY_DESCRIPTION_SIZE]; - char *p = push_key_description (XINT (key), tem); + char *p = push_key_description (XFIXNUM (key), tem); *p = 0; return make_specified_string (tem, -1, p - tem, 1); } @@ -2238,11 +2330,21 @@ around function keys and event symbols. */) { if (NILP (no_angles)) { - Lisp_Object result; - char *buffer = SAFE_ALLOCA (sizeof "<>" - + SBYTES (SYMBOL_NAME (key))); - esprintf (buffer, "<%s>", SDATA (SYMBOL_NAME (key))); - result = build_string (buffer); + Lisp_Object namestr = SYMBOL_NAME (key); + const char *sym = SSDATA (namestr); + ptrdiff_t len = SBYTES (namestr); + /* Find the extent of the modifier prefix, like "C-M-". */ + int i = 0; + while (i < len - 3 && sym[i + 1] == '-' && strchr ("CMSsHA", sym[i])) + i += 2; + /* First I bytes of SYM are modifiers; put <> around the rest. */ + char *buffer = SAFE_ALLOCA (len + 3); + memcpy (buffer, sym, i); + buffer[i] = '<'; + memcpy (buffer + i + 1, sym + i, len - i); + buffer [len + 1] = '>'; + buffer [len + 2] = '\0'; + Lisp_Object result = build_string (buffer); SAFE_FREE (); return result; } @@ -2258,12 +2360,6 @@ around function keys and event symbols. */) static char * push_text_char_description (register unsigned int c, register char *p) { - if (c >= 0200) - { - *p++ = 'M'; - *p++ = '-'; - c -= 0200; - } if (c < 040) { *p++ = '^'; @@ -2282,31 +2378,32 @@ push_text_char_description (register unsigned int c, register char *p) /* This function cannot GC. */ DEFUN ("text-char-description", Ftext_char_description, Stext_char_description, 1, 1, 0, - doc: /* Return a pretty description of file-character CHARACTER. -Control characters turn into "^char", etc. This differs from -`single-key-description' which turns them into "C-char". -Also, this function recognizes the 2**7 bit as the Meta character, -whereas `single-key-description' uses the 2**27 bit for Meta. + doc: /* Return the description of CHARACTER in standard Emacs notation. +CHARACTER must be a valid character code that passes the `characterp' test. +Control characters turn into "^char", and characters with Meta and other +modifiers signal an error, as they are not valid character codes. +This differs from `single-key-description' which accepts character events, +and thus doesn't enforce the `characterp' condition, turns control +characters into "C-char", and uses the 2**27 bit for Meta. See Info node `(elisp)Describing Characters' for examples. */) (Lisp_Object character) { - /* Currently MAX_MULTIBYTE_LENGTH is 4 (< 6). */ - char str[6]; - int c; - CHECK_CHARACTER (character); - c = XINT (character); + int c = XFIXNUM (character); if (!ASCII_CHAR_P (c)) { + char str[MAX_MULTIBYTE_LENGTH]; int len = CHAR_STRING (c, (unsigned char *) str); return make_multibyte_string (str, 1, len); } - - *push_text_char_description (c & 0377, str) = 0; - - return build_string (str); + else + { + char desc[4]; + int len = push_text_char_description (c, desc) - desc; + return make_string (desc, len); + } } static int where_is_preferred_modifier; @@ -2318,7 +2415,7 @@ static int preferred_sequence_p (Lisp_Object seq) { EMACS_INT i; - EMACS_INT len = XFASTINT (Flength (seq)); + EMACS_INT len = XFIXNAT (Flength (seq)); int result = 1; for (i = 0; i < len; i++) @@ -2328,11 +2425,11 @@ preferred_sequence_p (Lisp_Object seq) XSETFASTINT (ii, i); elt = Faref (seq, ii); - if (!INTEGERP (elt)) + if (!FIXNUMP (elt)) return 0; else { - int modifiers = XINT (elt) & (CHAR_MODIFIER_MASK & ~CHAR_META); + int modifiers = XFIXNUM (elt) & (CHAR_MODIFIER_MASK & ~CHAR_META); if (modifiers == where_is_preferred_modifier) result = 2; else if (modifiers) @@ -2349,39 +2446,24 @@ preferred_sequence_p (Lisp_Object seq) static void where_is_internal_1 (Lisp_Object key, Lisp_Object binding, Lisp_Object args, void *data); -/* 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. - If REMAP is true, pass the result of the lookup through command - remapping before returning it. */ +/* Like Flookup_key, but with command remapping; just returns nil + if the key sequence is too long. */ static Lisp_Object -shadow_lookup (Lisp_Object shadow, Lisp_Object key, Lisp_Object flag, +shadow_lookup (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default, bool remap) { - Lisp_Object tail, value; + Lisp_Object value = Flookup_key (keymap, key, accept_default); - for (tail = shadow; CONSP (tail); tail = XCDR (tail)) + if (FIXNATP (value)) /* `key' is too long! */ + return Qnil; + else if (!NILP (value) && remap && SYMBOLP (value)) { - value = Flookup_key (XCAR (tail), key, flag); - if (NATNUMP (value)) - { - value = Flookup_key (XCAR (tail), - Fsubstring (key, make_number (0), value), flag); - if (!NILP (value)) - return Qnil; - } - else if (!NILP (value)) - { - Lisp_Object remapping; - if (remap && SYMBOLP (value) - && (remapping = Fcommand_remapping (value, Qnil, shadow), - !NILP (remapping))) - return remapping; - else - return value; - } + Lisp_Object remapping = Fcommand_remapping (value, Qnil, keymap); + return (!NILP (remapping) ? remapping : value); } - return Qnil; + else + return value; } static Lisp_Object Vmouse_events; @@ -2404,7 +2486,6 @@ where_is_internal (Lisp_Object definition, Lisp_Object keymaps, bool noindirect, bool nomenus) { Lisp_Object maps = Qnil; - Lisp_Object found; struct where_is_internal_data data; /* Only important use of caching is for the menubar @@ -2430,7 +2511,7 @@ where_is_internal (Lisp_Object definition, Lisp_Object keymaps, we're filling it up. */ where_is_cache = Qnil; - found = keymaps; + Lisp_Object found = keymaps; while (CONSP (found)) { maps = @@ -2453,13 +2534,13 @@ where_is_internal (Lisp_Object definition, Lisp_Object keymaps, this = Fcar (XCAR (maps)); map = Fcdr (XCAR (maps)); - last = make_number (XINT (Flength (this)) - 1); - last_is_meta = (XINT (last) >= 0 + last = make_fixnum (XFIXNUM (Flength (this)) - 1); + last_is_meta = (XFIXNUM (last) >= 0 && EQ (Faref (this, last), meta_prefix_char)); /* if (nomenus && !preferred_sequence_p (this)) */ - if (nomenus && XINT (last) >= 0 - && SYMBOLP (tem = Faref (this, make_number (0))) + if (nomenus && XFIXNUM (last) >= 0 + && SYMBOLP (tem = Faref (this, make_fixnum (0))) && !NILP (Fmemq (XCAR (parse_modifiers (tem)), Vmouse_events))) /* If no menu entries should be returned, skip over the keymaps bound to `menu-bar' and `tool-bar' and other @@ -2521,7 +2602,10 @@ The optional 5th arg NO-REMAP alters how command remapping is handled: - If DEFINITION is remapped to OTHER-COMMAND, normally return the bindings for OTHER-COMMAND. But if NO-REMAP is non-nil, return the - bindings for DEFINITION instead, ignoring its remapping. */) + bindings for DEFINITION instead, ignoring its remapping. + +Keys that are represented as events that have a `non-key-event' non-nil +symbol property are ignored. */) (Lisp_Object definition, Lisp_Object keymap, Lisp_Object firstonly, Lisp_Object noindirect, Lisp_Object no_remap) { /* The keymaps in which to search. */ @@ -2539,8 +2623,7 @@ The optional 5th arg NO-REMAP alters how command remapping is handled: /* Whether or not we're handling remapped sequences. This is needed because remapping is not done recursively by Fcommand_remapping: you can't remap a remapped command. */ - bool remapped = 0; - Lisp_Object tem = Qnil; + bool remapped = false; /* Refresh the C version of the modifier preference. */ where_is_preferred_modifier @@ -2554,8 +2637,8 @@ The optional 5th arg NO-REMAP alters how command remapping is handled: else keymaps = Fcurrent_active_maps (Qnil, Qnil); - tem = Fcommand_remapping (definition, Qnil, keymaps); - /* If `definition' is remapped to tem', then OT1H no key will run + Lisp_Object tem = Fcommand_remapping (definition, Qnil, keymaps); + /* If `definition' is remapped to `tem', then OT1H no key will run that command (since they will run `tem' instead), so we should return nil; but OTOH all keys bound to `definition' (or to `tem') will run the same command. @@ -2577,6 +2660,8 @@ The optional 5th arg NO-REMAP alters how command remapping is handled: && !NILP (tem = Fget (definition, QCadvertised_binding))) { /* We have a list of advertised bindings. */ + /* FIXME: Not sure why we use false for shadow_lookup's remapping, + nor why we use `EQ' here but `Fequal' in the call further down. */ while (CONSP (tem)) if (EQ (shadow_lookup (keymaps, XCAR (tem), Qnil, 0), definition)) return XCAR (tem); @@ -2594,7 +2679,7 @@ The optional 5th arg NO-REMAP alters how command remapping is handled: considered remapped sequences yet, copy them over and process them. */ || (!remapped && (sequences = remapped_sequences, - remapped = 1, + remapped = true, CONSP (sequences)))) { Lisp_Object sequence, function; @@ -2636,15 +2721,20 @@ The optional 5th arg NO-REMAP alters how command remapping is handled: if (! NILP (sequence)) { Lisp_Object tem1; - tem1 = Faref (sequence, make_number (ASIZE (sequence) - 1)); + tem1 = Faref (sequence, make_fixnum (ASIZE (sequence) - 1)); if (STRINGP (tem1)) - Faset (sequence, make_number (ASIZE (sequence) - 1), + Faset (sequence, make_fixnum (ASIZE (sequence) - 1), build_string ("(any string)")); } /* 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))) + if (NILP (Fmember (sequence, found)) + /* Filter out non key events. */ + && !(VECTORP (sequence) + && ASIZE (sequence) == 1 + && SYMBOLP (AREF (sequence, 0)) + && !NILP (Fget (AREF (sequence, 0), Qnon_key_event)))) found = Fcons (sequence, found); /* If firstonly is Qnon_ascii, then we can return the first @@ -2707,10 +2797,10 @@ where_is_internal_1 (Lisp_Object key, Lisp_Object binding, Lisp_Object args, voi return; /* We have found a match. Construct the key sequence where we found it. */ - if (INTEGERP (key) && last_is_meta) + if (FIXNUMP (key) && last_is_meta) { sequence = Fcopy_sequence (this); - Faset (sequence, last, make_number (XINT (key) | meta_modifier)); + Faset (sequence, last, make_fixnum (XFIXNUM (key) | meta_modifier)); } else { @@ -2740,9 +2830,7 @@ The optional argument MENUS, if non-nil, says to mention menu bindings. \(Ordinarily these are omitted from the output.) */) (Lisp_Object buffer, Lisp_Object prefix, Lisp_Object menus) { - Lisp_Object outbuf, shadow; - bool nomenu = NILP (menus); - Lisp_Object start1; + Lisp_Object nomenu = NILP (menus) ? Qt : Qnil; const char *alternate_heading = "\ @@ -2752,17 +2840,16 @@ You type Translation\n\ CHECK_BUFFER (buffer); - shadow = Qnil; - outbuf = Fcurrent_buffer (); + Lisp_Object shadow = Qnil; + Lisp_Object outbuf = Fcurrent_buffer (); /* Report on alternates for keys. */ if (STRINGP (KVAR (current_kboard, Vkeyboard_translate_table)) && !NILP (prefix)) { - int c; const unsigned char *translate = SDATA (KVAR (current_kboard, Vkeyboard_translate_table)); int translate_len = SCHARS (KVAR (current_kboard, Vkeyboard_translate_table)); - for (c = 0; c < translate_len; c++) + for (int c = 0; c < translate_len; c++) if (translate[c] != c) { char buf[KEY_DESCRIPTION_SIZE]; @@ -2776,7 +2863,7 @@ You type Translation\n\ bufend = push_key_description (translate[c], buf); insert (buf, bufend - buf); - Findent_to (make_number (16), make_number (1)); + Findent_to (make_fixnum (16), make_fixnum (1)); bufend = push_key_description (c, buf); insert (buf, bufend - buf); @@ -2790,19 +2877,26 @@ You type Translation\n\ } if (!NILP (Vkey_translation_map)) - describe_map_tree (Vkey_translation_map, 0, Qnil, prefix, - "Key translations", nomenu, 1, 0, 0); - + { + Lisp_Object msg = build_unibyte_string ("Key translations"); + CALLN (Ffuncall, + Qdescribe_map_tree, + Vkey_translation_map, Qnil, Qnil, prefix, + msg, nomenu, Qt, Qnil, Qnil, buffer); + } /* Print the (major mode) local map. */ - start1 = Qnil; + Lisp_Object start1 = Qnil; if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map))) start1 = KVAR (current_kboard, Voverriding_terminal_local_map); if (!NILP (start1)) { - describe_map_tree (start1, 1, shadow, prefix, - "\f\nOverriding Bindings", nomenu, 0, 0, 0); + Lisp_Object msg = build_unibyte_string ("\f\nOverriding Bindings"); + CALLN (Ffuncall, + Qdescribe_map_tree, + start1, Qt, shadow, prefix, + msg, nomenu, Qnil, Qnil, Qnil, buffer); shadow = Fcons (start1, shadow); start1 = Qnil; } @@ -2811,39 +2905,43 @@ You type Translation\n\ if (!NILP (start1)) { - describe_map_tree (start1, 1, shadow, prefix, - "\f\nOverriding Bindings", nomenu, 0, 0, 0); + Lisp_Object msg = build_unibyte_string ("\f\nOverriding Bindings"); + CALLN (Ffuncall, + Qdescribe_map_tree, + start1, Qt, shadow, prefix, + msg, nomenu, Qnil, Qnil, Qnil, buffer); 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); + int 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, 0); + Lisp_Object msg = build_unibyte_string ("\f\n`keymap' Property Bindings"); + CALLN (Ffuncall, + Qdescribe_map_tree, + start1, Qt, shadow, prefix, + msg, nomenu, Qnil, Qnil, Qnil, buffer); shadow = Fcons (start1, shadow); } /* Print the minor mode maps. */ - for (i = 0; i < nmaps; i++) + for (int 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 + We let describe-map-tree do the actual insertion because it takes care of other features when doing so. */ char *title, *p; @@ -2863,8 +2961,11 @@ You type Translation\n\ p += strlen (" Minor Mode Bindings"); *p = 0; - describe_map_tree (maps[i], 1, shadow, prefix, - title, nomenu, 0, 0, 0); + Lisp_Object msg = build_unibyte_string (title); + CALLN (Ffuncall, + Qdescribe_map_tree, + maps[i], Qt, shadow, prefix, + msg, nomenu, Qnil, Qnil, Qnil, buffer); shadow = Fcons (maps[i], shadow); SAFE_FREE (); } @@ -2874,453 +2975,69 @@ You type Translation\n\ if (!NILP (start1)) { if (EQ (start1, BVAR (XBUFFER (buffer), keymap))) - describe_map_tree (start1, 1, shadow, prefix, - "\f\nMajor Mode Bindings", nomenu, 0, 0, 0); - else - describe_map_tree (start1, 1, shadow, prefix, - "\f\n`local-map' Property Bindings", - nomenu, 0, 0, 0); - - shadow = Fcons (start1, shadow); - } - } - - describe_map_tree (current_global_map, 1, shadow, prefix, - "\f\nGlobal Bindings", nomenu, 0, 1, 0); - - /* Print the function-key-map translations under this prefix. */ - if (!NILP (KVAR (current_kboard, Vlocal_function_key_map))) - describe_map_tree (KVAR (current_kboard, Vlocal_function_key_map), 0, Qnil, prefix, - "\f\nFunction key map translations", nomenu, 1, 0, 0); - - /* Print the input-decode-map translations under this prefix. */ - if (!NILP (KVAR (current_kboard, Vinput_decode_map))) - describe_map_tree (KVAR (current_kboard, Vinput_decode_map), 0, Qnil, prefix, - "\f\nInput decoding map translations", nomenu, 1, 0, 0); - - return Qnil; -} - -/* Insert a description of the key bindings in STARTMAP, - followed by those of all maps reachable through STARTMAP. - If PARTIAL, omit certain "uninteresting" commands - (such as `undefined'). - If SHADOW is non-nil, it is a list of maps; - don't mention keys which would be shadowed by any of them. - PREFIX, if non-nil, says mention only keys that start with PREFIX. - TITLE, if not 0, is a string to insert at the beginning. - TITLE should not end with a colon or a newline; we supply that. - If NOMENU, then omit menu-bar commands. - - If TRANSL, the definitions are actually key translations - so print strings and vectors differently. - - If ALWAYS_TITLE, print the title even if there are no maps - to look through. - - If MENTION_SHADOW, then when something is shadowed by SHADOW, - don't omit it; instead, mention it but say it is shadowed. - - Any inserted text ends in two newlines (used by `help-make-xrefs'). */ - -void -describe_map_tree (Lisp_Object startmap, bool partial, Lisp_Object shadow, - Lisp_Object prefix, const char *title, bool nomenu, - bool transl, bool always_title, bool mention_shadow) -{ - Lisp_Object maps, orig_maps, seen, sub_shadows; - bool something = 0; - const char *key_heading - = "\ -key binding\n\ ---- -------\n"; - - orig_maps = maps = Faccessible_keymaps (startmap, prefix); - seen = Qnil; - sub_shadows = Qnil; - - if (nomenu) - { - Lisp_Object list; - - /* Delete from MAPS each element that is for the menu bar. */ - for (list = maps; CONSP (list); list = XCDR (list)) - { - Lisp_Object elt, elt_prefix, tem; - - elt = XCAR (list); - elt_prefix = Fcar (elt); - if (ASIZE (elt_prefix) >= 1) { - tem = Faref (elt_prefix, make_number (0)); - if (EQ (tem, Qmenu_bar)) - maps = Fdelq (elt, maps); + Lisp_Object msg = + CALLN (Fformat, + build_unibyte_string ("\f\n`%s' Major Mode Bindings"), + XBUFFER (buffer)->major_mode_); + CALLN (Ffuncall, + Qdescribe_map_tree, + start1, Qt, shadow, prefix, + msg, nomenu, Qnil, Qnil, Qnil, buffer); } - } - } - - if (!NILP (maps) || always_title) - { - if (title) - { - insert_string (title); - if (!NILP (prefix)) - { - insert_string (" Starting With "); - insert1 (Fkey_description (prefix, Qnil)); - } - insert_string (":\n"); - } - insert_string (key_heading); - something = 1; - } - - for (; CONSP (maps); maps = XCDR (maps)) - { - register Lisp_Object elt, elt_prefix, tail; - - elt = XCAR (maps); - elt_prefix = Fcar (elt); - - sub_shadows = Qnil; - - for (tail = shadow; CONSP (tail); tail = XCDR (tail)) - { - Lisp_Object shmap; - - shmap = XCAR (tail); - - /* If the sequence by which we reach this keymap is zero-length, - then the shadow map for this keymap is just SHADOW. */ - if ((STRINGP (elt_prefix) && SCHARS (elt_prefix) == 0) - || (VECTORP (elt_prefix) && ASIZE (elt_prefix) == 0)) - ; - /* If the sequence by which we reach this keymap actually has - some elements, then the sequence's definition in SHADOW is - what we should use. */ else { - shmap = Flookup_key (shmap, Fcar (elt), Qt); - if (INTEGERP (shmap)) - shmap = Qnil; + Lisp_Object msg = build_unibyte_string ("\f\n`local-map' Property Bindings"); + CALLN (Ffuncall, + Qdescribe_map_tree, + start1, Qt, shadow, prefix, + msg, nomenu, Qnil, Qnil, Qnil, buffer); } - /* 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) && !KEYMAPP (shmap)) - goto skip; - - if (!NILP (shmap)) - sub_shadows = Fcons (shmap, sub_shadows); - } - - /* Maps we have already listed in this loop shadow this map. */ - for (tail = orig_maps; !EQ (tail, maps); tail = XCDR (tail)) - { - Lisp_Object tem; - tem = Fequal (Fcar (XCAR (tail)), elt_prefix); - if (!NILP (tem)) - sub_shadows = Fcons (XCDR (XCAR (tail)), sub_shadows); + shadow = Fcons (start1, shadow); } - - describe_map (Fcdr (elt), elt_prefix, - transl ? describe_translation : describe_command, - partial, sub_shadows, &seen, nomenu, mention_shadow); - - skip: ; } - if (something) - insert_string ("\n"); -} + Lisp_Object msg = build_unibyte_string ("\f\nGlobal Bindings"); + CALLN (Ffuncall, + Qdescribe_map_tree, + current_global_map, Qt, shadow, prefix, + msg, nomenu, Qnil, Qt, Qnil, buffer); -static int previous_description_column; - -static void -describe_command (Lisp_Object definition, Lisp_Object args) -{ - register Lisp_Object tem1; - ptrdiff_t column = current_column (); - int description_column; - - /* If column 16 is no good, go to col 32; - but don't push beyond that--go to next line instead. */ - if (column > 30) - { - insert_char ('\n'); - description_column = 32; - } - else if (column > 14 || (column > 10 && previous_description_column == 32)) - description_column = 32; - else - description_column = 16; - - Findent_to (make_number (description_column), make_number (1)); - previous_description_column = description_column; - - if (SYMBOLP (definition)) + /* Print the function-key-map translations under this prefix. */ + if (!NILP (KVAR (current_kboard, Vlocal_function_key_map))) { - tem1 = SYMBOL_NAME (definition); - insert1 (tem1); - insert_string ("\n"); + Lisp_Object msg = build_unibyte_string ("\f\nFunction key map translations"); + CALLN (Ffuncall, + Qdescribe_map_tree, + KVAR (current_kboard, Vlocal_function_key_map), Qnil, Qnil, prefix, + msg, nomenu, Qt, Qnil, Qnil, buffer); } - else if (STRINGP (definition) || VECTORP (definition)) - insert_string ("Keyboard Macro\n"); - else if (KEYMAPP (definition)) - insert_string ("Prefix Command\n"); - else - insert_string ("??\n"); -} -static void -describe_translation (Lisp_Object definition, Lisp_Object args) -{ - register Lisp_Object tem1; - - Findent_to (make_number (16), make_number (1)); - - if (SYMBOLP (definition)) - { - tem1 = SYMBOL_NAME (definition); - insert1 (tem1); - insert_string ("\n"); - } - else if (STRINGP (definition) || VECTORP (definition)) + /* Print the input-decode-map translations under this prefix. */ + if (!NILP (KVAR (current_kboard, Vinput_decode_map))) { - insert1 (Fkey_description (definition, Qnil)); - insert_string ("\n"); + Lisp_Object msg = build_unibyte_string ("\f\nInput decoding map translations"); + CALLN (Ffuncall, + Qdescribe_map_tree, + KVAR (current_kboard, Vinput_decode_map), Qnil, Qnil, prefix, + msg, nomenu, Qt, Qnil, Qnil, buffer); } - else if (KEYMAPP (definition)) - insert_string ("Prefix Command\n"); - else - insert_string ("??\n"); + return Qnil; } -/* describe_map puts all the usable elements of a sparse keymap - into an array of `struct describe_map_elt', - then sorts them by the events. */ - -struct describe_map_elt -{ - Lisp_Object event; - Lisp_Object definition; - bool shadowed; -}; - -/* qsort comparison function for sorting `struct describe_map_elt' by - the event field. */ - -static int -describe_map_compare (const void *aa, const void *bb) -{ - const struct describe_map_elt *a = aa, *b = bb; - if (INTEGERP (a->event) && INTEGERP (b->event)) - return ((XINT (a->event) > XINT (b->event)) - - (XINT (a->event) < XINT (b->event))); - if (!INTEGERP (a->event) && INTEGERP (b->event)) - return 1; - if (INTEGERP (a->event) && !INTEGERP (b->event)) - return -1; - if (SYMBOLP (a->event) && SYMBOLP (b->event)) - return (!NILP (Fstring_lessp (a->event, b->event)) ? -1 - : !NILP (Fstring_lessp (b->event, a->event)) ? 1 - : 0); - return 0; -} - -/* Describe the contents of map MAP, assuming that this map itself is - reached by the sequence of prefix keys PREFIX (a string or vector). - PARTIAL, SHADOW, NOMENU are as in `describe_map_tree' above. */ - static void -describe_map (Lisp_Object map, Lisp_Object prefix, - void (*elt_describer) (Lisp_Object, Lisp_Object), - bool partial, Lisp_Object shadow, - Lisp_Object *seen, bool nomenu, bool mention_shadow) +describe_vector_princ (Lisp_Object elt, Lisp_Object fun) { - Lisp_Object tail, definition, event; - Lisp_Object tem; - Lisp_Object suppress; - Lisp_Object kludge; - bool first = 1; - - /* These accumulate the values from sparse keymap bindings, - so we can sort them and handle them in order. */ - ptrdiff_t length_needed = 0; - struct describe_map_elt *vect; - ptrdiff_t slots_used = 0; - ptrdiff_t i; - - suppress = Qnil; - - if (partial) - suppress = intern ("suppress-keymap"); - - /* This vector gets used to present single keys to Flookup_key. Since - that is done once per keymap element, we don't want to cons up a - fresh vector every time. */ - kludge = Fmake_vector (make_number (1), Qnil); - definition = Qnil; - - map = call1 (Qkeymap_canonicalize, map); - - for (tail = map; CONSP (tail); tail = XCDR (tail)) - length_needed++; - - USE_SAFE_ALLOCA; - SAFE_NALLOCA (vect, 1, length_needed); - - for (tail = map; CONSP (tail); tail = XCDR (tail)) - { - maybe_quit (); - - if (VECTORP (XCAR (tail)) - || CHAR_TABLE_P (XCAR (tail))) - describe_vector (XCAR (tail), - prefix, Qnil, elt_describer, partial, shadow, map, - 1, mention_shadow); - else if (CONSP (XCAR (tail))) - { - bool this_shadowed = 0; - - event = XCAR (XCAR (tail)); - - /* Ignore bindings whose "prefix" are not really valid events. - (We get these in the frames and buffers menu.) */ - if (!(SYMBOLP (event) || INTEGERP (event))) - continue; - - if (nomenu && EQ (event, Qmenu_bar)) - continue; - - definition = get_keyelt (XCDR (XCAR (tail)), 0); - - /* Don't show undefined commands or suppressed commands. */ - if (NILP (definition)) continue; - if (SYMBOLP (definition) && partial) - { - tem = Fget (definition, suppress); - if (!NILP (tem)) - continue; - } - - /* Don't show a command that isn't really visible - because a local definition of the same key shadows it. */ - - ASET (kludge, 0, event); - if (!NILP (shadow)) - { - tem = shadow_lookup (shadow, kludge, Qt, 0); - if (!NILP (tem)) - { - /* If both bindings are keymaps, this key is a prefix key, - so don't say it is shadowed. */ - if (KEYMAPP (definition) && KEYMAPP (tem)) - ; - /* Avoid generating duplicate entries if the - shadowed binding has the same definition. */ - else if (mention_shadow && !EQ (tem, definition)) - this_shadowed = 1; - else - continue; - } - } - - tem = Flookup_key (map, kludge, Qt); - if (!EQ (tem, definition)) continue; - - vect[slots_used].event = event; - vect[slots_used].definition = definition; - vect[slots_used].shadowed = this_shadowed; - slots_used++; - } - else if (EQ (XCAR (tail), Qkeymap)) - { - /* The same keymap might be in the structure twice, if we're - using an inherited keymap. So skip anything we've already - encountered. */ - tem = Fassq (tail, *seen); - if (CONSP (tem) && !NILP (Fequal (XCAR (tem), prefix))) - break; - *seen = Fcons (Fcons (tail, prefix), *seen); - } - } - - /* If we found some sparse map events, sort them. */ - - qsort (vect, slots_used, sizeof (struct describe_map_elt), - describe_map_compare); - - /* Now output them in sorted order. */ - - for (i = 0; i < slots_used; i++) - { - Lisp_Object start, end; - - if (first) - { - previous_description_column = 0; - insert ("\n", 1); - first = 0; - } - - ASET (kludge, 0, vect[i].event); - start = vect[i].event; - end = start; - - definition = vect[i].definition; - - /* Find consecutive chars that are identically defined. */ - if (INTEGERP (vect[i].event)) - { - while (i + 1 < slots_used - && EQ (vect[i+1].event, make_number (XINT (vect[i].event) + 1)) - && !NILP (Fequal (vect[i + 1].definition, definition)) - && vect[i].shadowed == vect[i + 1].shadowed) - i++; - end = vect[i].event; - } - - /* Now START .. END is the range to describe next. */ - - /* Insert the string to describe the event START. */ - insert1 (Fkey_description (kludge, prefix)); - - if (!EQ (start, end)) - { - insert (" .. ", 4); - - ASET (kludge, 0, end); - /* Insert the string to describe the character END. */ - insert1 (Fkey_description (kludge, prefix)); - } - - /* Print a description of the definition of this character. - elt_describer will take care of spacing out far enough - for alignment purposes. */ - (*elt_describer) (vect[i].definition, Qnil); - - if (vect[i].shadowed) - { - ptrdiff_t pt = max (PT - 1, BEG); - - SET_PT (pt); - insert_string ("\n (that binding is currently shadowed by another mode)"); - pt = min (PT + 1, Z); - SET_PT (pt); - } - } - - SAFE_FREE (); + Findent_to (make_fixnum (16), make_fixnum (1)); + call1 (fun, elt); + Fterpri (Qnil, Qnil); } static void -describe_vector_princ (Lisp_Object elt, Lisp_Object fun) +describe_vector_basic (Lisp_Object elt, Lisp_Object fun) { - Findent_to (make_number (16), make_number (1)); call1 (fun, elt); - Fterpri (Qnil, Qnil); } DEFUN ("describe-vector", Fdescribe_vector, Sdescribe_vector, 1, 2, 0, @@ -3329,7 +3046,7 @@ This is text showing the elements of vector matched against indices. DESCRIBER is the output function used; nil means use `princ'. */) (Lisp_Object vector, Lisp_Object describer) { - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); if (NILP (describer)) describer = intern ("princ"); specbind (Qstandard_output, Fcurrent_buffer ()); @@ -3340,8 +3057,55 @@ DESCRIBER is the output function used; nil means use `princ'. */) return unbind_to (count, Qnil); } +static Lisp_Object fontify_key_properties; + +static Lisp_Object +describe_key_maybe_fontify (Lisp_Object str, Lisp_Object prefix, + bool keymap_p) +{ + Lisp_Object key_desc = Fkey_description (str, prefix); + if (keymap_p) + Fadd_text_properties (make_fixnum (0), + make_fixnum (SCHARS (key_desc)), + fontify_key_properties, + key_desc); + return key_desc; +} + +DEFUN ("help--describe-vector", Fhelp__describe_vector, Shelp__describe_vector, 7, 7, 0, + doc: /* Insert in the current buffer a description of the contents of VECTOR. +Call DESCRIBER to insert the description of one value found in VECTOR. + +PREFIX is a string describing the key which leads to the keymap that +this vector is in. + +If PARTIAL, it means do not mention suppressed commands. + +SHADOW is a list of keymaps that shadow this map. +If it is non-nil, look up the key in those maps and don't mention it +if it is defined by any of them. + +ENTIRE-MAP is the keymap in which this vector appears. +If the definition in effect in the whole map does not match +the one in this keymap, we ignore this one. */) + (Lisp_Object vector, Lisp_Object prefix, Lisp_Object describer, + Lisp_Object partial, Lisp_Object shadow, Lisp_Object entire_map, + Lisp_Object mention_shadow) +{ + specpdl_ref count = SPECPDL_INDEX (); + specbind (Qstandard_output, Fcurrent_buffer ()); + CHECK_VECTOR_OR_CHAR_TABLE (vector); + + bool b_partial = NILP (partial) ? false : true; + bool b_mention_shadow = NILP (mention_shadow) ? false : true; + + describe_vector (vector, prefix, describer, describe_vector_basic, b_partial, + shadow, entire_map, true, b_mention_shadow); + return unbind_to (count, Qnil); +} + /* Insert in the current buffer a description of the contents of VECTOR. - We call ELT_DESCRIBER to insert the description of one value found + Call ELT_DESCRIBER to insert the description of one value found in VECTOR. ELT_PREFIX describes what "comes before" the keys or indices defined @@ -3378,30 +3142,18 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args, bool partial, Lisp_Object shadow, Lisp_Object entire_map, bool keymap_p, bool mention_shadow) { - Lisp_Object definition; - Lisp_Object tem2; Lisp_Object elt_prefix = Qnil; - int i; - Lisp_Object suppress; - Lisp_Object kludge; - bool first = 1; + Lisp_Object suppress = Qnil; + bool first = true; /* Range of elements to be handled. */ - int from, to, stop; - Lisp_Object character; - int starting_i; - - suppress = Qnil; - - definition = Qnil; + int to, stop; if (!keymap_p) { - /* Call Fkey_description first, to avoid GC bug for the other string. */ - if (!NILP (prefix) && XFASTINT (Flength (prefix)) > 0) + if (!NILP (prefix) && XFIXNAT (Flength (prefix)) > 0) { - Lisp_Object tem = Fkey_description (prefix, Qnil); AUTO_STRING (space, " "); - elt_prefix = concat2 (tem, space); + elt_prefix = concat2 (Fkey_description (prefix, Qnil), space); } prefix = Qnil; } @@ -3409,22 +3161,25 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args, /* This vector gets used to present single keys to Flookup_key. Since that is done once per vector element, we don't want to cons up a fresh vector every time. */ - kludge = Fmake_vector (make_number (1), Qnil); + Lisp_Object kludge = make_nil_vector (1); if (partial) suppress = intern ("suppress-keymap"); - from = 0; + /* STOP is a boundary between normal characters (-#x3FFF7F) and + 8-bit characters (#x3FFF80-), used below when VECTOR is a + char-table. */ if (CHAR_TABLE_P (vector)) stop = MAX_5_BYTE_CHAR + 1, to = MAX_CHAR + 1; else stop = to = ASIZE (vector); - for (i = from; ; i++) + for (int i = 0; ; i++) { - bool this_shadowed = 0; - int range_beg, range_end; - Lisp_Object val; + bool this_shadowed = false; + Lisp_Object shadowed_by = Qnil; + int range_beg; + Lisp_Object val, tem2; maybe_quit (); @@ -3435,44 +3190,44 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args, stop = to; } - starting_i = i; + int starting_i = i; if (CHAR_TABLE_P (vector)) { + /* Find the value in VECTOR for the first character in the + range [RANGE_BEG..STOP), and update the range to include + only the characters whose value is the same as that of + the first in the range. */ range_beg = i; i = stop - 1; val = char_table_ref_and_range (vector, range_beg, &range_beg, &i); } else val = AREF (vector, i); - definition = get_keyelt (val, 0); + Lisp_Object definition = get_keyelt (val, 0); if (NILP (definition)) continue; /* Don't mention suppressed commands. */ if (SYMBOLP (definition) && partial) { - Lisp_Object tem; - - tem = Fget (definition, suppress); + Lisp_Object tem = Fget (definition, suppress); if (!NILP (tem)) continue; } - character = make_number (starting_i); + Lisp_Object character = make_fixnum (starting_i); ASET (kludge, 0, character); /* If this binding is shadowed by some other map, ignore it. */ if (!NILP (shadow)) { - Lisp_Object tem; - - tem = shadow_lookup (shadow, kludge, Qt, 0); + shadowed_by = shadow_lookup (shadow, kludge, Qt, 0); - if (!NILP (tem)) + if (!NILP (shadowed_by) && !EQ (shadowed_by, definition)) { if (mention_shadow) - this_shadowed = 1; + this_shadowed = true; else continue; } @@ -3482,9 +3237,7 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args, one in the same keymap. */ if (!NILP (entire_map)) { - Lisp_Object tem; - - tem = Flookup_key (entire_map, kludge, Qt); + Lisp_Object tem = Flookup_key (entire_map, kludge, Qt); if (!EQ (tem, definition)) continue; @@ -3493,36 +3246,43 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args, if (first) { insert ("\n", 1); - first = 0; + first = false; } /* Output the prefix that applies to every entry in this map. */ if (!NILP (elt_prefix)) insert1 (elt_prefix); - insert1 (Fkey_description (kludge, prefix)); + insert1 (describe_key_maybe_fontify (kludge, prefix, keymap_p)); /* Find all consecutive characters or rows that have the same - definition. But, VECTOR is a char-table, we had better put a - boundary between normal characters (-#x3FFF7F) and 8-bit - characters (#x3FFF80-). */ - if (CHAR_TABLE_P (vector)) + definition. */ + if (!CHAR_TABLE_P (vector)) { while (i + 1 < stop - && (range_beg = i + 1, range_end = stop - 1, - val = char_table_ref_and_range (vector, range_beg, - &range_beg, &range_end), - tem2 = get_keyelt (val, 0), - !NILP (tem2)) + && (tem2 = get_keyelt (AREF (vector, i + 1), 0), + !NILP (tem2)) && !NILP (Fequal (tem2, definition))) - i = range_end; + i++; + } + + /* Make sure found consecutive keys are either not shadowed or, + if they are, that they are shadowed by the same command. */ + if (!NILP (Vdescribe_bindings_check_shadowing_in_ranges) + && CHAR_TABLE_P (vector) && i != starting_i + && (!EQ (Vdescribe_bindings_check_shadowing_in_ranges, + Qignore_self_insert) + || !EQ (definition, Qself_insert_command))) + { + Lisp_Object key = make_nil_vector (1); + for (int j = range_beg + 1; j <= i; j++) + { + ASET (key, 0, make_fixnum (j)); + Lisp_Object tem = shadow_lookup (shadow, key, Qt, 0); + if (NILP (Fequal (tem, shadowed_by))) + i = j - 1; + } } - else - while (i + 1 < stop - && (tem2 = get_keyelt (AREF (vector, i + 1), 0), - !NILP (tem2)) - && !NILP (Fequal (tem2, definition))) - i++; /* If we have a range of more than one character, print where the range reaches to. */ @@ -3531,12 +3291,12 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args, { insert (" .. ", 4); - ASET (kludge, 0, make_number (i)); + ASET (kludge, 0, make_fixnum (i)); if (!NILP (elt_prefix)) insert1 (elt_prefix); - insert1 (Fkey_description (kludge, prefix)); + insert1 (describe_key_maybe_fontify (kludge, prefix, keymap_p)); } /* Print a description of the definition of this character. @@ -3547,7 +3307,13 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args, if (this_shadowed) { SET_PT (PT - 1); - insert_string (" (binding currently shadowed)"); + static char const fmt[] = " (currently shadowed by `%s')"; + USE_SAFE_ALLOCA; + char *buffer = SAFE_ALLOCA (sizeof fmt + + SBYTES (SYMBOL_NAME (shadowed_by))); + esprintf (buffer, fmt, SDATA (SYMBOL_NAME (shadowed_by))); + insert_string (buffer); + SAFE_FREE(); SET_PT (PT + 1); } } @@ -3561,98 +3327,37 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args, } } -/* Apropos - finding all symbols whose names match a regexp. */ -static Lisp_Object apropos_predicate; -static Lisp_Object apropos_accumulate; - -static void -apropos_accum (Lisp_Object symbol, Lisp_Object string) -{ - register Lisp_Object tem; - - tem = Fstring_match (string, Fsymbol_name (symbol), Qnil); - if (!NILP (tem) && !NILP (apropos_predicate)) - tem = call1 (apropos_predicate, symbol); - if (!NILP (tem)) - apropos_accumulate = Fcons (symbol, apropos_accumulate); -} - -DEFUN ("apropos-internal", Fapropos_internal, Sapropos_internal, 1, 2, 0, - 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. */) - (Lisp_Object regexp, Lisp_Object predicate) -{ - Lisp_Object tem; - CHECK_STRING (regexp); - apropos_predicate = predicate; - apropos_accumulate = Qnil; - map_obarray (Vobarray, apropos_accum, regexp); - tem = Fsort (apropos_accumulate, Qstring_lessp); - apropos_accumulate = Qnil; - apropos_predicate = Qnil; - return tem; -} - void syms_of_keymap (void) { DEFSYM (Qkeymap, "keymap"); - staticpro (&apropos_predicate); - staticpro (&apropos_accumulate); - apropos_predicate = Qnil; - apropos_accumulate = Qnil; + DEFSYM (Qdescribe_map_tree, "describe-map-tree"); DEFSYM (Qkeymap_canonicalize, "keymap-canonicalize"); /* Now we are ready to set up this property, so we can create char tables. */ - Fput (Qkeymap, Qchar_table_extra_slots, make_number (0)); + Fput (Qkeymap, Qchar_table_extra_slots, make_fixnum (0)); /* Initialize the keymaps standardly used. Each one is the value of a Lisp variable, and is also pointed to by a C variable */ - global_map = Fmake_keymap (Qnil); - Fset (intern_c_string ("global-map"), global_map); - - current_global_map = global_map; - staticpro (&global_map); + current_global_map = Qnil; staticpro (¤t_global_map); - meta_map = Fmake_keymap (Qnil); - Fset (intern_c_string ("esc-map"), meta_map); - Ffset (intern_c_string ("ESC-prefix"), meta_map); - - control_x_map = Fmake_keymap (Qnil); - Fset (intern_c_string ("ctl-x-map"), control_x_map); - Ffset (intern_c_string ("Control-X-prefix"), control_x_map); - - exclude_keys = listn (CONSTYPE_PURE, 5, - pure_cons (build_pure_c_string ("DEL"), build_pure_c_string ("\\d")), - pure_cons (build_pure_c_string ("TAB"), build_pure_c_string ("\\t")), - pure_cons (build_pure_c_string ("RET"), build_pure_c_string ("\\r")), - pure_cons (build_pure_c_string ("ESC"), build_pure_c_string ("\\e")), - pure_cons (build_pure_c_string ("SPC"), build_pure_c_string (" "))); + exclude_keys = pure_list + (pure_cons (build_pure_c_string ("DEL"), build_pure_c_string ("\\d")), + pure_cons (build_pure_c_string ("TAB"), build_pure_c_string ("\\t")), + pure_cons (build_pure_c_string ("RET"), build_pure_c_string ("\\r")), + pure_cons (build_pure_c_string ("ESC"), build_pure_c_string ("\\e")), + pure_cons (build_pure_c_string ("SPC"), build_pure_c_string (" "))); staticpro (&exclude_keys); - DEFVAR_LISP ("define-key-rebound-commands", Vdefine_key_rebound_commands, - 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, 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, - 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 ("minor-mode-map-alist", Vminor_mode_map_alist, doc: /* Alist of keymaps to use for minor modes. Each element looks like (VARIABLE . KEYMAP); KEYMAP is used to read @@ -3686,20 +3391,35 @@ be preferred. */); Vwhere_is_preferred_modifier = Qnil; where_is_preferred_modifier = 0; + DEFVAR_LISP ("describe-bindings-check-shadowing-in-ranges", + Vdescribe_bindings_check_shadowing_in_ranges, + doc: /* If non-nil, consider command shadowing when describing ranges of keys. +If the value is t, describing bindings of consecutive keys will not +report them as a single range if they are shadowed by different +minor-mode commands. +If the value is `ignore-self-insert', assume that consecutive keys +bound to `self-insert-command' are not all shadowed; this speeds up +commands such as \\[describe-bindings] and \\[describe-mode], but could miss some shadowing. +Any other non-nil value is treated is t. + +Beware: setting this non-nil could potentially slow down commands +that describe key bindings. That is why the default is nil. */); + Vdescribe_bindings_check_shadowing_in_ranges = Qnil; + + DEFSYM (Qself_insert_command, "self-insert-command"); + DEFSYM (Qignore_self_insert, "ignore-self-insert"); + DEFSYM (Qmenu_bar, "menu-bar"); DEFSYM (Qmode_line, "mode-line"); staticpro (&Vmouse_events); - Vmouse_events = listn (CONSTYPE_PURE, 9, - Qmenu_bar, - Qtool_bar, - Qheader_line, - Qmode_line, - intern_c_string ("mouse-1"), - intern_c_string ("mouse-2"), - intern_c_string ("mouse-3"), - intern_c_string ("mouse-4"), - intern_c_string ("mouse-5")); + Vmouse_events = pure_list (Qmenu_bar, Qtab_bar, Qtool_bar, + Qtab_line, Qheader_line, Qmode_line, + intern_c_string ("mouse-1"), + intern_c_string ("mouse-2"), + intern_c_string ("mouse-3"), + intern_c_string ("mouse-4"), + intern_c_string ("mouse-5")); /* Keymap used for minibuffers when doing completion. */ /* Keymap used for minibuffers when doing completion and require a match. */ @@ -3709,7 +3429,7 @@ be preferred. */); DEFSYM (Qremap, "remap"); DEFSYM (QCadvertised_binding, ":advertised-binding"); - command_remapping_vector = Fmake_vector (make_number (2), Qremap); + command_remapping_vector = make_vector (2, Qremap); staticpro (&command_remapping_vector); where_is_cache_keymaps = Qt; @@ -3717,6 +3437,12 @@ be preferred. */); staticpro (&where_is_cache); staticpro (&where_is_cache_keymaps); + DEFSYM (Qfont_lock_face, "font-lock-face"); + DEFSYM (Qhelp_key_binding, "help-key-binding"); + staticpro (&fontify_key_properties); + fontify_key_properties = Fcons (Qfont_lock_face, + Fcons (Qhelp_key_binding, Qnil)); + defsubr (&Skeymapp); defsubr (&Skeymap_parent); defsubr (&Skeymap_prompt); @@ -3728,12 +3454,9 @@ be preferred. */); defsubr (&Scopy_keymap); defsubr (&Scommand_remapping); defsubr (&Skey_binding); - defsubr (&Slocal_key_binding); - defsubr (&Sglobal_key_binding); defsubr (&Sminor_mode_key_binding); defsubr (&Sdefine_key); defsubr (&Slookup_key); - defsubr (&Sdefine_prefix_command); defsubr (&Suse_global_map); defsubr (&Suse_local_map); defsubr (&Scurrent_local_map); @@ -3742,17 +3465,16 @@ be preferred. */); defsubr (&Scurrent_active_maps); defsubr (&Saccessible_keymaps); defsubr (&Skey_description); + defsubr (&Skeymap__get_keyelt); + defsubr (&Shelp__describe_vector); defsubr (&Sdescribe_vector); defsubr (&Ssingle_key_description); defsubr (&Stext_char_description); defsubr (&Swhere_is_internal); defsubr (&Sdescribe_buffer_bindings); - defsubr (&Sapropos_internal); -} -void -keys_of_keymap (void) -{ - initial_define_key (global_map, 033, "ESC-prefix"); - initial_define_key (global_map, Ctl ('X'), "Control-X-prefix"); + DEFSYM (Qkey_parse, "key-parse"); + DEFSYM (Qkey_valid_p, "key-valid-p"); + + DEFSYM (Qnon_key_event, "non-key-event"); } |