changeset 50944:111b4f1da171

(follow_key): Remove dead variable `did_meta'. (access_keymap_keyremap, keyremap_step): New funs, extracted from the duplicated handling of function-key-map and key-translation-map in read_key_sequence. (read_key_sequence): Use them.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Sat, 10 May 2003 22:15:35 +0000
parents 654c1513e74a
children 4151ece07b08
files src/keyboard.c
diffstat 1 files changed, 159 insertions(+), 206 deletions(-) [+]
line wrap: on
line diff
--- a/src/keyboard.c	Sat May 10 18:54:13 2003 +0000
+++ b/src/keyboard.c	Sat May 10 22:15:35 2003 +0000
@@ -8179,20 +8179,13 @@
      int nmaps;
 {
   int i, first_binding;
-  int did_meta = 0;
 
   first_binding = nmaps;
   for (i = nmaps - 1; i >= 0; i--)
     {
       if (! NILP (current[i]))
 	{
-	  Lisp_Object map;
-	  if (did_meta)
-	    map = defs[i];
-	  else
-	    map = current[i];
-
-	  defs[i] = access_keymap (map, key, 1, 0, 1);
+	  defs[i] = access_keymap (current[i], key, 1, 0, 1);
 	  if (! NILP (defs[i]))
 	    first_binding = i;
 	}
@@ -8216,6 +8209,119 @@
   int start, end;
 } keyremap;
 
+/* Lookup KEY in MAP.
+   MAP is a keymap mapping keys to key vectors or functions.
+   If the mapping is a function and DO_FUNCTION is non-zero, then
+   the function is called with PROMPT as parameter and its return
+   value is used as the return value of this function (after checking
+   that it is indeed a vector).  */
+
+static Lisp_Object
+access_keymap_keyremap (map, key, prompt, do_funcall)
+     Lisp_Object map, key, prompt;
+     int do_funcall;
+{
+  Lisp_Object next;
+  
+  next = access_keymap (map, key, 1, 0, 1);
+
+  /* Handle symbol with autoload definition.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next))
+      && CONSP (XSYMBOL (next)->function)
+      && EQ (XCAR (XSYMBOL (next)->function), Qautoload))
+    do_autoload (XSYMBOL (next)->function, next);
+
+  /* Handle a symbol whose function definition is a keymap
+     or an array.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next))
+      && (!NILP (Farrayp (XSYMBOL (next)->function))
+	  || KEYMAPP (XSYMBOL (next)->function)))
+    next = XSYMBOL (next)->function;
+	    
+  /* If the keymap gives a function, not an
+     array, then call the function with one arg and use
+     its value instead.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next)) && do_funcall)
+    {
+      Lisp_Object tem;
+      tem = next;
+
+      next = call1 (next, prompt);
+      /* If the function returned something invalid,
+	 barf--don't ignore it.
+	 (To ignore it safely, we would need to gcpro a bunch of
+	 other variables.)  */
+      if (! (VECTORP (next) || STRINGP (next)))
+	error ("Function %s returns invalid key sequence", tem);
+    }
+  return next;
+}
+
+/* Do one step of the key remapping used for function-key-map and
+   key-translation-map:
+   KEYBUF is the buffer holding the input events.
+   BUFSIZE is its maximum size.
+   FKEY is a pointer to the keyremap structure to use.
+   INPUT is the index of the last element in KEYBUF.
+   DOIT if non-zero says that the remapping can actually take place.
+   DIFF is used to return the number of keys added/removed by the remapping.
+   PARENT is the root of the keymap.
+   PROMPT is the prompt to use if the remapping happens through a function.
+   The return value is non-zero if the remapping actually took place.  */
+
+static int
+keyremap_step (keybuf, bufsize, fkey, input, doit, diff, parent, prompt)
+     Lisp_Object *keybuf, prompt, parent;
+     keyremap *fkey;
+     int input, doit, *diff, bufsize;
+{
+  Lisp_Object next, key;
+
+  key = keybuf[fkey->end++];
+  next = access_keymap_keyremap (fkey->map, key, prompt, doit);
+
+  /* If keybuf[fkey->start..fkey->end] is bound in the
+     map and we're in a position to do the key remapping, replace it with
+     the binding and restart with fkey->start at the end. */
+  if ((VECTORP (next) || STRINGP (next)) && doit)
+    {
+      int len = XFASTINT (Flength (next));
+      int i;
+
+      *diff = len - (fkey->end - fkey->start);
+
+      if (input + *diff >= bufsize)
+	error ("Key sequence too long");
+
+      /* Shift the keys that follow fkey->end.  */
+      if (*diff < 0)
+	for (i = fkey->end; i < input; i++)
+	  keybuf[i + *diff] = keybuf[i];
+      else if (*diff > 0)
+	for (i = input - 1; i >= fkey->end; i--)
+	  keybuf[i + *diff] = keybuf[i];
+      /* Overwrite the old keys with the new ones.  */
+      for (i = 0; i < len; i++)
+	keybuf[fkey->start + i]
+	  = Faref (next, make_number (i));
+
+      fkey->start = fkey->end += *diff;
+      fkey->map = parent;
+
+      return 1;
+    }
+
+  fkey->map = get_keymap (next, 0, 1);
+
+  /* If we no longer have a bound suffix, try a new position for
+     fkey->start.  */
+  if (!CONSP (fkey->map))
+    {
+      fkey->end = ++fkey->start;
+      fkey->map = parent;
+    }
+  return 0;
+}
 
 /* Read a sequence of keys that ends with a non prefix character,
    storing it in KEYBUF, a buffer of size BUFSIZE.
@@ -8335,8 +8441,9 @@
   /* Likewise, for key_translation_map.  */
   volatile keyremap keytran;
 
-  /* If we receive a ``switch-frame'' event in the middle of a key sequence,
-     we put it off for later.  While we're reading, we keep the event here.  */
+  /* If we receive a `switch-frame' or `select-window' event in the middle of
+     a key sequence, we put it off for later.
+     While we're reading, we keep the event here.  */
   volatile Lisp_Object delayed_switch_frame;
 
   /* See the comment below... */
@@ -8507,6 +8614,9 @@
 	 just one key.  */
       volatile int echo_local_start, keys_local_start, local_first_binding;
 
+      eassert (fkey.end == t || (fkey.end > t && fkey.end <= mock_input));
+      eassert (fkey.start <= fkey.end);
+      eassert (keytran.start <= keytran.end);
       /* key-translation-map is applied *after* function-key-map.  */
       eassert (keytran.end <= fkey.start);
 
@@ -8675,6 +8785,7 @@
 	  Vquit_flag = Qnil;
 
 	  if (EVENT_HAS_PARAMETERS (key)
+	      /* Either a `switch-frame' or a `select-window' event.  */
 	      && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qswitch_frame))
 	    {
 	      /* If we're at the beginning of a key sequence, and the caller
@@ -9079,207 +9190,49 @@
       else
 	/* If the sequence is unbound, see if we can hang a function key
 	   off the end of it.  */
-	{
-	  Lisp_Object next;
-
-	  /* Continue scan from fkey.end until we find a bound suffix.
-	     If we fail, increment fkey.start and start over from there.  */
-	  while (fkey.end < t)
-	    {
-	      Lisp_Object key;
-
-	      key = keybuf[fkey.end++];
-	      next = access_keymap (fkey.map, key, 1, 0, 1);
-
-	      /* Handle symbol with autoload definition.  */
-	      if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-		  && CONSP (XSYMBOL (next)->function)
-		  && EQ (XCAR (XSYMBOL (next)->function), Qautoload))
-		do_autoload (XSYMBOL (next)->function, next);
-
-	      /* Handle a symbol whose function definition is a keymap
-		 or an array.  */
-	      if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-		  && (!NILP (Farrayp (XSYMBOL (next)->function))
-		      || KEYMAPP (XSYMBOL (next)->function)))
-		next = XSYMBOL (next)->function;
-
-#if 0 /* I didn't turn this on, because it might cause trouble
-	 for the mapping of return into C-m and tab into C-i.  */
-	      /* Optionally don't map function keys into other things.
-		 This enables the user to redefine kp- keys easily.  */
-	      if (SYMBOLP (key) && !NILP (Vinhibit_function_key_mapping))
-		next = Qnil;
-#endif
-
-	      /* If the function key map gives a function, not an
-		 array, then call the function with no args and use
-		 its value instead.  */
-	      if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-		  /* If there's a binding (i.e. first_binding >= nmaps)
-		     we don't want to apply this function-key-mapping.  */
-		  && fkey.end == t && first_binding >= nmaps)
-		{
-		  struct gcpro gcpro1, gcpro2, gcpro3;
-		  Lisp_Object tem;
-		  tem = next;
-
-		  GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
-		  next = call1 (next, prompt);
-		  UNGCPRO;
-		  /* If the function returned something invalid,
-		     barf--don't ignore it.
-		     (To ignore it safely, we would need to gcpro a bunch of
-		     other variables.)  */
-		  if (! (VECTORP (next) || STRINGP (next)))
-		    error ("Function in key-translation-map returns invalid key sequence");
-		}
-
-	      /* If keybuf[fkey.start..fkey.end] is bound in the
-		 function key map and it's a suffix of the current
-		 sequence (i.e. fkey.end == t), replace it with
-		 the binding and restart with fkey.start at the end. */
-	      if ((VECTORP (next) || STRINGP (next))
-		  /* If there's a binding (i.e. first_binding >= nmaps)
-		     we don't want to apply this function-key-mapping.  */
-		  && fkey.end == t && first_binding >= nmaps)
-		{
-		  int len = XFASTINT (Flength (next));
-
-		  t = fkey.start + len;
-		  if (t >= bufsize)
-		    error ("Key sequence too long");
-
-		  if (VECTORP (next))
-		    bcopy (XVECTOR (next)->contents,
-			   keybuf + fkey.start,
-			   (t - fkey.start) * sizeof (keybuf[0]));
-		  else if (STRINGP (next))
-		    {
-		      int i;
-
-		      for (i = 0; i < len; i++)
-			XSETFASTINT (keybuf[fkey.start + i], SREF (next, i));
-		    }
-
-		  mock_input = t;
-		  fkey.start = fkey.end = t;
-		  fkey.map = Vfunction_key_map;
-
-		  /* Do pass the results through key-translation-map.
-		     But don't retranslate what key-translation-map
-		     has already translated.  */
-		  keytran.end = keytran.start;
-		  keytran.map = Vkey_translation_map;
-
-		  goto replay_sequence;
-		}
-
-	      fkey.map = get_keymap (next, 0, 1);
-
-	      /* If we no longer have a bound suffix, try a new positions for
-		 fkey.start.  */
-	      if (!CONSP (fkey.map))
-		{
-		  fkey.end = ++fkey.start;
-		  fkey.map = Vfunction_key_map;
-		}
-	    }
-	}
-
-      /* Look for this sequence in key-translation-map.  */
-      {
-	Lisp_Object next;
-
-	/* Scan from keytran.end until we find a bound suffix.  */
-	while (keytran.end < fkey.start)
+	/* Continue scan from fkey.end until we find a bound suffix.  */
+	while (fkey.end < t)
 	  {
-	    Lisp_Object key;
-
-	    key = keybuf[keytran.end++];
-	    next = access_keymap (keytran.map, key, 1, 0, 1);
-
-	    /* Handle symbol with autoload definition.  */
-	    if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-		&& CONSP (XSYMBOL (next)->function)
-		&& EQ (XCAR (XSYMBOL (next)->function), Qautoload))
-	      do_autoload (XSYMBOL (next)->function, next);
-
-	    /* Handle a symbol whose function definition is a keymap
-	       or an array.  */
-	    if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-		&& (!NILP (Farrayp (XSYMBOL (next)->function))
-		    || KEYMAPP (XSYMBOL (next)->function)))
-	      next = XSYMBOL (next)->function;
-
-	    /* If the key translation map gives a function, not an
-	       array, then call the function with one arg and use
-	       its value instead.  */
-	    if (SYMBOLP (next) && ! NILP (Ffboundp (next)))
+	    struct gcpro gcpro1, gcpro2, gcpro3;
+	    int done, diff;
+
+	    GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
+	    done = keyremap_step (keybuf, bufsize, &fkey,
+				  max (t, mock_input),
+				  /* If there's a binding (i.e.
+				     first_binding >= nmaps) we don't want
+				     to apply this function-key-mapping.  */
+				  fkey.end + 1 == t && first_binding >= nmaps,
+				  &diff, Vfunction_key_map, prompt);
+	    UNGCPRO;
+	    if (done)
 	      {
-		struct gcpro gcpro1, gcpro2, gcpro3;
-		Lisp_Object tem;
-		tem = next;
-
-		GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
-		next = call1 (next, prompt);
-		UNGCPRO;
-		/* If the function returned something invalid,
-		   barf--don't ignore it.
-		   (To ignore it safely, we would need to gcpro a bunch of
-		   other variables.)  */
-		if (! (VECTORP (next) || STRINGP (next)))
-		  error ("Function in key-translation-map returns invalid key sequence");
-	      }
-
-	    /* If keybuf[keytran.start..keytran.end] is bound in the
-	       key translation map and it's a suffix of the current
-	       sequence (i.e. keytran.end == t), replace it with
-	       the binding and restart with keytran.start at the end. */
-	    if ((VECTORP (next) || STRINGP (next)))
-	      {
-		int len = XFASTINT (Flength (next));
-		int i, diff = len - (keytran.end - keytran.start);
-
-		mock_input = max (t, mock_input);
-		if (mock_input + diff >= bufsize)
-		  error ("Key sequence too long");
-
-		/* Shift the keys that are after keytran.end.  */
-		if (diff < 0)
-		  for (i = keytran.end; i < mock_input; i++)
-		    keybuf[i + diff] = keybuf[i];
-		else if (diff > 0)
-		  for (i = mock_input - 1; i >= keytran.end; i--)
-		    keybuf[i + diff] = keybuf[i];
-		/* Replace the keys between keytran.start and keytran.end
-		   with those from next.  */
-		for (i = 0; i < len; i++)
-		  keybuf[keytran.start + i]
-		    = Faref (next, make_number (i));
-
-		mock_input += diff;
-		keytran.start = keytran.end += diff;
-		keytran.map = Vkey_translation_map;
-
-		/* Adjust the function-key-map counters.  */
-		fkey.start += diff;
-		fkey.end += diff;
-
+		mock_input = diff + max (t, mock_input);
 		goto replay_sequence;
 	      }
-
-	    keytran.map = get_keymap (next, 0, 1);
-
-	    /* If we no longer have a bound suffix, try a new positions for
-	       keytran.start.  */
-	    if (!CONSP (keytran.map))
-	      {
-		keytran.end = ++keytran.start;
-		keytran.map = Vkey_translation_map;
-	      }
 	  }
-      }
+
+      /* Look for this sequence in key-translation-map.
+	 Scan from keytran.end until we find a bound suffix.  */
+      while (keytran.end < fkey.start)
+	{
+	  struct gcpro gcpro1, gcpro2, gcpro3;
+	  int done, diff;
+
+	  GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
+	  done = keyremap_step (keybuf, bufsize, &keytran, max (t, mock_input),
+				1, &diff, Vkey_translation_map, prompt);
+	  UNGCPRO;
+	  if (done)
+	    {
+	      mock_input = diff + max (t, mock_input);
+	      /* Adjust the function-key-map counters.  */
+	      fkey.end += diff;
+	      fkey.start += diff;
+	      
+	      goto replay_sequence;
+	    }
+	}
 
       /* If KEY is not defined in any of the keymaps,
 	 and cannot be part of a function key or translation,