diff options
| author | Stefan Monnier | 2000-10-25 23:35:21 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2000-10-25 23:35:21 +0000 |
| commit | 1e7d1ab059a1cab5f042f9a3fe6cb99dfdcb36c9 (patch) | |
| tree | 10fbe3ab5981094f49d23d853399c7b9e15b9ed2 /src | |
| parent | 5e011cb2e878f607b7154af46b6aec94e0df27a5 (diff) | |
| download | emacs-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.c | 169 |
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 | ||
| 101 | extern Lisp_Object Voverriding_local_map; | 101 | extern Lisp_Object Voverriding_local_map; |
| 102 | 102 | ||
| 103 | /* Hash table used to cache a reverse-map to speed up calls to where-is. */ | ||
| 104 | static Lisp_Object where_is_cache; | ||
| 105 | /* Which keymaps are reverse-stored in the cache. */ | ||
| 106 | static Lisp_Object where_is_cache_keymaps; | ||
| 107 | |||
| 103 | static Lisp_Object store_in_keymap P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); | 108 | static Lisp_Object store_in_keymap P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); |
| 104 | static void fix_submap_inheritance P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); | 109 | static 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 | ||
| 2057 | DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 4, 0, | 2075 | static Lisp_Object |
| 2058 | "Return list of keys that invoke DEFINITION.\n\ | 2076 | where_is_internal (definition, keymaps, firstonly, noindirect) |
| 2059 | If KEYMAP is non-nil, search only KEYMAP and the global keymap.\n\ | 2077 | Lisp_Object definition, keymaps; |
| 2060 | If KEYMAP is nil, search all the currently active keymaps.\n\ | ||
| 2061 | If KEYMAP is a list of keymaps, search only those keymaps.\n\ | ||
| 2062 | \n\ | ||
| 2063 | If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found,\n\ | ||
| 2064 | rather than a list of all possible key sequences.\n\ | ||
| 2065 | If FIRSTONLY is the symbol `non-ascii', return the first binding found,\n\ | ||
| 2066 | no matter what it is.\n\ | ||
| 2067 | If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters,\n\ | ||
| 2068 | and entirely reject menu bindings.\n\ | ||
| 2069 | \n\ | ||
| 2070 | If optional 4th arg NOINDIRECT is non-nil, don't follow indirections\n\ | ||
| 2071 | to other keymaps or slots. This makes it possible to search for an\n\ | ||
| 2072 | indirect 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 | ||
| 2238 | DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 4, 0, | ||
| 2239 | "Return list of keys that invoke DEFINITION.\n\ | ||
| 2240 | If KEYMAP is non-nil, search only KEYMAP and the global keymap.\n\ | ||
| 2241 | If KEYMAP is nil, search all the currently active keymaps.\n\ | ||
| 2242 | If KEYMAP is a list of keymaps, search only those keymaps.\n\ | ||
| 2243 | \n\ | ||
| 2244 | If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found,\n\ | ||
| 2245 | rather than a list of all possible key sequences.\n\ | ||
| 2246 | If FIRSTONLY is the symbol `non-ascii', return the first binding found,\n\ | ||
| 2247 | no matter what it is.\n\ | ||
| 2248 | If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters,\n\ | ||
| 2249 | and entirely reject menu bindings.\n\ | ||
| 2250 | \n\ | ||
| 2251 | If optional 4th arg NOINDIRECT is non-nil, don't follow indirections\n\ | ||
| 2252 | to other keymaps or slots. This makes it possible to search for an\n\ | ||
| 2253 | indirect 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); |