(Fcall_interactively): Call single_kboard_state
[bpt/emacs.git] / src / callint.c
index 337ea0e..8fbd45c 100644 (file)
@@ -1,5 +1,5 @@
 /* Call a Lisp function interactively.
-   Copyright (C) 1985, 1986, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1993, 1994, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -28,6 +28,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 extern char *index ();
 
+int current_prefix_partial;
 Lisp_Object Vprefix_arg, Vcurrent_prefix_arg, Qminus, Qplus;
 Lisp_Object Qcall_interactively;
 Lisp_Object Vcommand_history;
@@ -39,8 +40,53 @@ Lisp_Object Qenable_recursive_minibuffers;
    even if mark_active is 0.  */
 Lisp_Object Vmark_even_if_inactive;
 
+Lisp_Object Vmouse_leave_buffer_hook, Qmouse_leave_buffer_hook;
+
 Lisp_Object Qlist;
-Lisp_Object preserved_fns;
+static Lisp_Object preserved_fns;
+
+/* Marker used within call-interactively to refer to point.  */
+static Lisp_Object point_marker;
+
+
+void
+clear_prefix_arg ()
+{
+  Vprefix_arg = Qnil;
+  if (!current_prefix_partial)
+    {
+      current_kboard->prefix_factor = Qnil;
+      current_kboard->prefix_value = Qnil;
+      current_kboard->prefix_sign = 1;
+      current_kboard->prefix_partial = 0;
+    }
+}
+
+void
+finalize_prefix_arg ()
+{
+  if (!NILP (current_kboard->prefix_factor))
+    Vprefix_arg = Fcons (current_kboard->prefix_factor, Qnil);
+  else if (NILP (current_kboard->prefix_value))
+    Vprefix_arg = (current_kboard->prefix_sign > 0 ? Qnil : Qminus);
+  else if (current_kboard->prefix_sign > 0)
+    Vprefix_arg = current_kboard->prefix_value;
+  else
+    XSETINT (Vprefix_arg, -XINT (current_kboard->prefix_value));
+  current_kboard->prefix_partial = 0;
+}
+
+static void
+describe_prefix_arg ()
+{
+  if (INTEGERP (Vprefix_arg))
+    message ("Arg: %d", Vprefix_arg);
+  else if (CONSP (Vprefix_arg))
+    message ("Arg: [%d]", XCONS (Vprefix_arg)->car);
+  else if (EQ (Vprefix_arg, Qminus))
+    message ("Arg: -");
+}
+
 
 /* This comment supplies the doc string for interactive,
    for make-docfile to see.  We cannot put this in the real DEFUN
@@ -78,10 +124,11 @@ e -- Parametrized event (i.e., one that's a list) that invoked this command.\n\
      This skips events that are integers or symbols.\n\
 f -- Existing file name.\n\
 F -- Possibly nonexistent file name.\n\
-k -- Key sequence (string).\n\
+k -- Key sequence (downcase the last event if needed to get a definition).\n\
+K -- Key sequence to be redefined (do not downcase the last event).\n\
 m -- Value of mark as number.  Does not do I/O.\n\
 n -- Number read using minibuffer.\n\
-N -- Prefix arg converted to number, or if none, do like code `n'.\n\
+N -- Raw prefix arg, or if none, do like code `n'.\n\
 p -- Prefix arg converted to number.  Does not do I/O.\n\
 P -- Prefix arg in raw form.  Does not do I/O.\n\
 r -- Region: point and mark as 2 numeric args, smallest first.  Does no I/O.\n\
@@ -227,7 +274,7 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
     }
   else if (COMPILEDP (fun))
     {
-      if (XVECTOR (fun)->size <= COMPILED_INTERACTIVE)
+      if ((XVECTOR (fun)->size & PSEUDOVECTOR_SIZE_MASK) <= COMPILED_INTERACTIVE)
        goto lose;
       specs = XVECTOR (fun)->contents[COMPILED_INTERACTIVE];
     }
@@ -248,7 +295,10 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
       specs = Fcar (Fcdr (specs));
     }
   else if (EQ (funcar, Qmocklisp))
-    return ml_apply (fun, Qinteractive);
+    {
+      single_kboard_state ();
+      return ml_apply (fun, Qinteractive);
+    }
   else
     goto lose;
 
@@ -300,6 +350,7 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
          Vcommand_history
            = Fcons (Fcons (function, values), Vcommand_history);
        }
+      single_kboard_state ();
       return apply1 (function, specs);
     }
 
@@ -312,9 +363,12 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
       break;
   
   /* Handle special starting chars `*' and `@'.  Also `-'.  */
+  /* Note that `+' is reserved for user extensions.  */
   while (1)
     {
-      if (*string == '*')
+      if (*string == '+')
+       error ("`+' is not used in `interactive' for ordinary commands");
+      else if (*string == '*')
        {
          string++;
          if (!NILP (current_buffer->read_only))
@@ -336,6 +390,11 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
              if (MINI_WINDOW_P (XWINDOW (event))
                  && ! (minibuf_level > 0 && EQ (event, minibuf_window)))
                error ("Attempt to select inactive minibuffer window");
+
+             /* If the current buffer wants to clean up, let it.  */
+             if (!NILP (Vmouse_leave_buffer_hook))
+               call1 (Vrun_hooks, Qmouse_leave_buffer_hook);
+
              Fselect_window (event);
            }
          string++;
@@ -435,7 +494,8 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
          break;
 
        case 'd':               /* Value of point.  Does not do I/O.  */
-         XFASTINT (args[i]) = point;
+         Fset_marker (point_marker, make_number (PT), Qnil);
+         args[i] = point_marker;
          /* visargs[i] = Qnil; */
          varies[i] = 1;
          break;
@@ -455,8 +515,14 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
                                     Qnil, Qnil, Qnil, Qnil);
          break;
 
-       case 'k':               /* Key sequence (string) */
-         args[i] = Fread_key_sequence (build_string (prompt), Qnil);
+       case 'k':               /* Key sequence. */
+         args[i] = Fread_key_sequence (build_string (prompt), Qnil, Qnil, Qnil);
+         teml = args[i];
+         visargs[i] = Fkey_description (teml);
+         break;
+
+       case 'K':               /* Key sequence to be defined. */
+         args[i] = Fread_key_sequence (build_string (prompt), Qnil, Qt, Qnil);
          teml = args[i];
          visargs[i] = Fkey_description (teml);
          break;
@@ -481,7 +547,7 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
        case 'm':               /* Value of mark.  Does not do I/O.  */
          check_mark ();
          /* visargs[i] = Qnil; */
-         XFASTINT (args[i]) = marker_position (current_buffer->mark);
+         args[i] = current_buffer->mark;
          varies[i] = 2;
          break;
 
@@ -510,21 +576,22 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
 
        case 'r':               /* Region, point and mark as 2 args. */
          check_mark ();
+         Fset_marker (point_marker, make_number (PT), Qnil);
          /* visargs[i+1] = Qnil; */
          foo = marker_position (current_buffer->mark);
          /* visargs[i] = Qnil; */
-         XFASTINT (args[i]) = point < foo ? point : foo;
+         args[i] = point < foo ? point_marker : current_buffer->mark;
          varies[i] = 3;
-         XFASTINT (args[++i]) = point > foo ? point : foo;
+         args[++i] = point > foo ? point_marker : current_buffer->mark;
          varies[i] = 4;
          break;
 
        case 's':               /* String read via minibuffer.  */
-         args[i] = Fread_string (build_string (prompt), Qnil);
+         args[i] = Fread_string (build_string (prompt), Qnil, Qnil);
          break;
 
        case 'S':               /* Any symbol.  */
-         visargs[i] = Fread_string (build_string (prompt), Qnil);
+         visargs[i] = Fread_string (build_string (prompt), Qnil, Qnil);
          /* Passing args[i] directly stimulates compiler bug */
          teml = visargs[i];
          args[i] = Fintern (teml, Qnil);
@@ -546,8 +613,11 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
          visargs[i] = last_minibuf_string;
          break;
 
+         /* We have a case for `+' so we get an error
+            if anyone tries to define one here.  */
+       case '+':
        default:
-         error ("Invalid control letter \"%c\" (%03o) in interactive calling string",
+         error ("Invalid control letter `%c' (%03o) in interactive calling string",
                 *tem, *tem);
        }
 
@@ -571,14 +641,24 @@ Otherwise, this is done only if an arg is read using the minibuffer.")
     {
       visargs[0] = function;
       for (i = 1; i < count + 1; i++)
-       if (varies[i] > 0)
-         visargs[i] = Fcons (intern (callint_argfuns[varies[i]]), Qnil);
-       else
-         visargs[i] = quotify_arg (args[i]);
+       {
+         if (varies[i] > 0)
+           visargs[i] = Fcons (intern (callint_argfuns[varies[i]]), Qnil);
+         else
+           visargs[i] = quotify_arg (args[i]);
+       }
       Vcommand_history = Fcons (Flist (count + 1, visargs),
                                Vcommand_history);
     }
 
+  /* If we used a marker to hold point, mark, or an end of the region,
+     temporarily, convert it to an integer now.  */
+  for (i = 1; i <= count; i++)
+    if (varies[i] >= 1 && varies[i] <= 4)
+      XSETINT (args[i], marker_position (args[i]));
+
+  single_kboard_state ();
+
   {
     Lisp_Object val;
     specbind (Qcommand_debug_status, Qnil);
@@ -600,7 +680,7 @@ Its numeric meaning is what you would get from `(interactive \"p\")'.")
   Lisp_Object val;
   
   if (NILP (raw))
-    XFASTINT (val) = 1;
+    XSETFASTINT (val, 1);
   else if (EQ (raw, Qminus))
     XSETINT (val, -1);
   else if (CONSP (raw))
@@ -608,13 +688,75 @@ Its numeric meaning is what you would get from `(interactive \"p\")'.")
   else if (INTEGERP (raw))
     val = raw;
   else
-    XFASTINT (val) = 1;
+    XSETFASTINT (val, 1);
 
   return val;
 }
 
+DEFUN ("universal-argument", Funiversal_argument, Suniversal_argument, 0, 0, "",
+  "Begin a numeric argument for the following command.\n\
+Digits or minus sign following \\[universal-argument] make up the numeric argument.\n\
+\\[universal-argument] following the digits or minus sign ends the argument.\n\
+\\[universal-argument] without digits or minus sign provides 4 as argument.\n\
+Repeating \\[universal-argument] without digits or minus sign\n\
+ multiplies the argument by 4 each time.")
+  ()
+{
+  if (!current_prefix_partial)
+    {
+      /* First C-u */
+      XSETFASTINT (current_kboard->prefix_factor, 4);
+      current_kboard->prefix_value = Qnil;
+      current_kboard->prefix_sign = 1;
+      current_kboard->prefix_partial = 1;
+    }
+  else if (!NILP (current_kboard->prefix_factor))
+    {
+      /* Subsequent C-u */
+      XSETINT (current_kboard->prefix_factor,
+              XINT (current_kboard->prefix_factor) * 4);
+      current_kboard->prefix_partial = 1;
+    }
+  else
+    {
+      /* Terminating C-u */
+      finalize_prefix_arg ();
+      describe_prefix_arg ();
+    }
+}
+
+DEFUN ("negative-argument", Fnegative_argument, Snegative_argument, 0, 0, "",
+  "Begin a negative numeric argument for the next command.\n\
+\\[universal-argument] following digits or minus sign ends the argument.")
+  ()
+{
+  current_kboard->prefix_factor = Qnil;
+  current_kboard->prefix_sign *= -1;
+  current_kboard->prefix_partial = 1;
+}
+
+DEFUN ("digit-argument", Fdigit_argument, Sdigit_argument, 0, 0, "",
+  "Part of the numeric argument for the next command.\n\
+\\[universal-argument] following digits or minus sign ends the argument.")
+  ()
+{
+  int c;
+  if (!(INTEGERP (last_command_char)
+       && (c = (XINT (last_command_char) & 0177)) >= '0' && c <= '9'))
+    error("digit-argument must be bound to a digit key");
+  current_kboard->prefix_factor = Qnil;
+  if (NILP (current_kboard->prefix_value))
+    XSETFASTINT (current_kboard->prefix_value, 0);
+  XSETINT (current_kboard->prefix_value,
+          XINT (current_kboard->prefix_value) * 10 + (c - '0'));
+  current_kboard->prefix_partial = 1;
+}
+
 syms_of_callint ()
 {
+  point_marker = Fmake_marker ();
+  staticpro (&point_marker);
+
   preserved_fns = Fcons (intern ("region-beginning"),
                         Fcons (intern ("region-end"),
                                Fcons (intern ("point"),
@@ -639,6 +781,9 @@ syms_of_callint ()
   Qenable_recursive_minibuffers = intern ("enable-recursive-minibuffers");
   staticpro (&Qenable_recursive_minibuffers);
 
+  Qmouse_leave_buffer_hook = intern ("mouse-leave-buffer-hook");
+  staticpro (&Qmouse_leave_buffer_hook);
+
   DEFVAR_LISP ("prefix-arg", &Vprefix_arg,
     "The value of the prefix argument for the next editing command.\n\
 It may be a number, or the symbol `-' for just a minus sign as arg,\n\
@@ -678,7 +823,16 @@ turns off region highlighting, but commands that use the mark\n\
 behave as if the mark were still active.");
   Vmark_even_if_inactive = Qnil;
 
+  DEFVAR_LISP ("mouse-leave-buffer-hook", &Vmouse_leave_buffer_hook,
+    "Hook to run when about to switch windows with a mouse command.\n\
+Its purpose is to give temporary modes such as Isearch mode\n\
+a way to turn themselves off when a mouse command switches windows.");
+  Vmouse_leave_buffer_hook = Qnil;
+
   defsubr (&Sinteractive);
   defsubr (&Scall_interactively);
   defsubr (&Sprefix_numeric_value);
+  defsubr (&Suniversal_argument);
+  defsubr (&Snegative_argument);
+  defsubr (&Sdigit_argument);
 }