summaryrefslogtreecommitdiff
path: root/src/callint.c
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
commit650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch)
tree85d11f6437cde22f410c25e0e5f71a3131ebd07d /src/callint.c
parent8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff)
parent4b85ae6a24380fb67a3315eaec9233f17a872473 (diff)
downloademacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip
Merge 'master' into noverlay
Diffstat (limited to 'src/callint.c')
-rw-r--r--src/callint.c528
1 files changed, 241 insertions, 287 deletions
diff --git a/src/callint.c b/src/callint.c
index 469205cc380..8ef0e5240a5 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -1,5 +1,5 @@
/* Call a Lisp function interactively.
- Copyright (C) 1985-1986, 1993-1995, 1997, 2000-2017 Free Software
+ Copyright (C) 1985-1986, 1993-1995, 1997, 2000-2022 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
@@ -34,7 +34,6 @@ static Lisp_Object point_marker;
/* String for the prompt text used in Fcall_interactively. */
static Lisp_Object callint_message;
-/* ARGSUSED */
DEFUN ("interactive", Finteractive, Sinteractive, 0, UNEVALLED, 0,
doc: /* Specify a way of parsing arguments for interactive use of a function.
For example, write
@@ -53,10 +52,12 @@ Usually the argument of `interactive' is a string containing a code
arguments to the command, concatenate the individual strings,
separating them by newline characters.
-Prompts are passed to `format', and may use % escapes to print the
+Prompts are passed to `format', and may use %s escapes to print the
arguments that have already been read.
+
If the argument is not a string, it is evaluated to get a list of
arguments to pass to the command.
+
Just `(interactive)' means pass no arguments to the command when
calling interactively.
@@ -103,7 +104,14 @@ If the string begins with `^' and `shift-select-mode' is non-nil,
Emacs first calls the function `handle-shift-selection'.
You may use `@', `*', and `^' together. They are processed in the
order that they appear, before reading any arguments.
-usage: (interactive &optional ARG-DESCRIPTOR) */
+
+If MODES is present, it should be a list of mode names (symbols) that
+this command is applicable for. The main effect of this is that
+`M-x TAB' (by default) won't list this command if the current buffer's
+mode doesn't match the list. That is, if either the major mode isn't
+derived from them, or (when it's a minor mode) the mode isn't in effect.
+
+usage: (interactive &optional ARG-DESCRIPTOR &rest MODES) */
attributes: const)
(Lisp_Object args)
{
@@ -153,74 +161,62 @@ check_mark (bool for_region)
xsignal0 (Qmark_inactive);
}
-/* If the list of args INPUT was produced with an explicit call to
- `list', look for elements that were computed with
- (region-beginning) or (region-end), and put those expressions into
- VALUES instead of the present values.
+/* If FUNCTION has an `interactive-args' spec, replace relevant
+ elements in VALUES with those forms instead.
This function doesn't return a value because it modifies elements
of VALUES to do its job. */
static void
-fix_command (Lisp_Object input, Lisp_Object values)
+fix_command (Lisp_Object function, Lisp_Object values)
{
- /* FIXME: Instead of this ugly hack, we should provide a way for an
- interactive spec to return an expression/function that will re-build the
- args without user intervention. */
- if (CONSP (input))
+ /* Quick exit if there's no values to alter. */
+ if (!CONSP (values) || !SYMBOLP (function))
+ return;
+
+ Lisp_Object reps = Fget (function, Qinteractive_args);
+
+ if (CONSP (reps))
{
- Lisp_Object car;
+ int i = 0;
+ Lisp_Object vals = values;
- car = XCAR (input);
- /* Skip through certain special forms. */
- while (EQ (car, Qlet) || EQ (car, Qletx)
- || EQ (car, Qsave_excursion)
- || EQ (car, Qprogn))
+ while (!NILP (vals))
{
- while (CONSP (XCDR (input)))
- input = XCDR (input);
- input = XCAR (input);
- if (!CONSP (input))
- break;
- car = XCAR (input);
+ Lisp_Object rep = Fassq (make_fixnum (i), reps);
+ if (!NILP (rep))
+ Fsetcar (vals, XCDR (rep));
+ vals = XCDR (vals);
+ ++i;
}
- if (EQ (car, Qlist))
+ }
+
+ /* If the list contains a bunch of trailing nil values, and they are
+ optional, remove them from the list. This makes navigating the
+ history less confusing, since it doesn't contain a lot of
+ parameters that aren't used. */
+ Lisp_Object arity = Ffunc_arity (function);
+ /* We don't want to do this simplification if we have an &rest
+ function, because (cl-defun foo (a &optional (b 'zot)) ..)
+ etc. */
+ if (FIXNUMP (XCAR (arity)) && FIXNUMP (XCDR (arity)))
+ {
+ Lisp_Object final = Qnil;
+ ptrdiff_t final_i = 0, i = 0;
+ for (Lisp_Object tail = values;
+ CONSP (tail);
+ tail = XCDR (tail), ++i)
{
- Lisp_Object intail, valtail;
- for (intail = Fcdr (input), valtail = values;
- CONSP (valtail);
- intail = Fcdr (intail), valtail = XCDR (valtail))
+ if (!NILP (XCAR (tail)))
{
- Lisp_Object elt;
- elt = Fcar (intail);
- if (CONSP (elt))
- {
- Lisp_Object presflag, carelt;
- carelt = XCAR (elt);
- /* If it is (if X Y), look at Y. */
- if (EQ (carelt, Qif)
- && EQ (Fnthcdr (make_number (3), elt), Qnil))
- elt = Fnth (make_number (2), elt);
- /* If it is (when ... Y), look at Y. */
- else if (EQ (carelt, Qwhen))
- {
- while (CONSP (XCDR (elt)))
- elt = XCDR (elt);
- elt = Fcar (elt);
- }
-
- /* If the function call we're looking at
- is a special preserved one, copy the
- whole expression for this argument. */
- if (CONSP (elt))
- {
- presflag = Fmemq (Fcar (elt), preserved_fns);
- if (!NILP (presflag))
- Fsetcar (valtail, Fcar (intail));
- }
- }
+ final = tail;
+ final_i = i;
}
}
+
+ /* Chop the trailing optional values. */
+ if (final_i > 0 && final_i >= XFIXNUM (XCAR (arity)) - 1)
+ XSETCDR (final, Qnil);
}
}
@@ -243,7 +239,7 @@ return non-nil.
usage: (funcall-interactively FUNCTION &rest ARGUMENTS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
- ptrdiff_t speccount = SPECPDL_INDEX ();
+ specpdl_ref speccount = SPECPDL_INDEX ();
temporarily_switch_to_single_kboard (NULL);
/* Nothing special to do here, all the work is inside
@@ -261,53 +257,31 @@ to the function `interactive' at the top level of the function body.
See `interactive'.
Optional second arg RECORD-FLAG non-nil
-means unconditionally put this command in the command-history.
+means unconditionally put this command in the variable `command-history'.
Otherwise, this is done only if an arg is read using the minibuffer.
Optional third arg KEYS, if given, specifies the sequence of events to
-supply, as a vector, if the command inquires which events were used to
-invoke it. If KEYS is omitted or nil, the return value of
+supply, as a vector, if FUNCTION inquires which events were used to
+invoke it (via an `interactive' spec that contains, for instance, an
+\"e\" code letter). If KEYS is omitted or nil, the return value of
`this-command-keys-vector' is used. */)
(Lisp_Object function, Lisp_Object record_flag, Lisp_Object keys)
{
- /* `args' will contain the array of arguments to pass to the function.
- `visargs' will contain the same list but in a nicer form, so that if we
- pass it to styled_format it will be understandable to a human. */
- Lisp_Object *args, *visargs;
- Lisp_Object specs;
- Lisp_Object filter_specs;
- Lisp_Object teml;
- Lisp_Object up_event;
- Lisp_Object enable;
- USE_SAFE_ALLOCA;
- ptrdiff_t speccount = SPECPDL_INDEX ();
+ specpdl_ref speccount = SPECPDL_INDEX ();
- /* The index of the next element of this_command_keys to examine for
- the 'e' interactive code. */
- ptrdiff_t next_event;
-
- Lisp_Object prefix_arg;
- char *string;
- const char *tem;
-
- /* If varies[i] > 0, the i'th argument shouldn't just have its value
- in this call quoted in the command history. It should be
- recorded as a call to the function named callint_argfuns[varies[i]]. */
- signed char *varies;
-
- ptrdiff_t i, nargs;
- ptrdiff_t mark;
- bool arg_from_tty = 0;
+ bool arg_from_tty = false;
ptrdiff_t key_count;
- bool record_then_fail = 0;
+ bool record_then_fail = false;
- Lisp_Object save_this_command, save_last_command;
- Lisp_Object save_this_original_command, save_real_this_command;
+ Lisp_Object save_this_command = Vthis_command;
+ Lisp_Object save_this_original_command = Vthis_original_command;
+ Lisp_Object save_real_this_command = Vreal_this_command;
+ Lisp_Object save_last_command = KVAR (current_kboard, Vlast_command);
- save_this_command = Vthis_command;
- save_this_original_command = Vthis_original_command;
- save_real_this_command = Vreal_this_command;
- save_last_command = KVAR (current_kboard, Vlast_command);
+ /* Bound recursively so that code can check the current command from
+ code running from minibuffer hooks (and the like), without being
+ overwritten by subsequent minibuffer calls. */
+ specbind (Qcurrent_minibuffer_command, Vthis_command);
if (NILP (keys))
keys = this_command_keys, key_count = this_command_key_count;
@@ -318,66 +292,44 @@ invoke it. If KEYS is omitted or nil, the return value of
}
/* Save this now, since use of minibuffer will clobber it. */
- prefix_arg = Vcurrent_prefix_arg;
+ Lisp_Object prefix_arg = Vcurrent_prefix_arg;
- if (SYMBOLP (function))
- enable = Fget (function, Qenable_recursive_minibuffers);
- else
- enable = Qnil;
-
- specs = Qnil;
- string = 0;
- /* The idea of FILTER_SPECS is to provide a way to
- specify how to represent the arguments in command history.
- The feature is not fully implemented. */
- filter_specs = Qnil;
+ Lisp_Object enable = (SYMBOLP (function)
+ ? Fget (function, Qenable_recursive_minibuffers)
+ : Qnil);
/* If k or K discard an up-event, save it here so it can be retrieved with
U. */
- up_event = Qnil;
+ Lisp_Object up_event = Qnil;
/* Set SPECS to the interactive form, or barf if not interactive. */
- {
- Lisp_Object form;
- form = Finteractive_form (function);
- if (CONSP (form))
- specs = filter_specs = Fcar (XCDR (form));
- else
- wrong_type_argument (Qcommandp, function);
- }
+ Lisp_Object form = call1 (Qinteractive_form, function);
+ if (! CONSP (form))
+ wrong_type_argument (Qcommandp, function);
+ Lisp_Object specs = Fcar (XCDR (form));
+
+ /* At this point the value of SPECS could help provide a way to
+ specify how to represent the arguments in command history.
+ The feature is not fully implemented. */
/* If SPECS is not a string, invent one. */
if (! STRINGP (specs))
{
- Lisp_Object input;
Lisp_Object funval = Findirect_function (function, Qt);
uintmax_t events = num_input_events;
- input = specs;
/* Compute the arg values using the user's expression. */
specs = Feval (specs,
CONSP (funval) && EQ (Qclosure, XCAR (funval))
? CAR_SAFE (XCDR (funval)) : Qnil);
if (events != num_input_events || !NILP (record_flag))
{
- /* We should record this command on the command history. */
- Lisp_Object values;
- Lisp_Object this_cmd;
- /* Make a copy of the list of values, for the command history,
+ /* We should record this command on the command history.
+ Make a copy of the list of values, for the command history,
and turn them into things we can eval. */
- values = quotify_args (Fcopy_sequence (specs));
- fix_command (input, values);
- this_cmd = Fcons (function, values);
- if (history_delete_duplicates)
- Vcommand_history = Fdelete (this_cmd, Vcommand_history);
- Vcommand_history = Fcons (this_cmd, Vcommand_history);
-
- /* Don't keep command history around forever. */
- if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0)
- {
- teml = Fnthcdr (Vhistory_length, Vcommand_history);
- if (CONSP (teml))
- XSETCDR (teml, Qnil);
- }
+ Lisp_Object values = quotify_args (Fcopy_sequence (specs));
+ fix_command (function, values);
+ call4 (intern ("add-to-history"), intern ("command-history"),
+ Fcons (function, values), Qnil, Qt);
}
Vthis_command = save_this_command;
@@ -385,46 +337,45 @@ invoke it. If KEYS is omitted or nil, the return value of
Vreal_this_command = save_real_this_command;
kset_last_command (current_kboard, save_last_command);
- Lisp_Object result
- = unbind_to (speccount, CALLN (Fapply, Qfuncall_interactively,
- function, specs));
- SAFE_FREE ();
- return result;
+ return unbind_to (speccount, CALLN (Fapply, Qfuncall_interactively,
+ function, specs));
}
/* SPECS is set to a string; use it as an interactive prompt.
Copy it so that STRING will be valid even if a GC relocates SPECS. */
- SAFE_ALLOCA_STRING (string, specs);
-
- /* Here if function specifies a string to control parsing the defaults. */
+ USE_SAFE_ALLOCA;
+ ptrdiff_t string_len = SBYTES (specs);
+ char *string = SAFE_ALLOCA (string_len + 1);
+ memcpy (string, SDATA (specs), string_len + 1);
+ char *string_end = string + string_len;
- /* Set next_event to point to the first event with parameters. */
- for (next_event = 0; next_event < key_count; next_event++)
- if (EVENT_HAS_PARAMETERS (AREF (keys, next_event)))
- break;
+ /* The index of the next element of this_command_keys to examine for
+ the 'e' interactive code. Initialize it to point to the first
+ event with parameters. When `inhibit_mouse_event_check' is non-nil,
+ the command can accept an event without parameters,
+ so don't search for the event with parameters in this case. */
+ ptrdiff_t next_event = 0;
+ if (!inhibit_mouse_event_check)
+ for (; next_event < key_count; next_event++)
+ if (EVENT_HAS_PARAMETERS (AREF (keys, next_event)))
+ break;
/* Handle special starting chars `*' and `@'. Also `-'. */
/* Note that `+' is reserved for user extensions. */
- while (1)
+ for (;; string++)
{
if (*string == '+')
error ("`+' is not used in `interactive' for ordinary commands");
else if (*string == '*')
{
- string++;
if (!NILP (BVAR (current_buffer, read_only)))
{
if (!NILP (record_flag))
{
- char *p = string;
- while (*p)
- {
- if (! (*p == 'r' || *p == 'p' || *p == 'P'
- || *p == '\n'))
- Fbarf_if_buffer_read_only (Qnil);
- p++;
- }
- record_then_fail = 1;
+ for (char *p = string + 1; p < string_end; p++)
+ if (! (*p == 'r' || *p == 'p' || *p == 'P' || *p == '\n'))
+ Fbarf_if_buffer_read_only (Qnil);
+ record_then_fail = true;
}
else
Fbarf_if_buffer_read_only (Qnil);
@@ -432,21 +383,19 @@ invoke it. If KEYS is omitted or nil, the return value of
}
/* Ignore this for semi-compatibility with Lucid. */
else if (*string == '-')
- string++;
+ ;
else if (*string == '@')
{
- Lisp_Object event, w;
-
- event = (next_event < key_count
- ? AREF (keys, next_event)
- : Qnil);
+ Lisp_Object w, event = (next_event < key_count
+ ? AREF (keys, next_event)
+ : Qnil);
if (EVENT_HAS_PARAMETERS (event)
&& (w = XCDR (event), CONSP (w))
&& (w = XCAR (w), CONSP (w))
&& (w = XCAR (w), WINDOWP (w)))
{
if (MINI_WINDOW_P (XWINDOW (w))
- && ! (minibuf_level > 0 && EQ (w, minibuf_window)))
+ && ! (minibuf_level > 0 && BASE_EQ (w, minibuf_window)))
error ("Attempt to select inactive minibuffer window");
/* If the current buffer wants to clean up, let it. */
@@ -454,32 +403,23 @@ invoke it. If KEYS is omitted or nil, the return value of
Fselect_window (w, Qnil);
}
- string++;
}
else if (*string == '^')
- {
- call0 (Qhandle_shift_selection);
- string++;
- }
+ call0 (Qhandle_shift_selection);
else break;
}
/* Count the number of arguments, which is two (the function itself and
`funcall-interactively') plus the number of arguments the interactive spec
would have us give to the function. */
- tem = string;
- for (nargs = 2; *tem; )
+ ptrdiff_t nargs = 2;
+ for (char const *tem = string; tem < string_end; tem++)
{
/* 'r' specifications ("point and mark as 2 numeric args")
produce *two* arguments. */
- if (*tem == 'r')
- nargs += 2;
- else
- nargs++;
- tem = strchr (tem, '\n');
- if (tem)
- ++tem;
- else
+ nargs += 1 + (*tem == 'r');
+ tem = memchr (tem, '\n', string_len - (tem - string));
+ if (!tem)
break;
}
@@ -487,22 +427,32 @@ invoke it. If KEYS is omitted or nil, the return value of
&& MOST_POSITIVE_FIXNUM < nargs)
memory_full (SIZE_MAX);
- /* Allocate them all at one go. This wastes a bit of memory, but
+ /* ARGS will contain the array of arguments to pass to the function.
+ VISARGS will contain the same list but in a nicer form, so that if we
+ pass it to Fformat_message it will be understandable to a human.
+ Allocate them all at one go. This wastes a bit of memory, but
it's OK to trade space for speed. */
+ Lisp_Object *args;
SAFE_NALLOCA (args, 3, nargs);
- visargs = args + nargs;
- varies = (signed char *) (visargs + nargs);
+ Lisp_Object *visargs = args + nargs;
+ /* If varies[I] > 0, the Ith argument shouldn't just have its value
+ in this call quoted in the command history. It should be
+ recorded as a call to the function named callint_argfuns[varies[I]]. */
+ signed char *varies = (signed char *) (visargs + nargs);
memclear (args, nargs * (2 * word_size + 1));
if (!NILP (enable))
specbind (Qenable_recursive_minibuffers, Qt);
- tem = string;
- for (i = 2; *tem; i++)
+ char const *tem = string;
+ for (ptrdiff_t i = 2; tem < string_end; i++)
{
- visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n"));
- callint_message = styled_format (i - 1, visargs + 1, true, false);
+ char *pnl = memchr (tem + 1, '\n', string_len - (tem + 1 - string));
+ ptrdiff_t sz = pnl ? pnl - (tem + 1) : string_end - (tem + 1);
+
+ visargs[1] = make_string (tem + 1, sz);
+ callint_message = Fformat_message (i - 1, visargs + 1);
switch (*tem)
{
@@ -510,45 +460,41 @@ invoke it. If KEYS is omitted or nil, the return value of
visargs[i] = Fcompleting_read (callint_message,
Vobarray, Qfboundp, Qt,
Qnil, Qnil, Qnil, Qnil);
- /* Passing args[i] directly stimulates compiler bug. */
- teml = visargs[i];
- args[i] = Fintern (teml, Qnil);
+ args[i] = Fintern (visargs[i], Qnil);
break;
case 'b': /* Name of existing buffer. */
args[i] = Fcurrent_buffer ();
- if (EQ (selected_window, minibuf_window))
+ if (BASE_EQ (selected_window, minibuf_window))
args[i] = Fother_buffer (args[i], Qnil, Qnil);
args[i] = Fread_buffer (callint_message, args[i], Qt, Qnil);
break;
case 'B': /* Name of buffer, possibly nonexistent. */
args[i] = Fread_buffer (callint_message,
- Fother_buffer (Fcurrent_buffer (), Qnil, Qnil),
+ Fother_buffer (Fcurrent_buffer (),
+ Qnil, Qnil),
Qnil, Qnil);
break;
case 'c': /* Character. */
/* Prompt in `minibuffer-prompt' face. */
- Fput_text_property (make_number (0),
- make_number (SCHARS (callint_message)),
+ Fput_text_property (make_fixnum (0),
+ make_fixnum (SCHARS (callint_message)),
Qface, Qminibuffer_prompt, callint_message);
args[i] = Fread_char (callint_message, Qnil, Qnil);
message1_nolog (0);
- /* Passing args[i] directly stimulates compiler bug. */
- teml = args[i];
/* See bug#8479. */
- if (! CHARACTERP (teml)) error ("Non-character input-event");
- visargs[i] = Fchar_to_string (teml);
+ if (! CHARACTERP (args[i]))
+ error ("Non-character input-event");
+ visargs[i] = Fchar_to_string (args[i]);
break;
case 'C': /* Command: symbol with interactive function. */
visargs[i] = Fcompleting_read (callint_message,
Vobarray, Qcommandp,
Qt, Qnil, Qnil, Qnil, Qnil);
- /* Passing args[i] directly stimulates compiler bug. */
- teml = visargs[i];
- args[i] = Fintern (teml, Qnil);
+ args[i] = Fintern (visargs[i], Qnil);
break;
case 'd': /* Value of point. Does not do I/O. */
@@ -559,8 +505,8 @@ invoke it. If KEYS is omitted or nil, the return value of
break;
case 'D': /* Directory name. */
- args[i] = read_file_name (BVAR (current_buffer, directory), Qlambda, Qnil,
- Qfile_directory_p);
+ args[i] = read_file_name (BVAR (current_buffer, directory), Qlambda,
+ Qnil, Qfile_directory_p);
break;
case 'f': /* Existing file name. */
@@ -582,30 +528,28 @@ invoke it. If KEYS is omitted or nil, the return value of
case 'k': /* Key sequence. */
{
- ptrdiff_t speccount1 = SPECPDL_INDEX ();
+ specpdl_ref speccount1 = SPECPDL_INDEX ();
specbind (Qcursor_in_echo_area, Qt);
/* Prompt in `minibuffer-prompt' face. */
- Fput_text_property (make_number (0),
- make_number (SCHARS (callint_message)),
+ Fput_text_property (make_fixnum (0),
+ make_fixnum (SCHARS (callint_message)),
Qface, Qminibuffer_prompt, callint_message);
args[i] = Fread_key_sequence (callint_message,
Qnil, Qnil, Qnil, Qnil);
unbind_to (speccount1, Qnil);
- teml = args[i];
- visargs[i] = Fkey_description (teml, Qnil);
+ visargs[i] = Fkey_description (args[i], Qnil);
/* If the key sequence ends with a down-event,
discard the following up-event. */
- teml = Faref (args[i], make_number (XINT (Flength (args[i])) - 1));
+ Lisp_Object teml
+ = Faref (args[i], make_fixnum (XFIXNUM (Flength (args[i])) - 1));
if (CONSP (teml))
teml = XCAR (teml);
if (SYMBOLP (teml))
{
- Lisp_Object tem2;
-
teml = Fget (teml, Qevent_symbol_elements);
/* Ignore first element, which is the base key. */
- tem2 = Fmemq (Qdown, Fcdr (teml));
+ Lisp_Object tem2 = Fmemq (Qdown, Fcdr (teml));
if (! NILP (tem2))
up_event = Fread_event (Qnil, Qnil, Qnil);
}
@@ -614,30 +558,28 @@ invoke it. If KEYS is omitted or nil, the return value of
case 'K': /* Key sequence to be defined. */
{
- ptrdiff_t speccount1 = SPECPDL_INDEX ();
+ specpdl_ref speccount1 = SPECPDL_INDEX ();
specbind (Qcursor_in_echo_area, Qt);
/* Prompt in `minibuffer-prompt' face. */
- Fput_text_property (make_number (0),
- make_number (SCHARS (callint_message)),
+ Fput_text_property (make_fixnum (0),
+ make_fixnum (SCHARS (callint_message)),
Qface, Qminibuffer_prompt, callint_message);
args[i] = Fread_key_sequence_vector (callint_message,
Qnil, Qt, Qnil, Qnil);
- teml = args[i];
- visargs[i] = Fkey_description (teml, Qnil);
+ visargs[i] = Fkey_description (args[i], Qnil);
unbind_to (speccount1, Qnil);
/* If the key sequence ends with a down-event,
discard the following up-event. */
- teml = Faref (args[i], make_number (XINT (Flength (args[i])) - 1));
+ Lisp_Object teml
+ = Faref (args[i], make_fixnum (ASIZE (args[i]) - 1));
if (CONSP (teml))
teml = XCAR (teml);
if (SYMBOLP (teml))
{
- Lisp_Object tem2;
-
teml = Fget (teml, Qevent_symbol_elements);
/* Ignore first element, which is the base key. */
- tem2 = Fmemq (Qdown, Fcdr (teml));
+ Lisp_Object tem2 = Fmemq (Qdown, Fcdr (teml));
if (! NILP (tem2))
up_event = Fread_event (Qnil, Qnil, Qnil);
}
@@ -647,10 +589,9 @@ invoke it. If KEYS is omitted or nil, the return value of
case 'U': /* Up event from last k or K. */
if (!NILP (up_event))
{
- args[i] = Fmake_vector (make_number (1), up_event);
+ args[i] = make_vector (1, up_event);
up_event = Qnil;
- teml = args[i];
- visargs[i] = Fkey_description (teml, Qnil);
+ visargs[i] = Fkey_description (args[i], Qnil);
}
break;
@@ -661,18 +602,22 @@ invoke it. If KEYS is omitted or nil, the return value of
? SSDATA (SYMBOL_NAME (function))
: "command"));
args[i] = AREF (keys, next_event);
- next_event++;
varies[i] = -1;
- /* Find the next parameterized event. */
- while (next_event < key_count
- && !(EVENT_HAS_PARAMETERS (AREF (keys, next_event))))
+ /* `inhibit_mouse_event_check' allows non-parameterized events. */
+ if (inhibit_mouse_event_check)
next_event++;
+ else
+ /* Find the next parameterized event. */
+ do
+ next_event++;
+ while (next_event < key_count
+ && ! EVENT_HAS_PARAMETERS (AREF (keys, next_event)));
break;
case 'm': /* Value of mark. Does not do I/O. */
- check_mark (0);
+ check_mark (false);
/* visargs[i] = Qnil; */
args[i] = BVAR (current_buffer, mark);
varies[i] = 2;
@@ -690,9 +635,7 @@ invoke it. If KEYS is omitted or nil, the return value of
FALLTHROUGH;
case 'n': /* Read number from minibuffer. */
args[i] = call1 (Qread_number, callint_message);
- /* Passing args[i] directly stimulates compiler bug. */
- teml = args[i];
- visargs[i] = Fnumber_to_string (teml);
+ visargs[i] = Fnumber_to_string (args[i]);
break;
case 'P': /* Prefix arg in raw form. Does no I/O. */
@@ -709,15 +652,16 @@ invoke it. If KEYS is omitted or nil, the return value of
break;
case 'r': /* Region, point and mark as 2 args. */
- check_mark (1);
- set_marker_both (point_marker, Qnil, PT, PT_BYTE);
- /* visargs[i+1] = Qnil; */
- mark = marker_position (BVAR (current_buffer, mark));
- /* visargs[i] = Qnil; */
- args[i] = PT < mark ? point_marker : BVAR (current_buffer, mark);
- varies[i] = 3;
- args[++i] = PT > mark ? point_marker : BVAR (current_buffer, mark);
- varies[i] = 4;
+ {
+ check_mark (true);
+ set_marker_both (point_marker, Qnil, PT, PT_BYTE);
+ ptrdiff_t mark = marker_position (BVAR (current_buffer, mark));
+ /* visargs[i] = visargs[i + 1] = Qnil; */
+ args[i] = PT < mark ? point_marker : BVAR (current_buffer, mark);
+ varies[i] = 3;
+ args[++i] = PT > mark ? point_marker : BVAR (current_buffer, mark);
+ varies[i] = 4;
+ }
break;
case 's': /* String read via minibuffer without
@@ -729,9 +673,7 @@ invoke it. If KEYS is omitted or nil, the return value of
case 'S': /* Any symbol. */
visargs[i] = Fread_string (callint_message,
Qnil, Qnil, Qnil, Qnil);
- /* Passing args[i] directly stimulates compiler bug. */
- teml = visargs[i];
- args[i] = Fintern (teml, Qnil);
+ args[i] = Fintern (visargs[i], Qnil);
break;
case 'v': /* Variable name: symbol that is
@@ -774,21 +716,35 @@ invoke it. If KEYS is omitted or nil, the return value of
if anyone tries to define one here. */
case '+':
default:
- error ("Invalid control letter `%c' (#o%03o, #x%04x) in interactive calling string",
- STRING_CHAR ((unsigned char *) tem),
- (unsigned) STRING_CHAR ((unsigned char *) tem),
- (unsigned) STRING_CHAR ((unsigned char *) tem));
+ {
+ /* How many bytes are left unprocessed in the specs string?
+ (Note that this excludes the trailing null byte.) */
+ ptrdiff_t bytes_left = string_len - (tem - string);
+ unsigned letter;
+
+ /* If we have enough bytes left to treat the sequence as a
+ character, show that character's codepoint; otherwise
+ show only its first byte. */
+ if (bytes_left >= BYTES_BY_CHAR_HEAD (*((unsigned char *) tem)))
+ letter = STRING_CHAR ((unsigned char *) tem);
+ else
+ letter = *((unsigned char *) tem);
+
+ error (("Invalid control letter `%c' (#o%03o, #x%04x)"
+ " in interactive calling string"),
+ (int) letter, letter, letter);
+ }
}
if (varies[i] == 0)
- arg_from_tty = 1;
+ arg_from_tty = true;
if (NILP (visargs[i]) && STRINGP (args[i]))
visargs[i] = args[i];
- tem = strchr (tem, '\n');
+ tem = memchr (tem, '\n', string_len - (tem - string));
if (tem) tem++;
- else tem = "";
+ else tem = string_end;
}
unbind_to (speccount, Qnil);
@@ -802,27 +758,17 @@ invoke it. If KEYS is omitted or nil, the return value of
/* We don't need `visargs' any more, so let's recycle it since we need
an array of just the same size. */
visargs[1] = function;
- for (i = 2; i < nargs; i++)
- {
- if (varies[i] > 0)
- visargs[i] = list1 (intern (callint_argfuns[varies[i]]));
- else
- visargs[i] = quotify_arg (args[i]);
- }
- Vcommand_history = Fcons (Flist (nargs - 1, visargs + 1),
- Vcommand_history);
- /* Don't keep command history around forever. */
- if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0)
- {
- teml = Fnthcdr (Vhistory_length, Vcommand_history);
- if (CONSP (teml))
- XSETCDR (teml, Qnil);
- }
+ for (ptrdiff_t i = 2; i < nargs; i++)
+ visargs[i] = (varies[i] > 0
+ ? list1 (intern (callint_argfuns[varies[i]]))
+ : quotify_arg (args[i]));
+ call4 (intern ("add-to-history"), intern ("command-history"),
+ Flist (nargs - 1, visargs + 1), Qnil, Qt);
}
/* If we used a marker to hold point, mark, or an end of the region,
temporarily, convert it to an integer now. */
- for (i = 2; i < nargs; i++)
+ for (ptrdiff_t i = 2; i < nargs; i++)
if (varies[i] >= 1 && varies[i] <= 4)
XSETINT (args[i], marker_position (args[i]));
@@ -834,15 +780,10 @@ invoke it. If KEYS is omitted or nil, the return value of
Vreal_this_command = save_real_this_command;
kset_last_command (current_kboard, save_last_command);
- {
- Lisp_Object val;
- specbind (Qcommand_debug_status, Qnil);
+ specbind (Qcommand_debug_status, Qnil);
- val = Ffuncall (nargs, args);
- val = unbind_to (speccount, val);
- SAFE_FREE ();
- return val;
- }
+ Lisp_Object val = Ffuncall (nargs, args);
+ return SAFE_FREE_UNBIND_TO (speccount, val);
}
DEFUN ("prefix-numeric-value", Fprefix_numeric_value, Sprefix_numeric_value,
@@ -858,9 +799,9 @@ Its numeric meaning is what you would get from `(interactive "p")'. */)
XSETFASTINT (val, 1);
else if (EQ (raw, Qminus))
XSETINT (val, -1);
- else if (CONSP (raw) && INTEGERP (XCAR (raw)))
- XSETINT (val, XINT (XCAR (raw)));
- else if (INTEGERP (raw))
+ else if (CONSP (raw) && FIXNUMP (XCAR (raw)))
+ val = XCAR (raw);
+ else if (FIXNUMP (raw))
val = raw;
else
XSETFASTINT (val, 1);
@@ -877,11 +818,11 @@ syms_of_callint (void)
callint_message = Qnil;
staticpro (&callint_message);
- preserved_fns = listn (CONSTYPE_PURE, 4,
- intern_c_string ("region-beginning"),
- intern_c_string ("region-end"),
- intern_c_string ("point"),
- intern_c_string ("mark"));
+ preserved_fns = pure_list (intern_c_string ("region-beginning"),
+ intern_c_string ("region-end"),
+ intern_c_string ("point"),
+ intern_c_string ("mark"));
+ staticpro (&preserved_fns);
DEFSYM (Qlist, "list");
DEFSYM (Qlet, "let");
@@ -945,13 +886,26 @@ behave as if the mark were still active. */);
Vmark_even_if_inactive = Qt;
DEFVAR_LISP ("mouse-leave-buffer-hook", Vmouse_leave_buffer_hook,
- doc: /* Hook to run when about to switch windows with a mouse command.
+ doc: /* Hook run when the user mouse-clicks in a window.
+It can be run both before and after switching windows, or even when
+not actually switching windows.
+
Its purpose is to give temporary modes such as Isearch mode
a way to turn themselves off when a mouse command switches windows. */);
Vmouse_leave_buffer_hook = Qnil;
+ DEFVAR_BOOL ("inhibit-mouse-event-check", inhibit_mouse_event_check,
+ doc: /* Whether the interactive spec "e" requires a mouse gesture event.
+If non-nil, `(interactive "e")' doesn't signal an error when the command
+was invoked by an input event that is not a mouse gesture: a click, a drag,
+etc. To create the event data when the input was some other event,
+use `event-start', `event-end', and `event-click-count'. */);
+ inhibit_mouse_event_check = false;
+
defsubr (&Sinteractive);
defsubr (&Scall_interactively);
defsubr (&Sfuncall_interactively);
defsubr (&Sprefix_numeric_value);
+
+ DEFSYM (Qinteractive_args, "interactive-args");
}