Mercurial > emacs
changeset 43152:0029b0259426
(Fdefine_key): Allow symbol as KEY argument for
defining command remapping. Doc updated.
(Flookup_key): Remap command through keymap if KEY is a symbol.
(is_command_symbol): New function.
(Fkey_binding): Use it. New optional argument NO-REMAP. Doc
updated. Callers changed. Perform command remapping via
recursive call unless that arg is non-nil.
(where_is_internal): New argument no_remap. Callers changed.
Call recursively to find original key bindings for a remapped
comand unless that arg is non-nil.
(Fwhere_is_internal): New optional argument NO-REMAP. Doc
updated. Callers changed. Pass arg to where_is_internal.
author | Kim F. Storm <storm@cua.dk> |
---|---|
date | Wed, 06 Feb 2002 22:57:42 +0000 |
parents | 88bbfdf9451e |
children | d6162a8dc872 |
files | src/keymap.c |
diffstat | 1 files changed, 158 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/src/keymap.c Wed Feb 06 22:46:55 2002 +0000 +++ b/src/keymap.c Wed Feb 06 22:57:42 2002 +0000 @@ -954,10 +954,12 @@ DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0, doc: /* Args KEYMAP, KEY, DEF. Define key sequence KEY, in KEYMAP, as DEF. -KEYMAP is a keymap. KEY is a string or a vector of symbols and characters -meaning a sequence of keystrokes and events. -Non-ASCII characters with codes above 127 (such as ISO Latin-1) -can be included if you use a vector. +KEYMAP is a keymap. + +KEY is a string or a vector of symbols and characters meaning a +sequence of keystrokes and events. Non-ASCII characters with codes +above 127 (such as ISO Latin-1) can be included if you use a vector. + DEF is anything that can be a key's definition: nil (means key is undefined in this keymap), a command (a Lisp function suitable for interactive calling) @@ -971,7 +973,10 @@ or a cons (KEYMAP . CHAR), meaning use definition of CHAR in map KEYMAP. If KEYMAP is a sparse keymap, the pair binding KEY to DEF is added at -the front of KEYMAP. */) +the front of KEYMAP. + +KEY may also be a command name which is remapped to DEF. In this case, +DEF must be a symbol or nil (to remove a previous binding of KEY). */) (keymap, key, def) Lisp_Object keymap; Lisp_Object key; @@ -987,8 +992,24 @@ keymap = get_keymap (keymap, 1, 1); - if (!VECTORP (key) && !STRINGP (key)) - key = wrong_type_argument (Qarrayp, key); + if (SYMBOLP (key)) + { + /* A command may only be remapped to another command. */ + + /* I thought of using is_command_symbol above and below instead + of SYMBOLP, since remapping only works for sych symbols. + However, to make that a requirement would make it impossible + to remap a command before it has been defined, e.g. if a minor + mode were to remap a command of another minor mode which has + not yet been loaded, it would fail. So just use the least + restrictive sanity check here. */ + if (!SYMBOLP (def)) + key = wrong_type_argument (Qsymbolp, def); + else + key = Fmake_vector (make_number (1), key); + } + else if (!VECTORP (key) && !STRINGP (key)) + key = wrong_type_argument (Qarrayp, key); length = XFASTINT (Flength (key)); if (length == 0) @@ -1084,6 +1105,10 @@ keymap = get_keymap (keymap, 1, 1); + /* Command remapping is simple. */ + if (SYMBOLP (key)) + return access_keymap (keymap, key, t_ok, 0, 1); + if (!VECTORP (key) && !STRINGP (key)) key = wrong_type_argument (Qarrayp, key); @@ -1361,9 +1386,44 @@ return keymaps; } +/* Like Fcommandp, but looks specifically for a command symbol, and + doesn't signal errors. Returns 1 if FUNCTION is a command symbol. */ +int +is_command_symbol (function) + Lisp_Object function; +{ + if (!SYMBOLP (function) || EQ (function, Qunbound)) + return 0; + + function = indirect_function (function); + if (SYMBOLP (function) && EQ (function, Qunbound)) + return 0; + + if (SUBRP (function)) + return (XSUBR (function)->prompt != 0); + + if (COMPILEDP (function)) + return ((ASIZE (function) & PSEUDOVECTOR_SIZE_MASK) > COMPILED_INTERACTIVE); + + if (CONSP (function)) + { + Lisp_Object funcar; + + funcar = Fcar (function); + if (SYMBOLP (funcar)) + { + if (EQ (funcar, Qlambda)) + return !NILP (Fassq (Qinteractive, Fcdr (Fcdr (function)))); + if (EQ (funcar, Qautoload)) + return !NILP (Fcar (Fcdr (Fcdr (Fcdr (function))))); + } + } + return 0; +} + /* GC is possible in this function if it autoloads a keymap. */ -DEFUN ("key-binding", Fkey_binding, Skey_binding, 1, 2, 0, +DEFUN ("key-binding", Fkey_binding, Skey_binding, 1, 3, 0, doc: /* Return the binding for command KEY in current keymaps. KEY is a string or vector, a sequence of keystrokes. The binding is probably a symbol with a function definition. @@ -1372,9 +1432,14 @@ bindings, used when nothing else in the keymap applies; this makes it usable as a general function for probing keymaps. However, if the optional second argument ACCEPT-DEFAULT is non-nil, `key-binding' does -recognize the default bindings, just as `read-key-sequence' does. */) - (key, accept_default) - Lisp_Object key, accept_default; +recognize the default bindings, just as `read-key-sequence' does. + +Like the normal command loop, `key-binding' will remap the command +resulting from looking up KEY by looking up the command in the +currrent keymaps. However, if the optional third argument NO-REMAP +is non-nil, `key-binding' returns the unmapped command. */) + (key, accept_default, no_remap) + Lisp_Object key, accept_default, no_remap; { Lisp_Object *maps, value; int nmaps, i; @@ -1387,13 +1452,13 @@ value = Flookup_key (current_kboard->Voverriding_terminal_local_map, key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } else if (!NILP (Voverriding_local_map)) { value = Flookup_key (Voverriding_local_map, key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } else { @@ -1404,7 +1469,7 @@ { value = Flookup_key (local, key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } nmaps = current_minor_maps (0, &maps); @@ -1416,7 +1481,7 @@ { value = Flookup_key (maps[i], key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } local = get_local_map (PT, current_buffer, Qlocal_map); @@ -1424,16 +1489,30 @@ { value = Flookup_key (local, key, accept_default); if (! NILP (value) && !INTEGERP (value)) - RETURN_UNGCPRO (value); + goto done; } } value = Flookup_key (current_global_map, key, accept_default); + + done: UNGCPRO; - if (! NILP (value) && !INTEGERP (value)) - return value; + if (NILP (value) || INTEGERP (value)) + return Qnil; + + /* If the result of the ordinary keymap lookup is an interactive + command, look for a key binding (ie. remapping) for that command. */ + + if (NILP (no_remap) && is_command_symbol (value)) + { + Lisp_Object value1; + + value1 = Fkey_binding (value, accept_default, Qt); + if (!NILP (value1) && is_command_symbol (value1)) + value = value1; + } - return Qnil; + return value; } /* GC is possible in this function if it autoloads a keymap. */ @@ -2156,6 +2235,7 @@ /* where-is - finding a command in a set of keymaps. */ +static Lisp_Object where_is_internal (); static Lisp_Object where_is_internal_1 (); static void where_is_internal_2 (); @@ -2180,9 +2260,9 @@ /* This function can GC if Flookup_key autoloads any keymaps. */ static Lisp_Object -where_is_internal (definition, keymaps, firstonly, noindirect) +where_is_internal (definition, keymaps, firstonly, noindirect, no_remap) Lisp_Object definition, keymaps; - Lisp_Object firstonly, noindirect; + Lisp_Object firstonly, noindirect, no_remap; { Lisp_Object maps = Qnil; Lisp_Object found, sequences; @@ -2190,6 +2270,12 @@ /* 1 means ignore all menu bindings entirely. */ int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii); + /* If this command is remapped, then it has no key bindings + of its own. */ + if (NILP (no_remap) + && !NILP (Fkey_binding (definition, Qnil, Qt))) + return Qnil; + found = keymaps; while (CONSP (found)) { @@ -2295,11 +2381,41 @@ } - for (; !NILP (sequences); sequences = XCDR (sequences)) + while (!NILP (sequences)) { Lisp_Object sequence; + Lisp_Object remapped; sequence = XCAR (sequences); + sequences = XCDR (sequences); + + /* If the current sequence is of the form [command], + this may be a remapped command, so look for the key + sequences which run that command, and return those + sequences instead. */ + remapped = Qnil; + if (NILP (no_remap) + && VECTORP (sequence) && XVECTOR (sequence)->size == 1) + { + Lisp_Object function; + + function = AREF (sequence, 0); + if (is_command_symbol (function)) + { + Lisp_Object remapped1; + remapped1 = where_is_internal (function, keymaps, firstonly, noindirect, Qt); + if (CONSP (remapped1)) + { + /* Verify that this key binding actually maps to the + remapped command (see below). */ + if (!EQ (shadow_lookup (keymaps, XCAR (remapped1), Qnil), function)) + continue; + sequence = XCAR (remapped1); + remapped = XCDR (remapped1); + goto record_sequence; + } + } + } /* Verify that this key binding is not shadowed by another binding for the same key, before we say it exists. @@ -2313,6 +2429,7 @@ if (!EQ (shadow_lookup (keymaps, sequence, Qnil), definition)) continue; + record_sequence: /* It is a true unshadowed match. Record it, unless it's already been seen (as could happen when inheriting keymaps). */ if (NILP (Fmember (sequence, found))) @@ -2326,6 +2443,13 @@ RETURN_UNGCPRO (sequence); else if (!NILP (firstonly) && ascii_sequence_p (sequence)) RETURN_UNGCPRO (sequence); + + if (CONSP (remapped)) + { + sequence = XCAR (remapped); + remapped = XCDR (remapped); + goto record_sequence; + } } } } @@ -2343,7 +2467,7 @@ return found; } -DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 4, 0, +DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 5, 0, doc: /* Return list of keys that invoke DEFINITION. If KEYMAP is non-nil, search only KEYMAP and the global keymap. If KEYMAP is nil, search all the currently active keymaps. @@ -2358,10 +2482,14 @@ If optional 4th arg NOINDIRECT is non-nil, don't follow indirections to other keymaps or slots. This makes it possible to search for an -indirect definition itself. */) - (definition, keymap, firstonly, noindirect) +indirect definition itself. + +If optional 5th arg NO-REMAP is non-nil, don't search for key sequences +that invoke a command which is remapped to DEFINITION, but include the +remapped command in the returned list. */) + (definition, keymap, firstonly, noindirect, no_remap) Lisp_Object definition, keymap; - Lisp_Object firstonly, noindirect; + Lisp_Object firstonly, noindirect, no_remap; { Lisp_Object sequences, keymaps; /* 1 means ignore all menu bindings entirely. */ @@ -2382,7 +2510,7 @@ { Lisp_Object *defns; int i, j, n; - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; /* Check heuristic-consistency of the cache. */ if (NILP (Fequal (keymaps, where_is_cache_keymaps))) @@ -2396,8 +2524,8 @@ where_is_cache_keymaps = Qt; /* Fill in the cache. */ - GCPRO4 (definition, keymaps, firstonly, noindirect); - where_is_internal (definition, keymaps, firstonly, noindirect); + GCPRO5 (definition, keymaps, firstonly, noindirect, no_remap); + where_is_internal (definition, keymaps, firstonly, noindirect, no_remap); UNGCPRO; where_is_cache_keymaps = keymaps; @@ -2434,7 +2562,7 @@ /* Kill the cache so that where_is_internal_1 doesn't think we're filling it up. */ where_is_cache = Qnil; - result = where_is_internal (definition, keymaps, firstonly, noindirect); + result = where_is_internal (definition, keymaps, firstonly, noindirect, no_remap); } return result;