Mercurial > emacs
changeset 1209:1aa2cd425737
* keymap.c (DENSE_TABLE_SIZE): Doc fix.
(keymap_table): Function removed; this function exists only to
support an incorrect understanding of the format of keymaps.
(access_keymap, store_in_keymap, Fcopy_keymap,
Faccessible_keymaps): Correctly handle vectors at any point in the
keymap; don't assume it must be at the front.
(describe_map): Instead of calling describe_vector on the vector
in the cadr of the keymap (if present) and then calling
describe_alist to do the rest, just call describe_map_2.
(describe_alist): Renamed to describe_map_2; call describe_vector
when we encounter a vector in the list.
* keymap.c (access_keymap, store_in_keymap): Clarify error message
for non-ASCII characters.
* keymap.c (access_keymap): Return the binding of Qt as the
binding for all unbound characters.
author | Jim Blandy <jimb@redhat.com> |
---|---|
date | Wed, 23 Sep 1992 12:46:52 +0000 |
parents | fa662930e654 |
children | 3640e799d5fc |
files | src/keymap.c |
diffstat | 1 files changed, 203 insertions(+), 213 deletions(-) [+] |
line wrap: on
line diff
--- a/src/keymap.c Wed Sep 23 12:45:50 1992 +0000 +++ b/src/keymap.c Wed Sep 23 12:46:52 1992 +0000 @@ -28,9 +28,7 @@ #define min(a, b) ((a) < (b) ? (a) : (b)) -/* Dense keymaps look like (keymap VECTOR . ALIST), where VECTOR is a - 128-element vector used to look up bindings for ASCII characters, - and ALIST is an assoc list for looking up symbols. */ +/* The number of elements in keymap vectors. */ #define DENSE_TABLE_SIZE (0200) /* Actually allocate storage for these variables */ @@ -84,7 +82,7 @@ static Lisp_Object describe_buffer_bindings (); static void describe_command (); static void describe_map (); -static void describe_alist (); +static void describe_map_2 (); /* Keymap object support - constructors and predicates. */ @@ -190,6 +188,7 @@ tem = indirect_function (object); if (CONSP (tem) && EQ (XCONS (tem)->car, Qkeymap)) return tem; + if (error) wrong_type_argument (Qkeymapp, object); else @@ -204,27 +203,12 @@ } -/* If KEYMAP is a dense keymap, return the vector from its cadr. - Otherwise, return nil. */ - -Lisp_Object -keymap_table (keymap) - Lisp_Object keymap; -{ - Lisp_Object cadr; +/* Look up IDX in MAP. IDX may be any sort of event. - if (CONSP (XCONS (keymap)->cdr) - && XTYPE (cadr = XCONS (XCONS (keymap)->cdr)->car) == Lisp_Vector - && XVECTOR (cadr)->size == DENSE_TABLE_SIZE) - return cadr; - else - return Qnil; -} - - -/* Look up IDX in MAP. IDX may be any sort of event. - Note that this does only one level of lookup; IDX must - be a single event, not a sequence. */ + Note that this does only one level of lookup; IDX must be a single + event, not a sequence. If IDX is unbound in MAP but MAP has a + binding for Qt, then Qt's binding is returned; this makes bindings + of Qt act like "default" bindings. */ Lisp_Object access_keymap (map, idx) @@ -239,26 +223,39 @@ if (XTYPE (idx) == Lisp_Int && (XINT (idx) < 0 || XINT (idx) >= DENSE_TABLE_SIZE)) - error ("Command key is not an ASCII character"); + error ("only ASCII characters may used as keymap indices"); + + /* If idx is a symbol, it might have modifiers, which need to + be put in the canonical order. */ + else if (XTYPE (idx) == Lisp_Symbol) + idx = reorder_modifiers (idx); { - Lisp_Object table = keymap_table (map); + Lisp_Object tail; + Lisp_Object t_binding = Qnil; - /* A dense keymap indexed by a character? */ - if (XTYPE (idx) == Lisp_Int - && ! NILP (table)) - return XVECTOR (table)->contents[XFASTINT (idx)]; + for (tail = map; CONSP (tail); tail = XCONS (tail)->cdr) + { + Lisp_Object binding = XCONS (tail)->car; - /* This lookup will not involve a vector reference. */ - else - { - /* If idx is a symbol, it might have modifiers, which need to - be put in the canonical order. */ - if (XTYPE (idx) == Lisp_Symbol) - idx = reorder_modifiers (idx); - - return Fcdr (Fassq (idx, map)); + switch (XTYPE (binding)) + { + case Lisp_Cons: + if (EQ (XCONS (binding)->car, idx)) + return XCONS (binding)->cdr; + if (EQ (XCONS (binding)->car, Qt)) + t_binding = XCONS (binding)->cdr; + break; + + case Lisp_Vector: + if (XVECTOR (binding)->size == DENSE_TABLE_SIZE + && XTYPE (idx) == Lisp_Int) + return XVECTOR (binding)->contents[XINT (idx)]; + break; + } } + + return t_binding; } } @@ -313,6 +310,10 @@ register Lisp_Object idx; register Lisp_Object def; { + if (XTYPE (keymap) != Lisp_Cons + || ! EQ (XCONS (keymap)->car, Qkeymap)) + error ("attempt to define a key in a non-keymap"); + /* If idx is a list (some sort of mouse click, perhaps?), the index we want to use is the car of the list, which ought to be a symbol. */ @@ -321,44 +322,71 @@ if (XTYPE (idx) == Lisp_Int && (XINT (idx) < 0 || XINT (idx) >= DENSE_TABLE_SIZE)) - error ("Command key is a character outside of the ASCII set."); - - { - Lisp_Object table = keymap_table (keymap); + error ("only ASCII characters may be used as keymap indices"); + + /* If idx is a symbol, it might have modifiers, which need to + be put in the canonical order. */ + else if (XTYPE (idx) == Lisp_Symbol) + idx = reorder_modifiers (idx); + - /* A dense keymap indexed by a character? */ - if (XTYPE (idx) == Lisp_Int && !NILP (table)) - XVECTOR (table)->contents[XFASTINT (idx)] = def; + /* Scan the keymap for a binding of idx. */ + { + Lisp_Object tail; - /* Must be a sparse keymap, or a dense keymap indexed by a symbol. */ - else + /* The cons after which we should insert new bindings. If the + keymap has a table element, we record its position here, so new + bindings will go after it; this way, the table will stay + 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 = keymap; + + for (tail = XCONS (keymap)->cdr; CONSP (tail); tail = XCONS (tail)->cdr) { - /* Point to the pointer to the start of the assoc-list part - of the keymap. */ - register Lisp_Object *assoc_head - = (NILP (table) - ? & XCONS (keymap)->cdr - : & XCONS (XCONS (keymap)->cdr)->cdr); - register Lisp_Object defining_pair; + Lisp_Object elt = XCONS (tail)->car; + + switch (XTYPE (elt)) + { + case Lisp_Vector: + if (XTYPE (idx) == Lisp_Int) + { + XVECTOR (elt)->contents[XFASTINT (idx)] = def; + return def; + } + insertion_point = tail; + break; - /* If idx is a symbol, it might have modifiers, which need to - be put in the canonical order. */ - if (XTYPE (idx) == Lisp_Symbol) - idx = reorder_modifiers (idx); - - /* Point to the pair where idx is bound, if any. */ - defining_pair = Fassq (idx, *assoc_head); + case Lisp_Cons: + if (EQ (idx, XCONS (elt)->car)) + { + XCONS (elt)->cdr = def; + return def; + } + break; - if (NILP (defining_pair)) - *assoc_head = Fcons (Fcons (idx, def), *assoc_head); - else - Fsetcdr (defining_pair, def); + case Lisp_Symbol: + /* If we find a 'keymap' symbol in the spine of KEYMAP, + then we must have found the start of a second keymap + being used as the tail of KEYMAP, and a binding for IDX + should be inserted before it. */ + if (EQ (elt, Qkeymap)) + goto keymap_end; + break; + } } + + keymap_end: + /* We have scanned the entire keymap, and not found a binding for + IDX. Let's add one. */ + XCONS (insertion_point)->cdr = + Fcons (Fcons (idx, def), XCONS (insertion_point)->cdr); } - + return def; } + DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 0, "Return a copy of the keymap KEYMAP.\n\ The copy starts out with the same definitions of KEYMAP,\n\ @@ -372,43 +400,29 @@ register Lisp_Object copy, tail; copy = Fcopy_alist (get_keymap (keymap)); - tail = XCONS (copy)->cdr; - /* If this is a dense keymap, copy the vector. */ - if (CONSP (tail)) + for (tail = copy; CONSP (tail); tail = XCONS (tail)->cdr) { - register Lisp_Object table = XCONS (tail)->car; + Lisp_Object elt = XCONS (tail)->car; - if (XTYPE (table) == Lisp_Vector - && XVECTOR (table)->size == DENSE_TABLE_SIZE) + if (XTYPE (elt) == Lisp_Vector + && XVECTOR (elt)->size == DENSE_TABLE_SIZE) { - register int i; + int i; - table = Fcopy_sequence (table); + elt = Fcopy_sequence (elt); + XCONS (tail)->car = elt; for (i = 0; i < DENSE_TABLE_SIZE; i++) - if (XTYPE (XVECTOR (copy)->contents[i]) != Lisp_Symbol) - if (! NILP (Fkeymapp (XVECTOR (table)->contents[i]))) - XVECTOR (table)->contents[i] - = Fcopy_keymap (XVECTOR (table)->contents[i]); - XCONS (tail)->car = table; - - tail = XCONS (tail)->cdr; + if (XTYPE (XVECTOR (elt)->contents[i]) != Lisp_Symbol + && Fkeymapp (XVECTOR (elt)->contents[i])) + XVECTOR (elt)->contents[i] = + Fcopy_keymap (XVECTOR (elt)->contents[i]); } - } - - /* Copy the alist portion of the keymap. */ - while (CONSP (tail)) - { - register Lisp_Object elt; - - elt = XCONS (tail)->car; - if (CONSP (elt) - && XTYPE (XCONS (elt)->cdr) != Lisp_Symbol - && ! NILP (Fkeymapp (XCONS (elt)->cdr))) + else if (CONSP (elt) + && XTYPE (XCONS (elt)->cdr) != Lisp_Symbol + && ! NILP (Fkeymapp (XCONS (elt)->cdr))) XCONS (elt)->cdr = Fcopy_keymap (XCONS (elt)->cdr); - - tail = XCONS (tail)->cdr; } return copy; @@ -897,7 +911,6 @@ Lisp_Object maps, tail; maps = Fcons (Fcons (build_string (""), get_keymap (startmap)), Qnil); - tail = maps; /* For each map in the list maps, look at any other maps it points to, @@ -906,7 +919,7 @@ This is a breadth-first traversal, where tail is the queue of nodes, and maps accumulates a list of all nodes visited. */ - while (!NILP (tail)) + for (tail = maps; CONSP (tail); tail = XCONS (tail)->cdr) { register Lisp_Object thisseq = Fcar (Fcar (tail)); register Lisp_Object thismap = Fcdr (Fcar (tail)); @@ -916,14 +929,13 @@ int is_metized = (XINT (last) >= 0 && EQ (Faref (thisseq, last), meta_prefix_char)); - /* Skip the 'keymap element of the list. */ - thismap = Fcdr (thismap); + for (; CONSP (thismap); thismap = XCONS (thismap)->cdr) + { + Lisp_Object elt = XCONS (thismap)->car; - if (CONSP (thismap)) - { - register Lisp_Object table = XCONS (thismap)->car; + QUIT; - if (XTYPE (table) == Lisp_Vector) + if (XTYPE (elt) == Lisp_Vector) { register int i; @@ -933,7 +945,7 @@ register Lisp_Object tem; register Lisp_Object cmd; - cmd = get_keyelt (XVECTOR (table)->contents[i]); + cmd = get_keyelt (XVECTOR (elt)->contents[i]); if (NILP (cmd)) continue; tem = Fkeymapp (cmd); if (!NILP (tem)) @@ -946,7 +958,8 @@ /* If the last key in thisseq is meta-prefix-char, turn it into a meta-ized keystroke. We know that the event we're about to append is an - ascii keystroke. */ + ascii keystroke since we're processing a + keymap table. */ if (is_metized) { tem = Fcopy_sequence (thisseq); @@ -966,20 +979,8 @@ } } } - - /* Once finished with the lookup elements of the dense - keymap, go on to scan its assoc list. */ - thismap = XCONS (thismap)->cdr; - } - } - - /* The rest is an alist. Scan all the alist elements. */ - while (CONSP (thismap)) - { - Lisp_Object elt = XCONS (thismap)->car; - - /* Ignore elements that are not conses. */ - if (CONSP (elt)) + } + else if (CONSP (elt)) { register Lisp_Object cmd = get_keyelt (XCONS (elt)->cdr); register Lisp_Object tem; @@ -1017,11 +1018,7 @@ } } } - - thismap = XCONS (thismap)->cdr; } - - tail = Fcdr (tail); } return maps; @@ -1206,10 +1203,14 @@ for (; !NILP (maps); maps = Fcdr (maps)) { - register this = Fcar (Fcar (maps)); /* Key sequence to reach map */ - register map = Fcdr (Fcar (maps)); /* The map that it reaches */ - register dense_alist; - register int i = 0; + /* Key sequence to reach map */ + register Lisp_Object this = Fcar (Fcar (maps)); + + /* The map that it reaches */ + register Lisp_Object map = Fcdr (Fcar (maps)); + + /* If Fcar (map) is a VECTOR, the current element within that vector. */ + int i = 0; /* In order to fold [META-PREFIX-CHAR CHAR] sequences into [M-CHAR] sequences, check if last character of the sequence @@ -1217,54 +1218,50 @@ Lisp_Object last = make_number (XINT (Flength (this)) - 1); int last_is_meta = (XINT (last) >= 0 && EQ (Faref (this, last), meta_prefix_char)); - - /* Skip the 'keymap element of the list. */ - map = Fcdr (map); - /* If the keymap is sparse, map traverses the alist to the end. + while (CONSP (map)) + { + /* Because the code we want to run on each binding is rather + large, we don't want to have two separate loop bodies for + sparse keymap bindings and tables; we want to iterate one + loop body over both keymap and vector bindings. - If the keymap is dense, we set map to the vector and - dense_alist to the assoc-list portion of the keymap. When we - are finished dealing with the vector portion, we set map to - dense_alist, and handle the rest like a sparse keymap. */ - if (XTYPE (XCONS (map)->car) == Lisp_Vector) - { - dense_alist = XCONS (map)->cdr; - map = XCONS (map)->car; - } + For this reason, if Fcar (map) is a vector, we don't + advance map to the next element until i indicates that we + have finished off the vector. */ + + Lisp_Object elt = XCONS (map)->car; + Lisp_Object key, binding, sequence; - while (1) - { - register Lisp_Object key, binding, sequence; - - QUIT; - if (XTYPE (map) == Lisp_Vector) + /* Set key and binding to the current key and binding, and + advance map and i to the next binding. */ + if (XTYPE (elt) == Lisp_Vector) { /* In a vector, look at each element. */ - binding = XVECTOR (map)->contents[i]; + binding = XVECTOR (elt)->contents[i]; XFASTINT (key) = i; i++; - /* If we've just finished scanning a vector, switch map to - the assoc-list at the end of the vector. */ + /* If we've just finished scanning a vector, advance map + to the next element, and reset i in anticipation of the + next vector we may find. */ if (i >= DENSE_TABLE_SIZE) - map = dense_alist; + { + map = XCONS (map)->cdr; + i = 0; + } } - else if (CONSP (map)) + else if (CONSP (elt)) { - /* In an alist, ignore elements that aren't conses. */ - if (! CONSP (XCONS (map)->car)) - { - /* Ignore other elements. */ - map = Fcdr (map); - continue; - } + key = Fcar (Fcar (map)); binding = Fcdr (Fcar (map)); - key = Fcar (Fcar (map)); - map = Fcdr (map); + + map = XCONS (map)->cdr; } else - break; + /* We want to ignore keymap elements that are neither + vectors nor conses. */ + continue; /* Search through indirections unless that's not wanted. */ if (NILP (noindirect)) @@ -1575,28 +1572,14 @@ else keysdesc = Qnil; - /* Skip the 'keymap element of the list. */ - map = Fcdr (map); - - /* If this is a dense keymap, take care of the table. */ - if (CONSP (map) - && XTYPE (XCONS (map)->car) == Lisp_Vector) - { - describe_vector (XCONS (map)->car, keysdesc, describe_command, - partial, shadow); - map = XCONS (map)->cdr; - } - - /* Now map is an alist. */ - describe_alist (map, keysdesc, describe_command, partial, shadow); + describe_map_2 (map, keysdesc, describe_command, partial, shadow); } -/* Insert a description of ALIST into the current buffer. - Note that ALIST is just a plain association list, not a keymap. */ +/* Insert a description of KEYMAP into the current buffer. */ static void -describe_alist (alist, elt_prefix, elt_describer, partial, shadow) - register Lisp_Object alist; +describe_map_2 (keymap, elt_prefix, elt_describer, partial, shadow) + register Lisp_Object keymap; Lisp_Object elt_prefix; int (*elt_describer) (); int partial; @@ -1613,56 +1596,63 @@ suppress = intern ("suppress-keymap"); /* This vector gets used to present single keys to Flookup_key. Since - that is done once per alist element, we don't want to cons up a + 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); GCPRO3 (elt_prefix, tem2, kludge); - for (; CONSP (alist); alist = Fcdr (alist)) + for (; CONSP (keymap); keymap = Fcdr (keymap)) { QUIT; - tem1 = Fcar_safe (Fcar (alist)); - tem2 = get_keyelt (Fcdr_safe (Fcar (alist))); - /* Don't show undefined commands or suppressed commands. */ - if (NILP (tem2)) continue; - if (XTYPE (tem2) == Lisp_Symbol && partial) + if (XTYPE (XCONS (keymap)->car) == Lisp_Vector) + describe_vector (XCONS (keymap)->car, + elt_prefix, elt_describer, partial, shadow); + else { - this = Fget (tem2, suppress); - if (!NILP (this)) - continue; - } + tem1 = Fcar_safe (Fcar (keymap)); + tem2 = get_keyelt (Fcdr_safe (Fcar (keymap))); - /* Don't show a command that isn't really visible - because a local definition of the same key shadows it. */ + /* Don't show undefined commands or suppressed commands. */ + if (NILP (tem2)) continue; + if (XTYPE (tem2) == Lisp_Symbol && partial) + { + this = Fget (tem2, suppress); + if (!NILP (this)) + continue; + } - if (!NILP (shadow)) - { - Lisp_Object tem; + /* Don't show a command that isn't really visible + because a local definition of the same key shadows it. */ - XVECTOR (kludge)->contents[0] = tem1; - tem = Flookup_key (shadow, kludge); - if (!NILP (tem)) continue; - } + if (!NILP (shadow)) + { + Lisp_Object tem; - if (first) - { - insert ("\n", 1); - first = 0; - } + XVECTOR (kludge)->contents[0] = tem1; + tem = Flookup_key (shadow, kludge); + if (!NILP (tem)) continue; + } - if (!NILP (elt_prefix)) - insert1 (elt_prefix); + if (first) + { + insert ("\n", 1); + first = 0; + } + + if (!NILP (elt_prefix)) + insert1 (elt_prefix); - /* THIS gets the string to describe the character TEM1. */ - this = Fsingle_key_description (tem1); - insert1 (this); + /* THIS gets the string to describe the character TEM1. */ + this = Fsingle_key_description (tem1); + insert1 (this); - /* Print a description of the definition of this character. - elt_describer will take care of spacing out far enough - for alignment purposes. */ - (*elt_describer) (tem2); + /* Print a description of the definition of this character. + elt_describer will take care of spacing out far enough + for alignment purposes. */ + (*elt_describer) (tem2); + } } UNGCPRO;