]> code.delx.au - gnu-emacs/blobdiff - src/keymap.c
*** empty log message ***
[gnu-emacs] / src / keymap.c
index 6bf50cb18f6e31bc7025fc968c0acd057defd756..64f849f784536d8f1f3e7b9f0d21b5c7d798db4f 100644 (file)
@@ -412,7 +412,8 @@ PARENT should be nil or another keymap.  */)
        {
          Lisp_Object indices[3];
 
-         map_char_table (fix_submap_inheritance, Qnil, XCAR (list),
+         map_char_table (fix_submap_inheritance, Qnil,
+                         XCAR (list), XCAR (list),
                          keymap, 0, indices);
        }
     }
@@ -640,6 +641,103 @@ access_keymap (map, idx, t_ok, noinherit, autoload)
   }
 }
 
+static void
+map_keymap_item (fun, args, key, val, data)
+     map_keymap_function_t fun;
+     Lisp_Object args, key, val;
+     void *data;
+{
+  /* We should maybe try to detect bindings shadowed by previous
+     ones and things like that.  */
+  if (EQ (val, Qt))
+    val = Qnil;
+  (*fun) (key, val, args, data);
+}
+
+static void
+map_keymap_char_table_item (args, key, val)
+     Lisp_Object args, key, val;
+{
+  if (!NILP (val))
+    {
+      map_keymap_function_t fun = XSAVE_VALUE (XCAR (args))->pointer;
+      args = XCDR (args);
+      map_keymap_item (fun, XCDR (args), key, val,
+                      XSAVE_VALUE (XCAR (args))->pointer);
+    }
+}
+
+/* Call FUN for every binding in MAP.
+   FUN is called with 4 arguments: FUN (KEY, BINDING, ARGS, DATA).
+   AUTOLOAD if non-zero means that we can autoload keymaps if necessary.  */
+void
+map_keymap (map, fun, args, data, autoload)
+     map_keymap_function_t fun;
+     Lisp_Object map, args;
+     void *data;
+     int autoload;
+{
+  struct gcpro gcpro1, gcpro2, gcpro3;
+  Lisp_Object tail;
+
+  GCPRO3 (map, args, tail);
+  map = get_keymap (map, 1, autoload);
+  for (tail = (CONSP (map) && EQ (Qkeymap, XCAR (map))) ? XCDR (map) : map;
+       CONSP (tail) || (tail = get_keymap (tail, 0, autoload), CONSP (tail));
+       tail = XCDR (tail))
+    {
+      Lisp_Object binding = XCAR (tail);
+      
+      if (CONSP (binding))
+       map_keymap_item (fun, args, XCAR (binding), XCDR (binding), data);
+      else if (VECTORP (binding))
+       {
+         /* Loop over the char values represented in the vector.  */
+         int len = ASIZE (binding);
+         int c;
+         abort();
+         for (c = 0; c < len; c++)
+           {
+             Lisp_Object character;
+             XSETFASTINT (character, c);
+             map_keymap_item (fun, args, character, AREF (binding, c), data);
+           }
+       }
+      else if (CHAR_TABLE_P (binding))
+       {
+         Lisp_Object indices[3];
+         map_char_table (map_keymap_char_table_item, Qnil, binding, binding,
+                         Fcons (make_save_value (fun, 0),
+                                Fcons (make_save_value (data, 0),
+                                       args)),
+                         0, indices);
+       }
+    }
+  UNGCPRO;
+}
+
+static void
+map_keymap_call (key, val, fun, dummy)
+     Lisp_Object key, val, fun;
+     void *dummy;
+{
+  call2 (fun, key, val);
+}
+
+DEFUN ("map-keymap", Fmap_keymap, Smap_keymap, 2, 2, 0,
+       doc: /* Call FUNCTION for every binding in KEYMAP.
+FUNCTION is called with two arguments: the event and its binding.  */)
+     (function, keymap)
+     Lisp_Object function, keymap;
+{
+  if (INTEGERP (function))
+    /* We have to stop integers early since map_keymap gives them special
+       significance.  */
+    Fsignal (Qinvalid_function, Fcons (function, Qnil));
+  map_keymap (keymap, map_keymap_call, function, NULL, 1);
+  return Qnil;
+}
+
 /* Given OBJECT which was found in a slot in a keymap,
    trace indirect definitions to get the actual definition of that slot.
    An indirect definition is a list of the form
@@ -914,7 +1012,7 @@ copy_keymap_item (elt)
   return res;
 }
 
-void
+static void
 copy_keymap_1 (chartable, idx, elt)
      Lisp_Object chartable, idx, elt;
 {
@@ -943,7 +1041,7 @@ is not copied.  */)
        {
          Lisp_Object indices[3];
          elt = Fcopy_sequence (elt);
-         map_char_table (copy_keymap_1, Qnil, elt, elt, 0, indices);
+         map_char_table (copy_keymap_1, Qnil, elt, elt, elt, 0, indices);
        }
       else if (VECTORP (elt))
        {
@@ -967,14 +1065,14 @@ is not copied.  */)
 /* GC is possible in this function if it autoloads a keymap.  */
 
 DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0,
-       doc: /* Args KEYMAP, KEY, DEF.  Define key sequence KEY, in KEYMAP, as DEF.
+       doc: /* In KEYMAP, define key sequence KEY as DEF.
 KEYMAP is a keymap.
 
 KEY is a string or a vector of symbols and characters meaning a
 sequence of keystrokes and events.  Non-ASCII characters with codes
 above 127 (such as ISO Latin-1) can be included if you use a vector.
 Using [t] for KEY creates a default definition, which applies to any
-event type that has no other definition in thus keymap.
+event type that has no other definition in this keymap.
 
 DEF is anything that can be a key's definition:
  nil (means key is undefined in this keymap),
@@ -988,8 +1086,9 @@ DEF is anything that can be a key's definition:
     (DEFN should be a valid definition in its own right),
  or a cons (KEYMAP . CHAR), meaning use definition of CHAR in map KEYMAP.
 
-If KEYMAP is a sparse keymap, the pair binding KEY to DEF is added at
-the front of KEYMAP.  */)
+If KEYMAP is a sparse keymap with a binding for KEY, the existing
+binding is altered.  If there is no binding for KEY, the new pair
+binding KEY to DEF is added at the front of KEYMAP.  */)
      (keymap, key, def)
      Lisp_Object keymap;
      Lisp_Object key;
@@ -1658,43 +1757,54 @@ accessible_keymaps_1 (key, cmd, maps, tail, thisseq, is_metized)
 {
   Lisp_Object tem;
 
-  cmd = get_keyelt (cmd, 0);
+  cmd = get_keymap (get_keyelt (cmd, 0), 0, 0);
   if (NILP (cmd))
     return;
 
-  tem = get_keymap (cmd, 0, 0);
-  if (CONSP (tem))
+  /* Look for and break cycles.  */
+  while (!NILP (tem = Frassq (cmd, maps)))
     {
-      cmd = tem;
-      /* Ignore keymaps that are already added to maps.  */
-      tem = Frassq (cmd, maps);
-      if (NILP (tem))
-       {
-         /* 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 since we're processing a
-            keymap table.  */
-         if (is_metized)
-           {
-             int meta_bit = meta_modifier;
-             Lisp_Object last = make_number (XINT (Flength (thisseq)) - 1);
-             tem = Fcopy_sequence (thisseq);
-
-             Faset (tem, last, make_number (XINT (key) | meta_bit));
-
-             /* This new sequence is the same length as
-                thisseq, so stick it in the list right
-                after this one.  */
-             XSETCDR (tail,
-                      Fcons (Fcons (tem, cmd), XCDR (tail)));
-           }
-         else
-           {
-             tem = append_key (thisseq, key);
-             nconc2 (tail, Fcons (Fcons (tem, cmd), Qnil));
-           }
+      Lisp_Object prefix = XCAR (tem);
+      int lim = XINT (Flength (XCAR (tem)));
+      if (lim <= XINT (Flength (thisseq)))
+       { /* This keymap was already seen with a smaller prefix.  */
+         int i = 0;
+         while (i < lim && EQ (Faref (prefix, make_number (i)),
+                               Faref (thisseq, make_number (i))))
+           i++;
+         if (i >= lim)
+           /* `prefix' is a prefix of `thisseq' => there's a cycle.  */
+           return;
        }
+      /* This occurrence of `cmd' in `maps' does not correspond to a cycle,
+        but maybe `cmd' occurs again further down in `maps', so keep
+        looking.  */
+      maps = XCDR (Fmemq (tem, maps));
+    }
+
+  /* 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 since we're processing a
+     keymap table.  */
+  if (is_metized)
+    {
+      int meta_bit = meta_modifier;
+      Lisp_Object last = make_number (XINT (Flength (thisseq)) - 1);
+      tem = Fcopy_sequence (thisseq);
+      
+      Faset (tem, last, make_number (XINT (key) | meta_bit));
+      
+      /* This new sequence is the same length as
+        thisseq, so stick it in the list right
+        after this one.  */
+      XSETCDR (tail,
+              Fcons (Fcons (tem, cmd), XCDR (tail)));
+    }
+  else
+    {
+      tem = append_key (thisseq, key);
+      nconc2 (tail, Fcons (Fcons (tem, cmd), Qnil));
     }
 }
 
@@ -1722,7 +1832,7 @@ then the value includes only maps for prefixes that start with PREFIX.  */)
      (keymap, prefix)
      Lisp_Object keymap, prefix;
 {
-  Lisp_Object maps, good_maps, tail;
+  Lisp_Object maps, tail;
   int prefixlen = 0;
 
   /* no need for gcpro because we don't autoload any keymaps.  */
@@ -1805,7 +1915,7 @@ then the value includes only maps for prefixes that start with PREFIX.  */)
            {
              Lisp_Object indices[3];
 
-             map_char_table (accessible_keymaps_char_table, Qnil,
+             map_char_table (accessible_keymaps_char_table, Qnil, elt,
                              elt, Fcons (Fcons (maps, make_number (is_metized)),
                                          Fcons (tail, thisseq)),
                              0, indices);
@@ -1828,35 +1938,7 @@ then the value includes only maps for prefixes that start with PREFIX.  */)
        }
     }
 
-  if (NILP (prefix))
-    return maps;
-
-  /* Now find just the maps whose access prefixes start with PREFIX.  */
-
-  good_maps = Qnil;
-  for (; CONSP (maps); maps = XCDR (maps))
-    {
-      Lisp_Object elt, thisseq;
-      elt = XCAR (maps);
-      thisseq = XCAR (elt);
-      /* The access prefix must be at least as long as PREFIX,
-        and the first elements must match those of PREFIX.  */
-      if (XINT (Flength (thisseq)) >= prefixlen)
-       {
-         int i;
-         for (i = 0; i < prefixlen; i++)
-           {
-             Lisp_Object i1;
-             XSETFASTINT (i1, i);
-             if (!EQ (Faref (thisseq, i1), Faref (prefix, i1)))
-               break;
-           }
-         if (i == prefixlen)
-           good_maps = Fcons (elt, good_maps);
-       }
-    }
-
-  return Fnreverse (good_maps);
+  return maps;
 }
 \f
 Lisp_Object Qsingle_key_description, Qkey_description;
@@ -2239,6 +2321,8 @@ shadow_lookup (shadow, key, flag)
   return Qnil;
 }
 
+static Lisp_Object Vmenu_events;
+
 /* This function can GC if Flookup_key autoloads any keymaps.  */
 
 static Lisp_Object
@@ -2277,7 +2361,7 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
   for (; !NILP (maps); maps = Fcdr (maps))
     {
       /* Key sequence to reach map, and the map that it reaches */
-      register Lisp_Object this, map;
+      register Lisp_Object this, map, tem;
 
       /* In order to fold [META-PREFIX-CHAR CHAR] sequences into
         [M-CHAR] sequences, check if last character of the sequence
@@ -2293,7 +2377,8 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
 
       /* if (nomenus && !ascii_sequence_p (this)) */
       if (nomenus && XINT (last) >= 0
-         && !INTEGERP (Faref (this, make_number (0))))
+         && SYMBOLP (tem = Faref (this, make_number (0)))
+         && !NILP (Fmemq (XCAR (parse_modifiers (tem)), Vmenu_events)))
        /* If no menu entries should be returned, skip over the
           keymaps bound to `menu-bar' and `tool-bar' and other
           non-ascii prefixes like `C-down-mouse-2'.  */
@@ -2347,7 +2432,7 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
                            Fcons (Fcons (this, last),
                                   Fcons (make_number (nomenus),
                                          make_number (last_is_meta))));
-             map_char_table (where_is_internal_2, Qnil, elt, args,
+             map_char_table (where_is_internal_2, Qnil, elt, elt, args,
                              0, indices);
              sequences = XCDR (XCAR (args));
            }
@@ -3495,7 +3580,6 @@ Return list of symbols found.  */)
      Lisp_Object regexp, predicate;
 {
   Lisp_Object tem;
-  struct gcpro gcpro1, gcpro2;
   CHECK_STRING (regexp);
   apropos_predicate = predicate;
   apropos_accumulate = Qnil;
@@ -3626,6 +3710,15 @@ This keymap works like `function-key-map', but comes after that,
 and applies even for keys that have ordinary bindings.  */);
   Vkey_translation_map = Qnil;
 
+  staticpro (&Vmenu_events);
+  Vmenu_events = Fcons (intern ("menu-bar"),
+                       Fcons (intern ("tool-bar"),
+                              Fcons (intern ("mouse-1"),
+                                     Fcons (intern ("mouse-2"),
+                                            Fcons (intern ("mouse-3"),
+                                                   Qnil)))));
+
+
   Qsingle_key_description = intern ("single-key-description");
   staticpro (&Qsingle_key_description);
 
@@ -3658,6 +3751,7 @@ and applies even for keys that have ordinary bindings.  */);
   defsubr (&Sset_keymap_parent);
   defsubr (&Smake_keymap);
   defsubr (&Smake_sparse_keymap);
+  defsubr (&Smap_keymap);
   defsubr (&Scopy_keymap);
   defsubr (&Scommand_remapping);
   defsubr (&Skey_binding);