+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.
+If KEYMAP is a list of keymaps, search only those keymaps.
+
+If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found,
+rather than a list of all possible key sequences.
+If FIRSTONLY is the symbol `non-ascii', return the first binding found,
+no matter what it is.
+If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters,
+and entirely reject menu bindings.
+
+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.
+
+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, no_remap;
+{
+ Lisp_Object sequences, keymaps;
+ /* 1 means ignore all menu bindings entirely. */
+ int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii);
+ Lisp_Object result;
+
+ /* Find the relevant keymaps. */
+ if (CONSP (keymap) && KEYMAPP (XCAR (keymap)))
+ keymaps = keymap;
+ else if (!NILP (keymap))
+ keymaps = Fcons (keymap, Fcons (current_global_map, Qnil));
+ else
+ keymaps = Fcurrent_active_maps (Qnil);
+
+ /* Only use caching for the menubar (i.e. called with (def nil t nil).
+ We don't really need to check `keymap'. */
+ if (nomenus && NILP (noindirect) && NILP (keymap))
+ {
+ Lisp_Object *defns;
+ int i, j, n;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+
+ /* Check heuristic-consistency of the cache. */
+ if (NILP (Fequal (keymaps, where_is_cache_keymaps)))
+ where_is_cache = Qnil;
+
+ if (NILP (where_is_cache))
+ {
+ /* We need to create the cache. */
+ Lisp_Object args[2];
+ where_is_cache = Fmake_hash_table (0, args);
+ where_is_cache_keymaps = Qt;
+
+ /* Fill in the cache. */
+ GCPRO5 (definition, keymaps, firstonly, noindirect, no_remap);
+ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap);
+ UNGCPRO;
+
+ where_is_cache_keymaps = keymaps;
+ }
+
+ /* We want to process definitions from the last to the first.
+ Instead of consing, copy definitions to a vector and step
+ over that vector. */
+ sequences = Fgethash (definition, where_is_cache, Qnil);
+ n = XINT (Flength (sequences));
+ defns = (Lisp_Object *) alloca (n * sizeof *defns);
+ for (i = 0; CONSP (sequences); sequences = XCDR (sequences))
+ defns[i++] = XCAR (sequences);
+
+ /* Verify that the key bindings are not shadowed. Note that
+ the following can GC. */
+ GCPRO2 (definition, keymaps);
+ result = Qnil;
+ j = -1;
+ for (i = n - 1; i >= 0; --i)
+ if (EQ (shadow_lookup (keymaps, defns[i], Qnil), definition))
+ {
+ if (ascii_sequence_p (defns[i]))
+ break;
+ else if (j < 0)
+ j = i;
+ }
+
+ result = i >= 0 ? defns[i] : (j >= 0 ? defns[j] : Qnil);
+ UNGCPRO;
+ }
+ else
+ {
+ /* 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, no_remap);
+ }
+
+ return result;
+}
+