aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Monnier2000-10-25 23:35:21 +0000
committerStefan Monnier2000-10-25 23:35:21 +0000
commit1e7d1ab059a1cab5f042f9a3fe6cb99dfdcb36c9 (patch)
tree10fbe3ab5981094f49d23d853399c7b9e15b9ed2 /src
parent5e011cb2e878f607b7154af46b6aec94e0df27a5 (diff)
downloademacs-1e7d1ab059a1cab5f042f9a3fe6cb99dfdcb36c9.tar.gz
emacs-1e7d1ab059a1cab5f042f9a3fe6cb99dfdcb36c9.zip
(where_is_cache, where_is_cache_keymaps): New vars.
(Fset_keymap_parent, store_in_keymap): Flush the where-is cache. (where_is_internal): Renamed from Fwhere_is_internal. Don't DEFUN any more. Arg `xkeymap' replaced by `keymaps'. (Fwhere_is_internal): New function wrapping where_is_internal. (where_is_internal_1): Handle the case where we're filling the cache. (syms_of_keymap): Init and gcpro the where_is_cache(|_keymaps).
Diffstat (limited to 'src')
-rw-r--r--src/keymap.c169
1 files changed, 122 insertions, 47 deletions
diff --git a/src/keymap.c b/src/keymap.c
index cd8f1146d37..0f61304a8e5 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -100,6 +100,11 @@ extern Lisp_Object meta_prefix_char;
100 100
101extern Lisp_Object Voverriding_local_map; 101extern Lisp_Object Voverriding_local_map;
102 102
103/* Hash table used to cache a reverse-map to speed up calls to where-is. */
104static Lisp_Object where_is_cache;
105/* Which keymaps are reverse-stored in the cache. */
106static Lisp_Object where_is_cache_keymaps;
107
103static Lisp_Object store_in_keymap P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); 108static Lisp_Object store_in_keymap P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
104static void fix_submap_inheritance P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); 109static void fix_submap_inheritance P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
105 110
@@ -313,6 +318,15 @@ PARENT should be nil or another keymap.")
313 struct gcpro gcpro1; 318 struct gcpro gcpro1;
314 int i; 319 int i;
315 320
321 /* Force a keymap flush for the next call to where-is.
322 Since this can be called from within where-is, we don't set where_is_cache
323 directly but only where_is_cache_keymaps, since where_is_cache shouldn't
324 be changed during where-is, while where_is_cache_keymaps is only used at
325 the very beginning of where-is and can thus be changed here without any
326 adverse effect.
327 This is a very minor correctness (rather than safety) issue. */
328 where_is_cache_keymaps = Qt;
329
316 keymap = get_keymap_1 (keymap, 1, 1); 330 keymap = get_keymap_1 (keymap, 1, 1);
317 GCPRO1 (keymap); 331 GCPRO1 (keymap);
318 332
@@ -665,6 +679,10 @@ store_in_keymap (keymap, idx, def)
665 register Lisp_Object idx; 679 register Lisp_Object idx;
666 register Lisp_Object def; 680 register Lisp_Object def;
667{ 681{
682 /* Flush any reverse-map cache. */
683 where_is_cache = Qnil;
684 where_is_cache_keymaps = Qt;
685
668 /* If we are preparing to dump, and DEF is a menu element 686 /* If we are preparing to dump, and DEF is a menu element
669 with a menu item indicator, copy it to ensure it is not pure. */ 687 with a menu item indicator, copy it to ensure it is not pure. */
670 if (CONSP (def) && PURE_P (def) 688 if (CONSP (def) && PURE_P (def)
@@ -2054,46 +2072,17 @@ shadow_lookup (shadow, key, flag)
2054 2072
2055/* This function can GC if Flookup_key autoloads any keymaps. */ 2073/* This function can GC if Flookup_key autoloads any keymaps. */
2056 2074
2057DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 4, 0, 2075static Lisp_Object
2058 "Return list of keys that invoke DEFINITION.\n\ 2076where_is_internal (definition, keymaps, firstonly, noindirect)
2059If KEYMAP is non-nil, search only KEYMAP and the global keymap.\n\ 2077 Lisp_Object definition, keymaps;
2060If KEYMAP is nil, search all the currently active keymaps.\n\
2061If KEYMAP is a list of keymaps, search only those keymaps.\n\
2062\n\
2063If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found,\n\
2064rather than a list of all possible key sequences.\n\
2065If FIRSTONLY is the symbol `non-ascii', return the first binding found,\n\
2066no matter what it is.\n\
2067If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters,\n\
2068and entirely reject menu bindings.\n\
2069\n\
2070If optional 4th arg NOINDIRECT is non-nil, don't follow indirections\n\
2071to other keymaps or slots. This makes it possible to search for an\n\
2072indirect definition itself.")
2073 (definition, xkeymap, firstonly, noindirect)
2074 Lisp_Object definition, xkeymap;
2075 Lisp_Object firstonly, noindirect; 2078 Lisp_Object firstonly, noindirect;
2076{ 2079{
2077 Lisp_Object maps = Qnil; 2080 Lisp_Object maps = Qnil;
2078 Lisp_Object found, sequences; 2081 Lisp_Object found, sequences;
2079 Lisp_Object keymaps;
2080 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; 2082 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
2081 /* 1 means ignore all menu bindings entirely. */ 2083 /* 1 means ignore all menu bindings entirely. */
2082 int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii); 2084 int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii);
2083 2085
2084 /* Find keymaps accessible from `xkeymap' or the current context. */
2085 if (CONSP (xkeymap) && KEYMAPP (XCAR (xkeymap)))
2086 keymaps = xkeymap;
2087 else if (! NILP (xkeymap))
2088 keymaps = Fcons (xkeymap, Fcons (current_global_map, Qnil));
2089 else
2090 keymaps =
2091 Fdelq (Qnil,
2092 nconc2 (Fcurrent_minor_mode_maps (),
2093 Fcons (get_local_map (PT, current_buffer, keymap),
2094 Fcons (get_local_map (PT, current_buffer, local_map),
2095 Fcons (current_global_map, Qnil)))));
2096
2097 found = keymaps; 2086 found = keymaps;
2098 while (CONSP (found)) 2087 while (CONSP (found))
2099 { 2088 {
@@ -2213,8 +2202,7 @@ indirect definition itself.")
2213 2202
2214 Either nil or number as value from Flookup_key 2203 Either nil or number as value from Flookup_key
2215 means undefined. */ 2204 means undefined. */
2216 binding = shadow_lookup (keymaps, sequence, Qnil); 2205 if (!EQ (shadow_lookup (keymaps, sequence, Qnil), definition))
2217 if (!EQ (binding, definition))
2218 continue; 2206 continue;
2219 2207
2220 /* It is a true unshadowed match. Record it, unless it's already 2208 /* It is a true unshadowed match. Record it, unless it's already
@@ -2247,6 +2235,87 @@ indirect definition itself.")
2247 return found; 2235 return found;
2248} 2236}
2249 2237
2238DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 4, 0,
2239 "Return list of keys that invoke DEFINITION.\n\
2240If KEYMAP is non-nil, search only KEYMAP and the global keymap.\n\
2241If KEYMAP is nil, search all the currently active keymaps.\n\
2242If KEYMAP is a list of keymaps, search only those keymaps.\n\
2243\n\
2244If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found,\n\
2245rather than a list of all possible key sequences.\n\
2246If FIRSTONLY is the symbol `non-ascii', return the first binding found,\n\
2247no matter what it is.\n\
2248If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters,\n\
2249and entirely reject menu bindings.\n\
2250\n\
2251If optional 4th arg NOINDIRECT is non-nil, don't follow indirections\n\
2252to other keymaps or slots. This makes it possible to search for an\n\
2253indirect definition itself.")
2254 (definition, xkeymap, firstonly, noindirect)
2255 Lisp_Object definition, xkeymap;
2256 Lisp_Object firstonly, noindirect;
2257{
2258 Lisp_Object sequences, keymaps;
2259 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2260 /* 1 means ignore all menu bindings entirely. */
2261 int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii);
2262
2263 /* Find the relevant keymaps. */
2264 if (CONSP (xkeymap) && KEYMAPP (XCAR (xkeymap)))
2265 keymaps = xkeymap;
2266 else if (! NILP (xkeymap))
2267 keymaps = Fcons (xkeymap, Fcons (current_global_map, Qnil));
2268 else
2269 keymaps =
2270 Fdelq (Qnil,
2271 nconc2 (Fcurrent_minor_mode_maps (),
2272 Fcons (get_local_map (PT, current_buffer, keymap),
2273 Fcons (get_local_map (PT, current_buffer, local_map),
2274 Fcons (current_global_map, Qnil)))));
2275
2276 /* Only use caching for the menubar (i.e. called with (def nil t nil).
2277 We don't really need to check `xkeymap'. */
2278 if (nomenus && NILP (noindirect) && NILP (xkeymap))
2279 {
2280 /* Check heuristic-consistency of the cache. */
2281 if (NILP (Fequal (keymaps, where_is_cache_keymaps)))
2282 where_is_cache = Qnil;
2283
2284 if (NILP (where_is_cache))
2285 {
2286 /* We need to create the cache. */
2287 Lisp_Object args[2];
2288 where_is_cache = Fmake_hash_table (0, args);
2289 where_is_cache_keymaps = Qt;
2290
2291 /* Fill in the cache. */
2292 GCPRO4 (definition, keymaps, firstonly, noindirect);
2293 where_is_internal (definition, keymaps, firstonly, noindirect);
2294 UNGCPRO;
2295
2296 where_is_cache_keymaps = keymaps;
2297 }
2298
2299 sequences = Fgethash (definition, where_is_cache, Qnil);
2300 /* Verify that the key bindings are not shadowed. */
2301 /* key-binding can GC. */
2302 GCPRO3 (definition, sequences, keymaps);
2303 for (sequences = Fnreverse (sequences);
2304 CONSP (sequences);
2305 sequences = XCDR (sequences))
2306 if (EQ (shadow_lookup (keymaps, XCAR (sequences), Qnil), definition))
2307 RETURN_UNGCPRO (XCAR (sequences));
2308 RETURN_UNGCPRO (Qnil);
2309 }
2310 else
2311 {
2312 /* Kill the cache so that where_is_internal_1 doesn't think
2313 we're filling it up. */
2314 where_is_cache = Qnil;
2315 return where_is_internal (definition, keymaps, firstonly, noindirect);
2316 }
2317}
2318
2250/* This is the function that Fwhere_is_internal calls using map_char_table. 2319/* This is the function that Fwhere_is_internal calls using map_char_table.
2251 ARGS has the form 2320 ARGS has the form
2252 (((DEFINITION . NOINDIRECT) . (KEYMAP . RESULT)) 2321 (((DEFINITION . NOINDIRECT) . (KEYMAP . RESULT))
@@ -2307,19 +2376,13 @@ where_is_internal_1 (binding, key, definition, noindirect, this, last,
2307 /* End this iteration if this element does not match 2376 /* End this iteration if this element does not match
2308 the target. */ 2377 the target. */
2309 2378
2310 if (CONSP (definition)) 2379 if (!(!NILP (where_is_cache) /* everything "matches" during cache-fill. */
2311 { 2380 || EQ (binding, definition)
2312 Lisp_Object tem; 2381 || (CONSP (definition) && !NILP (Fequal (binding, definition)))))
2313 tem = Fequal (binding, definition); 2382 /* Doesn't match. */
2314 if (NILP (tem)) 2383 return Qnil;
2315 return Qnil;
2316 }
2317 else
2318 if (!EQ (binding, definition))
2319 return Qnil;
2320 2384
2321 /* We have found a match. 2385 /* We have found a match. Construct the key sequence where we found it. */
2322 Construct the key sequence where we found it. */
2323 if (INTEGERP (key) && last_is_meta) 2386 if (INTEGERP (key) && last_is_meta)
2324 { 2387 {
2325 sequence = Fcopy_sequence (this); 2388 sequence = Fcopy_sequence (this);
@@ -2328,7 +2391,14 @@ where_is_internal_1 (binding, key, definition, noindirect, this, last,
2328 else 2391 else
2329 sequence = append_key (this, key); 2392 sequence = append_key (this, key);
2330 2393
2331 return sequence; 2394 if (!NILP (where_is_cache))
2395 {
2396 Lisp_Object sequences = Fgethash (binding, where_is_cache, Qnil);
2397 Fputhash (binding, Fcons (sequence, sequences), where_is_cache);
2398 return Qnil;
2399 }
2400 else
2401 return sequence;
2332} 2402}
2333 2403
2334/* describe-bindings - summarizing all the bindings in a set of keymaps. */ 2404/* describe-bindings - summarizing all the bindings in a set of keymaps. */
@@ -3321,6 +3391,11 @@ and applies even for keys that have ordinary bindings.");
3321 Qmenu_item = intern ("menu-item"); 3391 Qmenu_item = intern ("menu-item");
3322 staticpro (&Qmenu_item); 3392 staticpro (&Qmenu_item);
3323 3393
3394 where_is_cache_keymaps = Qt;
3395 where_is_cache = Qnil;
3396 staticpro (&where_is_cache);
3397 staticpro (&where_is_cache_keymaps);
3398
3324 defsubr (&Skeymapp); 3399 defsubr (&Skeymapp);
3325 defsubr (&Skeymap_parent); 3400 defsubr (&Skeymap_parent);
3326 defsubr (&Sset_keymap_parent); 3401 defsubr (&Sset_keymap_parent);