/* Manipulation of keymaps
- Copyright (C) 1985, 86, 87, 88, 93, 94 Free Software Foundation, Inc.
+ Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
#include <config.h>
#include "keyboard.h"
#include "termhooks.h"
#include "blockinput.h"
+#include "puresize.h"
#define min(a, b) ((a) < (b) ? (a) : (b))
documentation. */
Lisp_Object Vfunction_key_map;
+/* Keymap mapping ASCII function key sequences onto their preferred forms. */
+Lisp_Object Vkey_translation_map;
+
+/* A list of all commands given new bindings since a certain time
+ when nil was stored here.
+ This is used to speed up recomputation of menu key equivalents
+ when Emacs starts up. t means don't record anything here. */
+Lisp_Object Vdefine_key_rebound_commands;
+
Lisp_Object Qkeymapp, Qkeymap, Qnon_ascii;
/* A char with the CHAR_META bit set in a vector or the 0200 bit set
extern Lisp_Object Voverriding_local_map;
-void describe_map_tree ();
static Lisp_Object define_as_prefix ();
static Lisp_Object describe_buffer_bindings ();
-static void describe_command ();
+static void describe_command (), describe_translation ();
static void describe_map ();
\f
/* Keymap object support - constructors and predicates. */
int fromchar, tochar;
{
Lisp_Object v, c;
- XSET (v, Lisp_Vector, tomap);
- XFASTINT (c) = tochar;
+ XSETVECTOR (v, tomap);
+ XSETFASTINT (c, tochar);
frommap->contents[fromchar] = Fcons (v, c);
}
#endif /* 0 */
DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0,
- "Return t if ARG is a keymap.\n\
+ "Return t if OBJECT is a keymap.\n\
\n\
A keymap is a list (keymap . ALIST),\n\
or a symbol whose function definition is itself a keymap.\n\
If AUTOLOAD is non-zero and OBJECT is a symbol whose function value
is an autoload form, do the autoload and try again.
+ If AUTOLOAD is nonzero, callers must assume GC is possible.
ERROR controls how we respond if OBJECT isn't a keymap.
If ERROR is non-zero, signal an error; otherwise, just return Qnil.
/* Should we do an autoload? Autoload forms for keymaps have
Qkeymap as their fifth element. */
if (autoload
- && XTYPE (object) == Lisp_Symbol
+ && SYMBOLP (object)
&& CONSP (tem)
&& EQ (XCONS (tem)->car, Qautoload))
{
{
return get_keymap_1 (object, 1, 0);
}
+\f
+/* Return the parent map of the keymap MAP, or nil if it has none.
+ We assume that MAP is a valid keymap. */
+
+DEFUN ("keymap-parent", Fkeymap_parent, Skeymap_parent, 1, 1, 0,
+ "Return the parent keymap of KEYMAP.")
+ (keymap)
+ Lisp_Object keymap;
+{
+ Lisp_Object list;
+
+ keymap = get_keymap_1 (keymap, 1, 1);
+
+ /* Skip past the initial element `keymap'. */
+ list = XCONS (keymap)->cdr;
+ for (; CONSP (list); list = XCONS (list)->cdr)
+ {
+ /* See if there is another `keymap'. */
+ if (EQ (Qkeymap, XCONS (list)->car))
+ return list;
+ }
+
+ return Qnil;
+}
+
+/* Set the parent keymap of MAP to PARENT. */
+DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0,
+ "Modify KEYMAP to set its parent map to PARENT.\n\
+PARENT should be nil or another keymap.")
+ (keymap, parent)
+ Lisp_Object keymap, parent;
+{
+ Lisp_Object list, prev;
+ int i;
+ keymap = get_keymap_1 (keymap, 1, 1);
+ if (!NILP (parent))
+ parent = get_keymap_1 (parent, 1, 1);
+
+ /* Skip past the initial element `keymap'. */
+ prev = keymap;
+ while (1)
+ {
+ list = XCONS (prev)->cdr;
+ /* If there is a parent keymap here, replace it.
+ If we came to the end, add the parent in PREV. */
+ if (! CONSP (list) || EQ (Qkeymap, XCONS (list)->car))
+ {
+ /* If we already have the right parent, return now
+ so that we avoid the loops below. */
+ if (EQ (XCONS (prev)->cdr, parent))
+ return parent;
+
+ XCONS (prev)->cdr = parent;
+ break;
+ }
+ prev = list;
+ }
+
+ /* Scan through for submaps, and set their parents too. */
+
+ for (list = XCONS (keymap)->cdr; CONSP (list); list = XCONS (list)->cdr)
+ {
+ /* Stop the scan when we come to the parent. */
+ if (EQ (XCONS (list)->car, Qkeymap))
+ break;
+
+ /* If this element holds a prefix map, deal with it. */
+ if (CONSP (XCONS (list)->car)
+ && CONSP (XCONS (XCONS (list)->car)->cdr))
+ fix_submap_inheritance (keymap, XCONS (XCONS (list)->car)->car,
+ XCONS (XCONS (list)->car)->cdr);
+
+ if (VECTORP (XCONS (list)->car))
+ for (i = 0; i < XVECTOR (XCONS (list)->car)->size; i++)
+ if (CONSP (XVECTOR (XCONS (list)->car)->contents[i]))
+ fix_submap_inheritance (keymap, make_number (i),
+ XVECTOR (XCONS (list)->car)->contents[i]);
+ }
+
+ return parent;
+}
+
+/* EVENT is defined in MAP as a prefix, and SUBMAP is its definition.
+ if EVENT is also a prefix in MAP's parent,
+ make sure that SUBMAP inherits that definition as its own parent. */
+
+fix_submap_inheritance (map, event, submap)
+ Lisp_Object map, event, submap;
+{
+ Lisp_Object map_parent, parent_entry;
+
+ /* SUBMAP is a cons that we found as a key binding.
+ Discard the other things found in a menu key binding. */
+
+ if (CONSP (submap)
+ && STRINGP (XCONS (submap)->car))
+ {
+ submap = XCONS (submap)->cdr;
+ /* Also remove a menu help string, if any,
+ following the menu item name. */
+ if (CONSP (submap) && STRINGP (XCONS (submap)->car))
+ submap = XCONS (submap)->cdr;
+ /* Also remove the sublist that caches key equivalences, if any. */
+ if (CONSP (submap)
+ && CONSP (XCONS (submap)->car))
+ {
+ Lisp_Object carcar;
+ carcar = XCONS (XCONS (submap)->car)->car;
+ if (NILP (carcar) || VECTORP (carcar))
+ submap = XCONS (submap)->cdr;
+ }
+ }
+
+ /* If it isn't a keymap now, there's no work to do. */
+ if (! CONSP (submap)
+ || ! EQ (XCONS (submap)->car, Qkeymap))
+ return;
+
+ map_parent = Fkeymap_parent (map);
+ if (! NILP (map_parent))
+ parent_entry = access_keymap (map_parent, event, 0, 0);
+ else
+ parent_entry = Qnil;
+
+ /* If MAP's parent has something other than a keymap,
+ our own submap shadows it completely, so use nil as SUBMAP's parent. */
+ if (! (CONSP (parent_entry) && EQ (XCONS (parent_entry)->car, Qkeymap)))
+ parent_entry = Qnil;
+
+ if (! EQ (parent_entry, submap))
+ Fset_keymap_parent (submap, parent_entry);
+}
+\f
/* 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.
/* If idx is a symbol, it might have modifiers, which need to
be put in the canonical order. */
- if (XTYPE (idx) == Lisp_Symbol)
+ if (SYMBOLP (idx))
idx = reorder_modifiers (idx);
else if (INTEGERP (idx))
/* Clobber the high bits that can be present on a machine
with more than 24 bits of integer. */
- XFASTINT (idx) = XINT (idx) & (CHAR_META | (CHAR_META - 1));
+ XSETFASTINT (idx, XINT (idx) & (CHAR_META | (CHAR_META - 1)));
{
Lisp_Object tail;
Lisp_Object binding;
binding = XCONS (tail)->car;
- switch (XTYPE (binding))
+ if (SYMBOLP (binding))
{
- case Lisp_Symbol:
/* If NOINHERIT, stop finding prefix definitions
after we pass a second occurrence of the `keymap' symbol. */
if (noinherit && EQ (binding, Qkeymap) && ! EQ (tail, map))
noprefix = 1;
- break;
-
- case Lisp_Cons:
+ }
+ else if (CONSP (binding))
+ {
if (EQ (XCONS (binding)->car, idx))
{
val = XCONS (binding)->cdr;
if (noprefix && CONSP (val) && EQ (XCONS (val)->car, Qkeymap))
return Qnil;
+ if (CONSP (val))
+ fix_submap_inheritance (map, idx, val);
return val;
}
if (t_ok && EQ (XCONS (binding)->car, Qt))
t_binding = XCONS (binding)->cdr;
- break;
-
- case Lisp_Vector:
- if (XTYPE (idx) == Lisp_Int
- && XINT (idx) >= 0
- && XINT (idx) < XVECTOR (binding)->size)
+ }
+ else if (VECTORP (binding))
+ {
+ if (NATNUMP (idx) && XFASTINT (idx) < XVECTOR (binding)->size)
{
- val = XVECTOR (binding)->contents[XINT (idx)];
+ val = XVECTOR (binding)->contents[XFASTINT (idx)];
if (noprefix && CONSP (val) && EQ (XCONS (val)->car, Qkeymap))
return Qnil;
+ if (CONSP (val))
+ fix_submap_inheritance (map, idx, val);
return val;
}
- break;
}
QUIT;
use DEFN.
Keymap alist elements like (CHAR MENUSTRING . DEFN)
will be used by HierarKey menus. */
- else if (XTYPE (object) == Lisp_Cons
- && XTYPE (XCONS (object)->car) == Lisp_String)
+ else if (CONSP (object)
+ && STRINGP (XCONS (object)->car))
{
object = XCONS (object)->cdr;
/* Also remove a menu help string, if any,
following the menu item name. */
- if (XTYPE (object) == Lisp_Cons
- && XTYPE (XCONS (object)->car) == Lisp_String)
+ if (CONSP (object) && STRINGP (XCONS (object)->car))
object = XCONS (object)->cdr;
/* Also remove the sublist that caches key equivalences, if any. */
if (CONSP (object)
register Lisp_Object idx;
register Lisp_Object def;
{
- if (XTYPE (keymap) != Lisp_Cons
- || ! EQ (XCONS (keymap)->car, Qkeymap))
+ /* If we are preparing to dump, and DEF is a menu element
+ with a menu item string, copy it to ensure it is not pure. */
+ if (CONSP (def) && PURE_P (def) && STRINGP (XCONS (def)->car))
+ def = Fcons (XCONS (def)->car, XCONS (def)->cdr);
+
+ if (!CONSP (keymap) || ! 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?),
/* If idx is a symbol, it might have modifiers, which need to
be put in the canonical order. */
- if (XTYPE (idx) == Lisp_Symbol)
+ if (SYMBOLP (idx))
idx = reorder_modifiers (idx);
else if (INTEGERP (idx))
/* Clobber the high bits that can be present on a machine
with more than 24 bits of integer. */
- XFASTINT (idx) = XINT (idx) & (CHAR_META | (CHAR_META - 1));
+ XSETFASTINT (idx, XINT (idx) & (CHAR_META | (CHAR_META - 1)));
/* Scan the keymap for a binding of idx. */
{
Lisp_Object elt;
elt = XCONS (tail)->car;
- switch (XTYPE (elt))
+ if (VECTORP (elt))
{
- case Lisp_Vector:
- if (XTYPE (idx) == Lisp_Int
- && XINT (idx) >= 0 && XINT (idx) < XVECTOR (elt)->size)
+ if (NATNUMP (idx) && XFASTINT (idx) < XVECTOR (elt)->size)
{
XVECTOR (elt)->contents[XFASTINT (idx)] = def;
return def;
}
insertion_point = tail;
- break;
-
- case Lisp_Cons:
+ }
+ else if (CONSP (elt))
+ {
if (EQ (idx, XCONS (elt)->car))
{
XCONS (elt)->cdr = def;
return def;
}
- break;
-
- case Lisp_Symbol:
+ }
+ else if (SYMBOLP (elt))
+ {
/* 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;
}
QUIT;
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);
+ XCONS (insertion_point)->cdr
+ = Fcons (Fcons (idx, def), XCONS (insertion_point)->cdr);
}
return def;
Lisp_Object elt;
elt = XCONS (tail)->car;
- if (XTYPE (elt) == Lisp_Vector)
+ if (VECTORP (elt))
{
int i;
XCONS (tail)->car = elt;
for (i = 0; i < XVECTOR (elt)->size; i++)
- if (XTYPE (XVECTOR (elt)->contents[i]) != Lisp_Symbol
+ if (!SYMBOLP (XVECTOR (elt)->contents[i])
&& ! NILP (Fkeymapp (XVECTOR (elt)->contents[i])))
XVECTOR (elt)->contents[i] =
Fcopy_keymap (XVECTOR (elt)->contents[i]);
\f
/* Simple Keymap mutators and accessors. */
+/* GC is possible in this function if it autoloads a keymap. */
+
DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0,
"Args KEYMAP, KEY, DEF. Define key sequence KEY, in KEYMAP, as DEF.\n\
KEYMAP is a keymap. KEY is a string or a vector of symbols and characters\n\
keymap = get_keymap_1 (keymap, 1, 1);
- if (XTYPE (key) != Lisp_Vector
- && XTYPE (key) != Lisp_String)
+ if (!VECTORP (key) && !STRINGP (key))
key = wrong_type_argument (Qarrayp, key);
length = XFASTINT (Flength (key));
if (length == 0)
return Qnil;
+ if (SYMBOLP (def) && !EQ (Vdefine_key_rebound_commands, Qt))
+ Vdefine_key_rebound_commands = Fcons (def, Vdefine_key_rebound_commands);
+
GCPRO3 (keymap, key, def);
- if (XTYPE (key) == Lisp_Vector)
+ if (VECTORP (key))
meta_bit = meta_modifier;
else
meta_bit = 0x80;
{
c = Faref (key, make_number (idx));
- if (XTYPE (c) == Lisp_Int
+ if (CONSP (c) && lucid_event_type_list_p (c))
+ c = Fevent_convert_list (c);
+
+ if (INTEGERP (c)
&& (XINT (c) & meta_bit)
&& !metized)
{
}
else
{
- if (XTYPE (c) == Lisp_Int)
+ if (INTEGERP (c))
XSETINT (c, XINT (c) & ~meta_bit);
metized = 0;
}
if (! INTEGERP (c) && ! SYMBOLP (c) && ! CONSP (c))
- error ("Key sequence contains illegal events");
+ error ("Key sequence contains invalid events");
if (idx == length)
RETURN_UNGCPRO (store_in_keymap (keymap, c, def));
}
/* Value is number if KEY is too long; NIL if valid but has no definition. */
+/* GC is possible in this function if it autoloads a keymap. */
DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
"In keymap KEYMAP, look up key sequence KEY. Return the definition.\n\
\n\
Normally, `lookup-key' ignores bindings for t, which act as default\n\
bindings, used when nothing else in the keymap applies; this makes it\n\
-useable as a general function for probing keymaps. However, if the\n\
+usable as a general function for probing keymaps. However, if the\n\
third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will\n\
recognize the default bindings, just as `read-key-sequence' does.")
(keymap, key, accept_default)
int length;
int t_ok = ! NILP (accept_default);
int meta_bit;
+ struct gcpro gcpro1;
keymap = get_keymap_1 (keymap, 1, 1);
- if (XTYPE (key) != Lisp_Vector
- && XTYPE (key) != Lisp_String)
+ if (!VECTORP (key) && !STRINGP (key))
key = wrong_type_argument (Qarrayp, key);
length = XFASTINT (Flength (key));
if (length == 0)
return keymap;
- if (XTYPE (key) == Lisp_Vector)
+ if (VECTORP (key))
meta_bit = meta_modifier;
else
meta_bit = 0x80;
+ GCPRO1 (key);
+
idx = 0;
while (1)
{
c = Faref (key, make_number (idx));
- if (XTYPE (c) == Lisp_Int
+ if (CONSP (c) && lucid_event_type_list_p (c))
+ c = Fevent_convert_list (c);
+
+ if (INTEGERP (c)
&& (XINT (c) & meta_bit)
&& !metized)
{
}
else
{
- if (XTYPE (c) == Lisp_Int)
+ if (INTEGERP (c))
XSETINT (c, XINT (c) & ~meta_bit);
metized = 0;
cmd = get_keyelt (access_keymap (keymap, c, t_ok, 0), 1);
if (idx == length)
- return cmd;
+ RETURN_UNGCPRO (cmd);
keymap = get_keymap_1 (cmd, 0, 1);
if (NILP (keymap))
- return make_number (idx);
+ RETURN_UNGCPRO (make_number (idx));
QUIT;
}
make it a prefix in this map, and make its definition
inherit the other prefix definition. */
inherit = access_keymap (keymap, c, 0, 0);
+#if 0
+ /* This code is needed to do the right thing in the following case:
+ keymap A inherits from B,
+ you define KEY as a prefix in A,
+ then later you define KEY as a prefix in B.
+ We want the old prefix definition in A to inherit from that in B.
+ It is hard to do that retroactively, so this code
+ creates the prefix in B right away.
+
+ But it turns out that this code causes problems immediately
+ when the prefix in A is defined: it causes B to define KEY
+ as a prefix with no subcommands.
+
+ So I took out this code. */
if (NILP (inherit))
{
/* If there's an inherited keymap
if (!NILP (tail))
inherit = define_as_prefix (tail, c);
}
+#endif
cmd = nconc2 (cmd, inherit);
store_in_keymap (keymap, c, cmd);
static Lisp_Object *cmm_modes, *cmm_maps;
static int cmm_size;
+/* Error handler used in current_minor_maps. */
+static Lisp_Object
+current_minor_maps_error ()
+{
+ return Qnil;
+}
+
/* Store a pointer to an array of the keymaps of the currently active
minor modes in *buf, and return the number of maps it contains.
for (alist = Vminor_mode_map_alist;
CONSP (alist);
alist = XCONS (alist)->cdr)
- if (CONSP (assoc = XCONS (alist)->car)
- && XTYPE (var = XCONS (assoc)->car) == Lisp_Symbol
- && ! EQ ((val = find_symbol_value (var)), Qunbound)
+ if ((assoc = XCONS (alist)->car, CONSP (assoc))
+ && (var = XCONS (assoc)->car, SYMBOLP (var))
+ && (val = find_symbol_value (var), ! EQ (val, Qunbound))
&& ! NILP (val))
{
+ Lisp_Object temp;
+
if (i >= cmm_size)
{
Lisp_Object *newmodes, *newmaps;
else
break;
}
- cmm_modes[i] = var;
- cmm_maps [i] = Findirect_function (XCONS (assoc)->cdr);
- i++;
+
+ /* Get the keymap definition--or nil if it is not defined. */
+ temp = internal_condition_case_1 (Findirect_function,
+ XCONS (assoc)->cdr,
+ Qerror, current_minor_maps_error);
+ if (!NILP (temp))
+ {
+ cmm_modes[i] = var;
+ cmm_maps [i] = temp;
+ i++;
+ }
}
if (modeptr) *modeptr = cmm_modes;
return i;
}
+/* GC is possible in this function if it autoloads a keymap. */
+
DEFUN ("key-binding", Fkey_binding, Skey_binding, 1, 2, 0,
"Return the binding for command KEY in current keymaps.\n\
KEY is a string or vector, a sequence of keystrokes.\n\
{
Lisp_Object *maps, value;
int nmaps, i;
+ struct gcpro gcpro1;
- if (!NILP (Voverriding_local_map))
+ GCPRO1 (key);
+
+ if (!NILP (current_kboard->Voverriding_terminal_local_map))
+ {
+ value = Flookup_key (current_kboard->Voverriding_terminal_local_map,
+ key, accept_default);
+ if (! NILP (value) && !INTEGERP (value))
+ RETURN_UNGCPRO (value);
+ }
+ else if (!NILP (Voverriding_local_map))
{
value = Flookup_key (Voverriding_local_map, key, accept_default);
- if (! NILP (value) && XTYPE (value) != Lisp_Int)
- return value;
+ if (! NILP (value) && !INTEGERP (value))
+ RETURN_UNGCPRO (value);
}
else
{
+ Lisp_Object local;
+
nmaps = current_minor_maps (0, &maps);
+ /* Note that all these maps are GCPRO'd
+ in the places where we found them. */
+
for (i = 0; i < nmaps; i++)
if (! NILP (maps[i]))
{
value = Flookup_key (maps[i], key, accept_default);
- if (! NILP (value) && XTYPE (value) != Lisp_Int)
- return value;
+ if (! NILP (value) && !INTEGERP (value))
+ RETURN_UNGCPRO (value);
}
- if (! NILP (current_buffer->keymap))
+ local = get_local_map (PT, current_buffer);
+
+ if (! NILP (local))
{
- value = Flookup_key (current_buffer->keymap, key, accept_default);
- if (! NILP (value) && XTYPE (value) != Lisp_Int)
- return value;
+ value = Flookup_key (local, key, accept_default);
+ if (! NILP (value) && !INTEGERP (value))
+ RETURN_UNGCPRO (value);
}
}
value = Flookup_key (current_global_map, key, accept_default);
- if (! NILP (value) && XTYPE (value) != Lisp_Int)
+ UNGCPRO;
+ if (! NILP (value) && !INTEGERP (value))
return value;
return Qnil;
}
+/* GC is possible in this function if it autoloads a keymap. */
+
DEFUN ("local-key-binding", Flocal_key_binding, Slocal_key_binding, 1, 2, 0,
"Return the binding for command KEYS in current local keymap only.\n\
KEYS is a string, a sequence of keystrokes.\n\
return Flookup_key (map, keys, accept_default);
}
+/* GC is possible in this function if it autoloads a keymap. */
+
DEFUN ("global-key-binding", Fglobal_key_binding, Sglobal_key_binding, 1, 2, 0,
"Return the binding for command KEYS in current global keymap only.\n\
KEYS is a string, a sequence of keystrokes.\n\
The binding is probably a symbol with a function definition.\n\
This function's return values are the same as those of lookup-key\n\
-(which see).\n\
+\(which see).\n\
\n\
If optional argument ACCEPT-DEFAULT is non-nil, recognize default\n\
bindings; see the description of `lookup-key' for more details about this.")
return Flookup_key (current_global_map, keys, accept_default);
}
+/* GC is possible in this function if it autoloads a keymap. */
+
DEFUN ("minor-mode-key-binding", Fminor_mode_key_binding, Sminor_mode_key_binding, 1, 2, 0,
"Find the visible minor mode bindings of KEY.\n\
Return an alist of pairs (MODENAME . BINDING), where MODENAME is the\n\
int nmaps;
Lisp_Object binding;
int i, j;
+ struct gcpro gcpro1, gcpro2;
nmaps = current_minor_maps (&modes, &maps);
+ /* Note that all these maps are GCPRO'd
+ in the places where we found them. */
+
+ binding = Qnil;
+ GCPRO2 (key, binding);
for (i = j = 0; i < nmaps; i++)
if (! NILP (maps[i])
&& ! NILP (binding = Flookup_key (maps[i], key, accept_default))
- && XTYPE (binding) != Lisp_Int)
+ && !INTEGERP (binding))
{
if (! NILP (get_keymap (binding)))
maps[j++] = Fcons (modes[i], binding);
else if (j == 0)
- return Fcons (Fcons (modes[i], binding), Qnil);
+ RETURN_UNGCPRO (Fcons (Fcons (modes[i], binding), Qnil));
}
+ UNGCPRO;
return Flist (j, maps);
}
-DEFUN ("global-set-key", Fglobal_set_key, Sglobal_set_key, 2, 2,
- "kSet key globally: \nCSet key %s to command: ",
- "Give KEY a global binding as COMMAND.\n\
-COMMAND is a symbol naming an interactively-callable function.\n\
-KEY is a key sequence (a string or vector of characters or event types).\n\
-Non-ASCII characters with codes above 127 (such as ISO Latin-1)\n\
-can be included if you use a vector.\n\
-Note that if KEY has a local binding in the current buffer\n\
-that local binding will continue to shadow any global binding.")
- (keys, function)
- Lisp_Object keys, function;
-{
- if (XTYPE (keys) != Lisp_Vector
- && XTYPE (keys) != Lisp_String)
- keys = wrong_type_argument (Qarrayp, keys);
-
- Fdefine_key (current_global_map, keys, function);
- return Qnil;
-}
-
-DEFUN ("local-set-key", Flocal_set_key, Slocal_set_key, 2, 2,
- "kSet key locally: \nCSet key %s locally to command: ",
- "Give KEY a local binding as COMMAND.\n\
-COMMAND is a symbol naming an interactively-callable function.\n\
-KEY is a key sequence (a string or vector of characters or event types).\n\
-Non-ASCII characters with codes above 127 (such as ISO Latin-1)\n\
-can be included if you use a vector.\n\
-The binding goes in the current buffer's local map,\n\
-which in most cases is shared with all other buffers in the same major mode.")
- (keys, function)
- Lisp_Object keys, function;
-{
- register Lisp_Object map;
- map = current_buffer->keymap;
- if (NILP (map))
- {
- map = Fmake_sparse_keymap (Qnil);
- current_buffer->keymap = map;
- }
-
- if (XTYPE (keys) != Lisp_Vector
- && XTYPE (keys) != Lisp_String)
- keys = wrong_type_argument (Qarrayp, keys);
-
- Fdefine_key (map, keys, function);
- return Qnil;
-}
-
-DEFUN ("global-unset-key", Fglobal_unset_key, Sglobal_unset_key,
- 1, 1, "kUnset key globally: ",
- "Remove global binding of KEY.\n\
-KEY is a string representing a sequence of keystrokes.")
- (keys)
- Lisp_Object keys;
-{
- return Fglobal_set_key (keys, Qnil);
-}
-
-DEFUN ("local-unset-key", Flocal_unset_key, Slocal_unset_key, 1, 1,
- "kUnset key locally: ",
- "Remove local binding of KEY.\n\
-KEY is a string representing a sequence of keystrokes.")
- (keys)
- Lisp_Object keys;
-{
- if (!NILP (current_buffer->keymap))
- Flocal_set_key (keys, Qnil);
- return Qnil;
-}
-
DEFUN ("define-prefix-command", Fdefine_prefix_command, Sdefine_prefix_command, 1, 2, 0,
"Define COMMAND as a prefix command. COMMAND should be a symbol.\n\
A new sparse keymap is stored as COMMAND's function definition and its value.\n\
If a second optional argument MAPVAR is given, the map is stored as\n\
its value instead of as COMMAND's value; but COMMAND is still defined\n\
as a function.")
- (name, mapvar)
- Lisp_Object name, mapvar;
+ (command, mapvar)
+ Lisp_Object command, mapvar;
{
Lisp_Object map;
map = Fmake_sparse_keymap (Qnil);
- Ffset (name, map);
+ Ffset (command, map);
if (!NILP (mapvar))
Fset (mapvar, map);
else
- Fset (name, map);
- return name;
+ Fset (command, map);
+ return command;
}
DEFUN ("use-global-map", Fuse_global_map, Suse_global_map, 1, 1, 0,
{
keymap = get_keymap (keymap);
current_global_map = keymap;
+
return Qnil;
}
\f
/* Help functions for describing and documenting keymaps. */
+/* This function cannot GC. */
+
DEFUN ("accessible-keymaps", Faccessible_keymaps, Saccessible_keymaps,
1, 2, 0,
"Find all keymaps accessible via prefix characters from KEYMAP.\n\
Returns a list of elements of the form (KEYS . MAP), where the sequence\n\
KEYS starting from KEYMAP gets you to MAP. These elements are ordered\n\
-so that the KEYS increase in length. The first element is (\"\" . KEYMAP).\n\
+so that the KEYS increase in length. The first element is ([] . KEYMAP).\n\
An optional argument PREFIX, if non-nil, should be a key sequence;\n\
then the value includes only maps for prefixes that start with PREFIX.")
- (startmap, prefix)
- Lisp_Object startmap, prefix;
+ (keymap, prefix)
+ Lisp_Object keymap, prefix;
{
Lisp_Object maps, good_maps, tail;
int prefixlen = 0;
+ /* no need for gcpro because we don't autoload any keymaps. */
+
if (!NILP (prefix))
prefixlen = XINT (Flength (prefix));
- maps = Fcons (Fcons (Fmake_vector (make_number (0), Qnil),
- get_keymap (startmap)),
- Qnil);
+ if (!NILP (prefix))
+ {
+ /* If a prefix was specified, start with the keymap (if any) for
+ that prefix, so we don't waste time considering other prefixes. */
+ Lisp_Object tem;
+ tem = Flookup_key (keymap, prefix, Qt);
+ /* Flookup_key may give us nil, or a number,
+ if the prefix is not defined in this particular map.
+ It might even give us a list that isn't a keymap. */
+ tem = get_keymap_1 (tem, 0, 0);
+ if (!NILP (tem))
+ maps = Fcons (Fcons (prefix, tem), Qnil);
+ else
+ return Qnil;
+ }
+ else
+ maps = Fcons (Fcons (Fmake_vector (make_number (0), Qnil),
+ get_keymap (keymap)),
+ Qnil);
/* For each map in the list maps,
look at any other maps it points to,
QUIT;
- if (XTYPE (elt) == Lisp_Vector)
+ if (VECTORP (elt))
{
register int i;
/* If the last key in thisseq is meta-prefix-char, and
this entry is a binding for an ascii keystroke,
turn it into a meta-ized keystroke. */
- if (is_metized && XTYPE (elt) == Lisp_Int)
+ if (is_metized && INTEGERP (elt))
{
tem = Fcopy_sequence (thisseq);
Faset (tem, last,
for (i = 0; i < prefixlen; i++)
{
Lisp_Object i1;
- XFASTINT (i1) = i;
+ XSETFASTINT (i1, i);
if (!EQ (Faref (thisseq, i1), Faref (prefix, i1)))
break;
}
Lisp_Object Qsingle_key_description, Qkey_description;
+/* This function cannot GC. */
+
DEFUN ("key-description", Fkey_description, Skey_description, 1, 1, 0,
"Return a pretty description of key-sequence KEYS.\n\
Control characters turn into \"C-foo\" sequences, meta into \"M-foo\"\n\
(keys)
Lisp_Object keys;
{
- if (XTYPE (keys) == Lisp_String)
+ int len;
+ int i;
+ Lisp_Object sep;
+ Lisp_Object *args;
+
+ if (STRINGP (keys))
{
Lisp_Object vector;
- int i;
vector = Fmake_vector (Flength (keys), Qnil);
for (i = 0; i < XSTRING (keys)->size; i++)
{
if (XSTRING (keys)->data[i] & 0x80)
- XFASTINT (XVECTOR (vector)->contents[i])
- = meta_modifier | (XSTRING (keys)->data[i] & ~0x80);
+ XSETFASTINT (XVECTOR (vector)->contents[i],
+ meta_modifier | (XSTRING (keys)->data[i] & ~0x80));
else
- XFASTINT (XVECTOR (vector)->contents[i])
- = XSTRING (keys)->data[i];
+ XSETFASTINT (XVECTOR (vector)->contents[i],
+ XSTRING (keys)->data[i]);
}
keys = vector;
}
- return Fmapconcat (Qsingle_key_description, keys, build_string (" "));
+ else if (!VECTORP (keys))
+ keys = wrong_type_argument (Qarrayp, keys);
+
+ /* In effect, this computes
+ (mapconcat 'single-key-description keys " ")
+ but we shouldn't use mapconcat because it can do GC. */
+
+ len = XVECTOR (keys)->size;
+ sep = build_string (" ");
+ /* This has one extra element at the end that we don't pass to Fconcat. */
+ args = (Lisp_Object *) alloca (len * 2 * sizeof (Lisp_Object));
+
+ for (i = 0; i < len; i++)
+ {
+ args[i * 2] = Fsingle_key_description (XVECTOR (keys)->contents[i]);
+ args[i * 2 + 1] = sep;
+ }
+
+ return Fconcat (len * 2 - 1, args);
}
char *
return p;
}
+/* This function cannot GC. */
+
DEFUN ("single-key-description", Fsingle_key_description, Ssingle_key_description, 1, 1, 0,
"Return a pretty description of command character KEY.\n\
Control characters turn into C-whatever, etc.")
key = EVENT_HEAD (key);
- switch (XTYPE (key))
+ if (INTEGERP (key)) /* Normal character */
{
- case Lisp_Int: /* Normal character */
*push_key_description (XUINT (key), tem) = 0;
return build_string (tem);
-
- case Lisp_Symbol: /* Function key or event-symbol */
- return Fsymbol_name (key);
-
- case Lisp_String:
- return key;
-
- default:
- error ("KEY must be an integer, cons, string, or symbol.");
}
+ else if (SYMBOLP (key)) /* Function key or event-symbol */
+ return Fsymbol_name (key);
+ else if (STRINGP (key)) /* Buffer names in the menubar. */
+ return Fcopy_sequence (key);
+ else
+ error ("KEY must be an integer, cons, symbol, or string");
}
char *
return p;
}
+/* This function cannot GC. */
+
DEFUN ("text-char-description", Ftext_char_description, Stext_char_description, 1, 1, 0,
- "Return a pretty description of file-character CHAR.\n\
+ "Return a pretty description of file-character CHARACTER.\n\
Control characters turn into \"^char\", etc.")
- (chr)
- Lisp_Object chr;
+ (character)
+ Lisp_Object character;
{
char tem[6];
- CHECK_NUMBER (chr, 0);
+ CHECK_NUMBER (character, 0);
- *push_text_char_description (XINT (chr) & 0377, tem) = 0;
+ *push_text_char_description (XINT (character) & 0377, tem) = 0;
return build_string (tem);
}
ascii_sequence_p (seq)
Lisp_Object seq;
{
- Lisp_Object i;
+ int i;
int len = XINT (Flength (seq));
- for (XFASTINT (i) = 0; XFASTINT (i) < len; XFASTINT (i)++)
+ for (i = 0; i < len; i++)
{
- Lisp_Object elt;
+ Lisp_Object ii, elt;
- elt = Faref (seq, i);
+ XSETFASTINT (ii, i);
+ elt = Faref (seq, ii);
- if (XTYPE (elt) != Lisp_Int
+ if (!INTEGERP (elt)
|| (XUINT (elt) & ~CHAR_META) >= 0x80)
return 0;
}
\f
/* where-is - finding a command in a set of keymaps. */
+/* This function can GC if Flookup_key autoloads any keymaps. */
+
DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 4, 0,
"Return list of keys that invoke DEFINITION.\n\
If KEYMAP is non-nil, search only KEYMAP and the global keymap.\n\
\n\
If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found,\n\
rather than a list of all possible key sequences.\n\
-If FIRSTONLY is t, avoid key sequences which use non-ASCII\n\
-keys and therefore may not be usable on ASCII terminals. If FIRSTONLY\n\
-is the symbol `non-ascii', return the first binding found, no matter\n\
-what its components.\n\
+If FIRSTONLY is the symbol `non-ascii', return the first binding found,\n\
+no matter what it is.\n\
+If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters,\n\
+and entirely reject menu bindings.\n\
\n\
If optional 4th arg NOINDIRECT is non-nil, don't follow indirections\n\
to other keymaps or slots. This makes it possible to search for an\n\
Lisp_Object definition, keymap;
Lisp_Object firstonly, noindirect;
{
- register Lisp_Object maps;
- Lisp_Object found;
+ Lisp_Object maps;
+ Lisp_Object found, sequence;
int keymap_specified = !NILP (keymap);
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+ /* 1 means ignore all menu bindings entirely. */
+ int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii);
if (! keymap_specified)
{
}
}
+ GCPRO5 (definition, keymap, maps, found, sequence);
found = Qnil;
+ sequence = Qnil;
for (; !NILP (maps); maps = Fcdr (maps))
{
advance map to the next element until i indicates that we
have finished off the vector. */
- Lisp_Object elt, key, binding, sequence;
+ Lisp_Object elt, key, binding;
elt = XCONS (map)->car;
QUIT;
/* Set key and binding to the current key and binding, and
advance map and i to the next binding. */
- if (XTYPE (elt) == Lisp_Vector)
+ if (VECTORP (elt))
{
/* In a vector, look at each element. */
binding = XVECTOR (elt)->contents[i];
- XFASTINT (key) = i;
+ XSETFASTINT (key, i);
i++;
/* If we've just finished scanning a vector, advance map
/* Search through indirections unless that's not wanted. */
if (NILP (noindirect))
- binding = get_keyelt (binding, 0);
+ {
+ if (nomenus)
+ {
+ while (1)
+ {
+ Lisp_Object map, tem;
+ /* If the contents are (KEYMAP . ELEMENT), go indirect. */
+ map = get_keymap_1 (Fcar_safe (definition), 0, 0);
+ tem = Fkeymapp (map);
+ if (!NILP (tem))
+ definition = access_keymap (map, Fcdr (definition), 0, 0);
+ else
+ break;
+ }
+ /* If the contents are (STRING ...), reject. */
+ if (CONSP (definition)
+ && STRINGP (XCONS (definition)->car))
+ continue;
+ }
+ else
+ binding = get_keyelt (binding, 0);
+ }
/* End this iteration if this element does not match
the target. */
- if (XTYPE (definition) == Lisp_Cons)
+ if (CONSP (definition))
{
Lisp_Object tem;
tem = Fequal (binding, definition);
/* We have found a match.
Construct the key sequence where we found it. */
- if (XTYPE (key) == Lisp_Int && last_is_meta)
+ if (INTEGERP (key) && last_is_meta)
{
sequence = Fcopy_sequence (this);
Faset (sequence, last, make_number (XINT (key) | meta_modifier));
if (keymap_specified)
{
binding = Flookup_key (keymap, sequence, Qnil);
- if (!NILP (binding) && XTYPE (binding) != Lisp_Int)
+ if (!NILP (binding) && !INTEGERP (binding))
{
- if (XTYPE (definition) == Lisp_Cons)
+ if (CONSP (definition))
{
Lisp_Object tem;
tem = Fequal (binding, definition);
nil, then we should return the first ascii-only binding
we find. */
if (EQ (firstonly, Qnon_ascii))
- return sequence;
+ RETURN_UNGCPRO (sequence);
else if (! NILP (firstonly) && ascii_sequence_p (sequence))
- return sequence;
+ RETURN_UNGCPRO (sequence);
}
}
+ UNGCPRO;
+
found = Fnreverse (found);
/* firstonly may have been t, but we may have gone all the way through
Lisp_Object prefix;
{
register Lisp_Object thisbuf;
- XSET (thisbuf, Lisp_Buffer, current_buffer);
+ XSETBUFFER (thisbuf, current_buffer);
internal_with_output_to_temp_buffer ("*Help*",
describe_buffer_bindings,
Fcons (thisbuf, prefix));
Lisp_Object arg;
{
Lisp_Object descbuf, prefix, shadow;
- register Lisp_Object start1, start2;
+ register Lisp_Object start1;
+ struct gcpro gcpro1;
char *alternate_heading
= "\
descbuf = XCONS (arg)->car;
prefix = XCONS (arg)->cdr;
shadow = Qnil;
+ GCPRO1 (shadow);
Fset_buffer (Vstandard_output);
/* Report on alternates for keys. */
- if (XTYPE (Vkeyboard_translate_table) == Lisp_String)
+ if (STRINGP (Vkeyboard_translate_table) && !NILP (prefix))
{
int c;
unsigned char *translate = XSTRING (Vkeyboard_translate_table)->data;
insert ("\n", 1);
}
+ if (!NILP (Vkey_translation_map))
+ describe_map_tree (Vkey_translation_map, 0, Qnil, prefix,
+ "Key translations", 0, 1, 0);
+
{
int i, nmaps;
Lisp_Object *modes, *maps;
/* Temporarily switch to descbuf, so that we can get that buffer's
minor modes correctly. */
Fset_buffer (descbuf);
- if (!NILP (Voverriding_local_map))
+
+ if (!NILP (current_kboard->Voverriding_terminal_local_map)
+ || !NILP (Voverriding_local_map))
nmaps = 0;
else
nmaps = current_minor_maps (&modes, &maps);
because it takes care of other features when doing so. */
char *title, *p;
- if (XTYPE (modes[i]) == Lisp_Symbol)
- {
- p = title = (char *) alloca (40 + XSYMBOL (modes[i])->name->size);
- *p++ = '`';
- bcopy (XSYMBOL (modes[i])->name->data, p,
- XSYMBOL (modes[i])->name->size);
- p += XSYMBOL (modes[i])->name->size;
- *p++ = '\'';
- }
- else
- {
- p = title = (char *) alloca (40 + 20);
- bcopy ("Strangely Named", p, sizeof ("Strangely Named") - 1);
- p += sizeof ("Strangely Named") - 1;
- }
+ if (!SYMBOLP (modes[i]))
+ abort();
+
+ p = title = (char *) alloca (40 + XSYMBOL (modes[i])->name->size);
+ *p++ = '`';
+ bcopy (XSYMBOL (modes[i])->name->data, p,
+ XSYMBOL (modes[i])->name->size);
+ p += XSYMBOL (modes[i])->name->size;
+ *p++ = '\'';
bcopy (" Minor Mode Bindings", p, sizeof (" Minor Mode Bindings") - 1);
p += sizeof (" Minor Mode Bindings") - 1;
*p = 0;
- describe_map_tree (maps[i], 0, shadow, prefix, title, 0);
+ describe_map_tree (maps[i], 0, shadow, prefix, title, 0, 0, 0);
shadow = Fcons (maps[i], shadow);
}
}
/* Print the (major mode) local map. */
- if (!NILP (Voverriding_local_map))
+ if (!NILP (current_kboard->Voverriding_terminal_local_map))
+ start1 = current_kboard->Voverriding_terminal_local_map;
+ else if (!NILP (Voverriding_local_map))
start1 = Voverriding_local_map;
else
start1 = XBUFFER (descbuf)->keymap;
if (!NILP (start1))
{
describe_map_tree (start1, 0, shadow, prefix,
- "Major Mode Bindings", 0);
+ "Major Mode Bindings", 0, 0, 0);
shadow = Fcons (start1, shadow);
}
describe_map_tree (current_global_map, 0, shadow, prefix,
- "Global Bindings", 0);
+ "Global Bindings", 0, 0, 1);
+
+ /* Print the function-key-map translations under this prefix. */
+ if (!NILP (Vfunction_key_map))
+ describe_map_tree (Vfunction_key_map, 0, Qnil, prefix,
+ "Function key map translations", 0, 1, 0);
+ call0 (intern ("help-mode"));
Fset_buffer (descbuf);
+ UNGCPRO;
return Qnil;
}
-/* Insert a desription of the key bindings in STARTMAP,
+/* Insert a description of the key bindings in STARTMAP,
followed by those of all maps reachable through STARTMAP.
If PARTIAL is nonzero, omit certain "uninteresting" commands
(such as `undefined').
PREFIX, if non-nil, says mention only keys that start with PREFIX.
TITLE, if not 0, is a string to insert at the beginning.
TITLE should not end with a colon or a newline; we supply that.
- If NOMENU is not 0, then omit menu-bar commands. */
+ If NOMENU is not 0, then omit menu-bar commands.
+
+ If TRANSL is nonzero, the definitions are actually key translations
+ so print strings and vectors differently.
+
+ If ALWAYS_TITLE is nonzero, print the title even if there are no maps
+ to look through. */
void
-describe_map_tree (startmap, partial, shadow, prefix, title, nomenu)
+describe_map_tree (startmap, partial, shadow, prefix, title, nomenu, transl,
+ always_title)
Lisp_Object startmap, shadow, prefix;
int partial;
char *title;
int nomenu;
+ int transl;
+ int always_title;
{
- Lisp_Object maps, seen;
- struct gcpro gcpro1, gcpro2;
+ Lisp_Object maps, seen, sub_shadows;
+ struct gcpro gcpro1, gcpro2, gcpro3;
int something = 0;
char *key_heading
= "\
maps = Faccessible_keymaps (startmap, prefix);
seen = Qnil;
- GCPRO2 (maps, seen);
+ sub_shadows = Qnil;
+ GCPRO3 (maps, seen, sub_shadows);
if (nomenu)
{
}
}
- if (!NILP (maps))
+ if (!NILP (maps) || always_title)
{
if (title)
{
for (; !NILP (maps); maps = Fcdr (maps))
{
- register Lisp_Object elt, prefix, sub_shadows, tail;
+ register Lisp_Object elt, prefix, tail;
elt = Fcar (maps);
prefix = Fcar (elt);
/* If the sequence by which we reach this keymap is zero-length,
then the shadow map for this keymap is just SHADOW. */
- if ((XTYPE (prefix) == Lisp_String
- && XSTRING (prefix)->size == 0)
- || (XTYPE (prefix) == Lisp_Vector
- && XVECTOR (prefix)->size == 0))
+ if ((STRINGP (prefix) && XSTRING (prefix)->size == 0)
+ || (VECTORP (prefix) && XVECTOR (prefix)->size == 0))
;
/* If the sequence by which we reach this keymap actually has
some elements, then the sequence's definition in SHADOW is
else
{
shmap = Flookup_key (shmap, Fcar (elt), Qt);
- if (XTYPE (shmap) == Lisp_Int)
+ if (INTEGERP (shmap))
shmap = Qnil;
}
sub_shadows = Fcons (shmap, sub_shadows);
}
- describe_map (Fcdr (elt), Fcar (elt), describe_command,
- partial, sub_shadows, &seen);
+ describe_map (Fcdr (elt), Fcar (elt),
+ transl ? describe_translation : describe_command,
+ partial, sub_shadows, &seen, nomenu);
skip: ;
}
UNGCPRO;
}
+static int previous_description_column;
+
static void
describe_command (definition)
Lisp_Object definition;
{
register Lisp_Object tem1;
+ int column = current_column ();
+ int description_column;
- Findent_to (make_number (16), make_number (1));
+ /* If column 16 is no good, go to col 32;
+ but don't push beyond that--go to next line instead. */
+ if (column > 30)
+ {
+ insert_char ('\n');
+ description_column = 32;
+ }
+ else if (column > 14 || (column > 10 && previous_description_column == 32))
+ description_column = 32;
+ else
+ description_column = 16;
- if (XTYPE (definition) == Lisp_Symbol)
+ Findent_to (make_number (description_column), make_number (1));
+ previous_description_column = description_column;
+
+ if (SYMBOLP (definition))
{
- XSET (tem1, Lisp_String, XSYMBOL (definition)->name);
+ XSETSTRING (tem1, XSYMBOL (definition)->name);
insert1 (tem1);
insert_string ("\n");
}
- else if (STRINGP (definition))
+ else if (STRINGP (definition) || VECTORP (definition))
insert_string ("Keyboard Macro\n");
else
{
}
}
+static void
+describe_translation (definition)
+ Lisp_Object definition;
+{
+ register Lisp_Object tem1;
+
+ Findent_to (make_number (16), make_number (1));
+
+ if (SYMBOLP (definition))
+ {
+ XSETSTRING (tem1, XSYMBOL (definition)->name);
+ insert1 (tem1);
+ insert_string ("\n");
+ }
+ else if (STRINGP (definition) || VECTORP (definition))
+ {
+ insert1 (Fkey_description (definition));
+ insert_string ("\n");
+ }
+ else
+ {
+ tem1 = Fkeymapp (definition);
+ if (!NILP (tem1))
+ insert_string ("Prefix Command\n");
+ else
+ insert_string ("??\n");
+ }
+}
+
/* Like Flookup_key, but uses a list of keymaps SHADOW instead of a single map.
Returns the first non-nil binding found in any of those maps. */
/* Describe the contents of map MAP, assuming that this map itself is
reached by the sequence of prefix keys KEYS (a string or vector).
- PARTIAL, SHADOW are as in `describe_map_tree' above. */
+ PARTIAL, SHADOW, NOMENU are as in `describe_map_tree' above. */
static void
-describe_map (map, keys, elt_describer, partial, shadow, seen)
+describe_map (map, keys, elt_describer, partial, shadow, seen, nomenu)
register Lisp_Object map;
Lisp_Object keys;
int (*elt_describer) ();
int partial;
Lisp_Object shadow;
Lisp_Object *seen;
+ int nomenu;
{
Lisp_Object elt_prefix;
Lisp_Object tail, definition, event;
{
QUIT;
- if (XTYPE (XCONS (tail)->car) == Lisp_Vector)
+ if (VECTORP (XCONS (tail)->car))
describe_vector (XCONS (tail)->car,
- elt_prefix, elt_describer, partial, shadow);
+ elt_prefix, elt_describer, partial, shadow, map);
else if (CONSP (XCONS (tail)->car))
{
event = XCONS (XCONS (tail)->car)->car;
+
+ /* Ignore bindings whose "keys" are not really valid events.
+ (We get these in the frames and buffers menu.) */
+ if (! (SYMBOLP (event) || INTEGERP (event)))
+ continue;
+
+ if (nomenu && EQ (event, Qmenu_bar))
+ continue;
+
definition = get_keyelt (XCONS (XCONS (tail)->car)->cdr, 0);
/* Don't show undefined commands or suppressed commands. */
if (NILP (definition)) continue;
- if (XTYPE (definition) == Lisp_Symbol && partial)
+ if (SYMBOLP (definition) && partial)
{
tem = Fget (definition, suppress);
if (!NILP (tem))
if (first)
{
+ previous_description_column = 0;
insert ("\n", 1);
first = 0;
}
using an inherited keymap. So skip anything we've already
encountered. */
tem = Fassq (tail, *seen);
- if (CONSP (tem) && Fequal (XCONS (tem)->car, keys))
+ if (CONSP (tem) && !NILP (Fequal (XCONS (tem)->car, keys)))
break;
*seen = Fcons (Fcons (tail, keys), *seen);
}
int count = specpdl_ptr - specpdl;
specbind (Qstandard_output, Fcurrent_buffer ());
- CHECK_VECTOR (vector, 0);
- describe_vector (vector, Qnil, describe_vector_princ, 0, Qnil);
+ CHECK_VECTOR_OR_CHAR_TABLE (vector, 0);
+ describe_vector (vector, Qnil, describe_vector_princ, 0, Qnil, Qnil);
return unbind_to (count, Qnil);
}
-describe_vector (vector, elt_prefix, elt_describer, partial, shadow)
+/* Insert in the current buffer a description of the contents of VECTOR.
+ We call ELT_DESCRIBER to insert the description of one value found
+ in VECTOR.
+
+ ELT_PREFIX describes what "comes before" the keys or indices defined
+ by this vector.
+
+ If the vector is in a keymap, ELT_PREFIX is a prefix key which
+ leads to this keymap.
+
+ If the vector is a chartable, ELT_PREFIX is the vector
+ of bytes that lead to the character set or portion of a character
+ set described by this chartable.
+
+ If PARTIAL is nonzero, it means do not mention suppressed commands
+ (that assumes the vector is in a keymap).
+
+ SHADOW is a list of keymaps that shadow this map.
+ If it is non-nil, then we look up the key in those maps
+ and we don't mention it now if it is defined by any of them.
+
+ ENTIRE_MAP is the keymap in which this vector appears.
+ If the definition in effect in the whole map does not match
+ the one in this vector, we ignore this one. */
+
+describe_vector (vector, elt_prefix, elt_describer,
+ partial, shadow, entire_map)
register Lisp_Object vector;
Lisp_Object elt_prefix;
int (*elt_describer) ();
int partial;
Lisp_Object shadow;
+ Lisp_Object entire_map;
{
Lisp_Object this;
Lisp_Object dummy;
- Lisp_Object tem1, tem2;
+ Lisp_Object definition;
+ Lisp_Object tem2;
register int i;
Lisp_Object suppress;
Lisp_Object kludge;
+ Lisp_Object chartable_kludge;
int first = 1;
- struct gcpro gcpro1, gcpro2, gcpro3;
+ int size;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
- tem1 = Qnil;
+ definition = Qnil;
+ chartable_kludge = Qnil;
/* This vector gets used to present single keys to Flookup_key. Since
that is done once per vector element, we don't want to cons up a
fresh vector every time. */
kludge = Fmake_vector (make_number (1), Qnil);
- GCPRO3 (elt_prefix, tem1, kludge);
+ GCPRO4 (elt_prefix, definition, kludge, chartable_kludge);
if (partial)
suppress = intern ("suppress-keymap");
- for (i = 0; i < XVECTOR (vector)->size; i++)
+ /* This does the right thing for char-tables as well as ordinary vectors. */
+ size = XFASTINT (Flength (vector));
+
+ for (i = 0; i < size; i++)
{
QUIT;
- tem1 = get_keyelt (XVECTOR (vector)->contents[i], 0);
+ definition = get_keyelt (XVECTOR (vector)->contents[i], 0);
- if (NILP (tem1)) continue;
+ if (NILP (definition)) continue;
/* Don't mention suppressed commands. */
- if (XTYPE (tem1) == Lisp_Symbol && partial)
+ if (SYMBOLP (definition) && partial)
{
- this = Fget (tem1, suppress);
+ this = Fget (definition, suppress);
if (!NILP (this))
continue;
}
- /* If this command in this map is shadowed by some other map,
- ignore it. */
+ /* If this binding is shadowed by some other map, ignore it. */
if (!NILP (shadow))
{
Lisp_Object tem;
if (!NILP (tem)) continue;
}
+ /* Ignore this definition if it is shadowed by an earlier
+ one in the same keymap. */
+ if (!NILP (entire_map))
+ {
+ Lisp_Object tem;
+
+ XVECTOR (kludge)->contents[0] = make_number (i);
+ tem = Flookup_key (entire_map, kludge, Qt);
+
+ if (! EQ (tem, definition))
+ continue;
+ }
+
+ /* If we find a char-table within a char-table,
+ scan it recursively; it defines the details for
+ a character set or a portion of a character set. */
+ if (CHAR_TABLE_P (vector) && CHAR_TABLE_P (definition))
+ {
+ int outer_level
+ = !NILP (elt_prefix) ? XVECTOR (elt_prefix)->size : 0;
+ if (NILP (chartable_kludge))
+ {
+ chartable_kludge
+ = Fmake_vector (make_number (outer_level + 1), Qnil);
+ if (outer_level != 0)
+ bcopy (XVECTOR (elt_prefix)->contents,
+ XVECTOR (chartable_kludge)->contents,
+ outer_level * sizeof (Lisp_Object));
+ }
+ XVECTOR (chartable_kludge)->contents[outer_level]
+ = make_number (i);
+ describe_vector (definition, chartable_kludge, elt_describer,
+ partial, shadow, entire_map);
+ continue;
+ }
+
if (first)
{
insert ("\n", 1);
first = 0;
}
- /* Output the prefix that applies to every entry in this map. */
- if (!NILP (elt_prefix))
- insert1 (elt_prefix);
+ if (CHAR_TABLE_P (vector))
+ {
+ if (!NILP (elt_prefix))
+ {
+ /* Must combine elt_prefix with i to produce a character
+ code, then insert that character's description. */
+ }
+ else
+ {
+ /* Get the string to describe the character I, and print it. */
+ XSETFASTINT (dummy, i);
- /* Get the string to describe the character I, and print it. */
- XFASTINT (dummy) = i;
+ /* THIS gets the string to describe the character DUMMY. */
+ this = Fsingle_key_description (dummy);
+ insert1 (this);
+ }
+ }
+ else
+ {
+ /* Output the prefix that applies to every entry in this map. */
+ if (!NILP (elt_prefix))
+ insert1 (elt_prefix);
- /* THIS gets the string to describe the character DUMMY. */
- this = Fsingle_key_description (dummy);
- insert1 (this);
+ /* Get the string to describe the character I, and print it. */
+ XSETFASTINT (dummy, i);
+
+ /* THIS gets the string to describe the character DUMMY. */
+ this = Fsingle_key_description (dummy);
+ insert1 (this);
+ }
/* Find all consecutive characters that have the same definition. */
while (i + 1 < XVECTOR (vector)->size
&& (tem2 = get_keyelt (XVECTOR (vector)->contents[i+1], 0),
- EQ (tem2, tem1)))
+ EQ (tem2, definition)))
i++;
/* If we have a range of more than one character,
if (i != XINT (dummy))
{
insert (" .. ", 4);
- if (!NILP (elt_prefix))
- insert1 (elt_prefix);
+ if (CHAR_TABLE_P (vector))
+ {
+ if (!NILP (elt_prefix))
+ {
+ /* Must combine elt_prefix with i to produce a character
+ code, then insert that character's description. */
+ }
+ else
+ {
+ XSETFASTINT (dummy, i);
+
+ this = Fsingle_key_description (dummy);
+ insert1 (this);
+ }
+ }
+ else
+ {
+ if (!NILP (elt_prefix))
+ insert1 (elt_prefix);
- XFASTINT (dummy) = i;
- insert1 (Fsingle_key_description (dummy));
+ XSETFASTINT (dummy, i);
+ insert1 (Fsingle_key_description (dummy));
+ }
}
/* Print a description of the definition of this character.
elt_describer will take care of spacing out far enough
for alignment purposes. */
- (*elt_describer) (tem1);
+ (*elt_describer) (definition);
}
UNGCPRO;
DEFUN ("apropos-internal", Fapropos_internal, Sapropos_internal, 1, 2, 0,
"Show all symbols whose names contain match for REGEXP.\n\
-If optional 2nd arg PRED is non-nil, (funcall PRED SYM) is done\n\
+If optional 2nd arg PREDICATE is non-nil, (funcall PREDICATE SYMBOL) is done\n\
for each symbol and a symbol is mentioned only if that returns non-nil.\n\
Return list of symbols found.")
- (string, pred)
- Lisp_Object string, pred;
+ (regexp, predicate)
+ Lisp_Object regexp, predicate;
{
struct gcpro gcpro1, gcpro2;
- CHECK_STRING (string, 0);
- apropos_predicate = pred;
+ CHECK_STRING (regexp, 0);
+ apropos_predicate = predicate;
GCPRO2 (apropos_predicate, apropos_accumulate);
apropos_accumulate = Qnil;
- map_obarray (Vobarray, apropos_accum, string);
+ map_obarray (Vobarray, apropos_accum, regexp);
apropos_accumulate = Fsort (apropos_accumulate, Qstring_lessp);
UNGCPRO;
return apropos_accumulate;
Fcons (Fmake_vector (make_number (0400), Qnil), Qnil));
Fset (intern ("global-map"), global_map);
+ current_global_map = global_map;
+ staticpro (&global_map);
+ staticpro (¤t_global_map);
+
meta_map = Fmake_keymap (Qnil);
Fset (intern ("esc-map"), meta_map);
Ffset (intern ("ESC-prefix"), meta_map);
Fset (intern ("ctl-x-map"), control_x_map);
Ffset (intern ("Control-X-prefix"), control_x_map);
+ DEFVAR_LISP ("define-key-rebound-commands", &Vdefine_key_rebound_commands,
+ "List of commands given new key bindings recently.\n\
+This is used for internal purposes during Emacs startup;\n\
+don't alter it yourself.");
+ Vdefine_key_rebound_commands = Qt;
+
DEFVAR_LISP ("minibuffer-local-map", &Vminibuffer_local_map,
"Default keymap to use when reading from the minibuffer.");
Vminibuffer_local_map = Fmake_sparse_keymap (Qnil);
"Local keymap for minibuffer input with completion, for exact match.");
Vminibuffer_local_must_match_map = Fmake_sparse_keymap (Qnil);
- current_global_map = global_map;
-
DEFVAR_LISP ("minor-mode-map-alist", &Vminor_mode_map_alist,
"Alist of keymaps to use for minor modes.\n\
Each element looks like (VARIABLE . KEYMAP); KEYMAP is used to read\n\
This allows Emacs to recognize function keys sent from ASCII\n\
terminals at any point in a key sequence.\n\
\n\
-The read-key-sequence function replaces subsequences bound by\n\
-function-key-map with their bindings. When the current local and global\n\
+The `read-key-sequence' function replaces any subsequence bound by\n\
+`function-key-map' with its binding. More precisely, when the active\n\
keymaps have no binding for the current key sequence but\n\
-function-key-map binds a suffix of the sequence to a vector or string,\n\
-read-key-sequence replaces the matching suffix with its binding, and\n\
+`function-key-map' binds a suffix of the sequence to a vector or string,\n\
+`read-key-sequence' replaces the matching suffix with its binding, and\n\
continues with the new sequence.\n\
\n\
-For example, suppose function-key-map binds `ESC O P' to [f1].\n\
-Typing `ESC O P' to read-key-sequence would return [f1]. Typing\n\
+The events that come from bindings in `function-key-map' are not\n\
+themselves looked up in `function-key-map'.\n\
+\n\
+For example, suppose `function-key-map' binds `ESC O P' to [f1].\n\
+Typing `ESC O P' to `read-key-sequence' would return [f1]. Typing\n\
`C-x ESC O P' would return [?\\C-x f1]. If [f1] were a prefix\n\
key, typing `ESC O P x' would return [f1 x].");
Vfunction_key_map = Fmake_sparse_keymap (Qnil);
+ DEFVAR_LISP ("key-translation-map", &Vkey_translation_map,
+ "Keymap of key translations that can override keymaps.\n\
+This keymap works like `function-key-map', but comes after that,\n\
+and applies even for keys that have ordinary bindings.");
+ Vkey_translation_map = Qnil;
+
Qsingle_key_description = intern ("single-key-description");
staticpro (&Qsingle_key_description);
staticpro (&Qnon_ascii);
defsubr (&Skeymapp);
+ defsubr (&Skeymap_parent);
+ defsubr (&Sset_keymap_parent);
defsubr (&Smake_keymap);
defsubr (&Smake_sparse_keymap);
defsubr (&Scopy_keymap);
defsubr (&Slocal_key_binding);
defsubr (&Sglobal_key_binding);
defsubr (&Sminor_mode_key_binding);
- defsubr (&Sglobal_set_key);
- defsubr (&Slocal_set_key);
defsubr (&Sdefine_key);
defsubr (&Slookup_key);
- defsubr (&Sglobal_unset_key);
- defsubr (&Slocal_unset_key);
defsubr (&Sdefine_prefix_command);
defsubr (&Suse_global_map);
defsubr (&Suse_local_map);