This source file includes following definitions.
- DEFUN
- quotify_arg
- quotify_args
- check_mark
- fix_command
- read_file_name
- DEFUN
- syms_of_callint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <config.h>
22
23 #include "lisp.h"
24 #include "character.h"
25 #include "buffer.h"
26 #include "keyboard.h"
27 #include "window.h"
28
29 static Lisp_Object preserved_fns;
30
31
32 static Lisp_Object point_marker;
33
34
35 static Lisp_Object callint_message;
36
37 DEFUN ("interactive", Finteractive, Sinteractive, 0, UNEVALLED, 0,
38 doc:
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 attributes: const)
118 (Lisp_Object args)
119 {
120 return Qnil;
121 }
122
123
124
125 static Lisp_Object
126 quotify_arg (register Lisp_Object exp)
127 {
128 if (CONSP (exp)
129 || (SYMBOLP (exp)
130 && !NILP (exp) && !EQ (exp, Qt)))
131 return list2 (Qquote, exp);
132
133 return exp;
134 }
135
136
137 static Lisp_Object
138 quotify_args (Lisp_Object exp)
139 {
140 register Lisp_Object tail;
141 Lisp_Object next;
142 for (tail = exp; CONSP (tail); tail = next)
143 {
144 next = XCDR (tail);
145 XSETCAR (tail, quotify_arg (XCAR (tail)));
146 }
147 return exp;
148 }
149
150 static const char *callint_argfuns[]
151 = {"", "point", "mark", "region-beginning", "region-end"};
152
153 static void
154 check_mark (bool for_region)
155 {
156 Lisp_Object tem;
157 tem = Fmarker_buffer (BVAR (current_buffer, mark));
158 if (NILP (tem) || (XBUFFER (tem) != current_buffer))
159 error (for_region ? "The mark is not set now, so there is no region"
160 : "The mark is not set now");
161 if (!NILP (Vtransient_mark_mode) && NILP (Vmark_even_if_inactive)
162 && NILP (BVAR (current_buffer, mark_active)))
163 xsignal0 (Qmark_inactive);
164 }
165
166
167
168
169
170
171
172 static void
173 fix_command (Lisp_Object function, Lisp_Object values)
174 {
175
176 if (!CONSP (values) || !SYMBOLP (function))
177 return;
178
179 Lisp_Object reps = Fget (function, Qinteractive_args);
180
181 if (CONSP (reps))
182 {
183 int i = 0;
184 Lisp_Object vals = values;
185
186 while (!NILP (vals))
187 {
188 Lisp_Object rep = Fassq (make_fixnum (i), reps);
189 if (!NILP (rep))
190 Fsetcar (vals, XCDR (rep));
191 vals = XCDR (vals);
192 ++i;
193 }
194 }
195
196
197
198
199
200 Lisp_Object arity = Ffunc_arity (function);
201
202
203
204 if (FIXNUMP (XCAR (arity)) && FIXNUMP (XCDR (arity)))
205 {
206 Lisp_Object final = Qnil;
207 ptrdiff_t final_i = 0, i = 0;
208 for (Lisp_Object tail = values;
209 CONSP (tail);
210 tail = XCDR (tail), ++i)
211 {
212 if (!NILP (XCAR (tail)))
213 {
214 final = tail;
215 final_i = i;
216 }
217 }
218
219
220 if (final_i > 0 && final_i >= XFIXNUM (XCAR (arity)) - 1)
221 XSETCDR (final, Qnil);
222 }
223 }
224
225
226
227 static Lisp_Object
228 read_file_name (Lisp_Object default_filename, Lisp_Object mustmatch,
229 Lisp_Object initial, Lisp_Object predicate)
230 {
231 return CALLN (Ffuncall, intern ("read-file-name"),
232 callint_message, Qnil, default_filename,
233 mustmatch, initial, predicate);
234 }
235
236
237 DEFUN ("funcall-interactively", Ffuncall_interactively, Sfuncall_interactively,
238 1, MANY, 0, doc:
239
240
241 )
242 (ptrdiff_t nargs, Lisp_Object *args)
243 {
244 specpdl_ref speccount = SPECPDL_INDEX ();
245 temporarily_switch_to_single_kboard (NULL);
246
247
248
249
250 return unbind_to (speccount, Ffuncall (nargs, args));
251 }
252
253 DEFUN ("call-interactively", Fcall_interactively, Scall_interactively, 1, 3, 0,
254 doc:
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269 )
270 (Lisp_Object function, Lisp_Object record_flag, Lisp_Object keys)
271 {
272 specpdl_ref speccount = SPECPDL_INDEX ();
273
274 bool arg_from_tty = false;
275 ptrdiff_t key_count;
276 bool record_then_fail = false;
277
278 Lisp_Object save_this_command = Vthis_command;
279 Lisp_Object save_this_original_command = Vthis_original_command;
280 Lisp_Object save_real_this_command = Vreal_this_command;
281 Lisp_Object save_last_command = KVAR (current_kboard, Vlast_command);
282
283
284
285
286 specbind (Qcurrent_minibuffer_command, Vthis_command);
287
288 if (NILP (keys))
289 keys = this_command_keys, key_count = this_command_key_count;
290 else
291 {
292 CHECK_VECTOR (keys);
293 key_count = ASIZE (keys);
294 }
295
296
297 Lisp_Object prefix_arg = Vcurrent_prefix_arg;
298
299 Lisp_Object enable = (SYMBOLP (function)
300 ? Fget (function, Qenable_recursive_minibuffers)
301 : Qnil);
302
303
304
305 Lisp_Object up_event = Qnil;
306
307
308 Lisp_Object form = call1 (Qinteractive_form, function);
309 if (! CONSP (form))
310 wrong_type_argument (Qcommandp, function);
311 Lisp_Object specs = Fcar (XCDR (form));
312
313
314
315
316
317
318 if (! STRINGP (specs))
319 {
320 Lisp_Object funval = Findirect_function (function, Qt);
321 uintmax_t events = num_input_events;
322
323 specs = Feval (specs,
324 CONSP (funval) && EQ (Qclosure, XCAR (funval))
325 ? CAR_SAFE (XCDR (funval)) : Qnil);
326 if (events != num_input_events || !NILP (record_flag))
327 {
328
329
330
331 Lisp_Object values = quotify_args (Fcopy_sequence (specs));
332 fix_command (function, values);
333 call4 (intern ("add-to-history"), intern ("command-history"),
334 Fcons (function, values), Qnil, Qt);
335 }
336
337 Vthis_command = save_this_command;
338 Vthis_original_command = save_this_original_command;
339 Vreal_this_command = save_real_this_command;
340 kset_last_command (current_kboard, save_last_command);
341
342 return unbind_to (speccount, CALLN (Fapply, Qfuncall_interactively,
343 function, specs));
344 }
345
346
347
348 USE_SAFE_ALLOCA;
349 ptrdiff_t string_len = SBYTES (specs);
350 char *string = SAFE_ALLOCA (string_len + 1);
351 memcpy (string, SDATA (specs), string_len + 1);
352 char *string_end = string + string_len;
353
354
355
356
357
358
359 ptrdiff_t next_event = 0;
360 if (!inhibit_mouse_event_check)
361 for (; next_event < key_count; next_event++)
362 if (EVENT_HAS_PARAMETERS (AREF (keys, next_event)))
363 break;
364
365
366
367 for (;; string++)
368 {
369 if (*string == '+')
370 error ("`+' is not used in `interactive' for ordinary commands");
371 else if (*string == '*')
372 {
373 if (!NILP (BVAR (current_buffer, read_only)))
374 {
375 if (!NILP (record_flag))
376 {
377 for (char *p = string + 1; p < string_end; p++)
378 if (! (*p == 'r' || *p == 'p' || *p == 'P' || *p == '\n'))
379 Fbarf_if_buffer_read_only (Qnil);
380 record_then_fail = true;
381 }
382 else
383 Fbarf_if_buffer_read_only (Qnil);
384 }
385 }
386
387 else if (*string == '-')
388 ;
389 else if (*string == '@')
390 {
391 Lisp_Object w, event = (next_event < key_count
392 ? AREF (keys, next_event)
393 : Qnil);
394 if (EVENT_HAS_PARAMETERS (event)
395 && (w = XCDR (event), CONSP (w))
396 && (w = XCAR (w), CONSP (w))
397 && (w = XCAR (w), WINDOWP (w)))
398 {
399 if (MINI_WINDOW_P (XWINDOW (w))
400 && ! (minibuf_level > 0 && BASE_EQ (w, minibuf_window)))
401 error ("Attempt to select inactive minibuffer window");
402
403
404 run_hook (Qmouse_leave_buffer_hook);
405
406 Fselect_window (w, Qnil);
407 }
408 }
409 else if (*string == '^')
410 call0 (Qhandle_shift_selection);
411 else break;
412 }
413
414
415
416
417 ptrdiff_t nargs = 2;
418 for (char const *tem = string; tem < string_end; tem++)
419 {
420
421
422 nargs += 1 + (*tem == 'r');
423 tem = memchr (tem, '\n', string_len - (tem - string));
424 if (!tem)
425 break;
426 }
427
428 if (MOST_POSITIVE_FIXNUM < min (PTRDIFF_MAX, SIZE_MAX) / word_size
429 && MOST_POSITIVE_FIXNUM < nargs)
430 memory_full (SIZE_MAX);
431
432
433
434
435
436
437 Lisp_Object *args;
438 SAFE_NALLOCA (args, 3, nargs);
439 Lisp_Object *visargs = args + nargs;
440
441
442
443 signed char *varies = (signed char *) (visargs + nargs);
444
445 memclear (args, nargs * (2 * word_size + 1));
446
447 if (!NILP (enable))
448 specbind (Qenable_recursive_minibuffers, Qt);
449
450 char const *tem = string;
451 for (ptrdiff_t i = 2; tem < string_end; i++)
452 {
453 char *pnl = memchr (tem + 1, '\n', string_len - (tem + 1 - string));
454 ptrdiff_t sz = pnl ? pnl - (tem + 1) : string_end - (tem + 1);
455
456 visargs[1] = make_string (tem + 1, sz);
457 callint_message = Fformat_message (i - 1, visargs + 1);
458
459 switch (*tem)
460 {
461 case 'a':
462 visargs[i] = Fcompleting_read (callint_message,
463 Vobarray, Qfboundp, Qt,
464 Qnil, Qnil, Qnil, Qnil);
465 args[i] = Fintern (visargs[i], Qnil);
466 break;
467
468 case 'b':
469 args[i] = Fcurrent_buffer ();
470 if (BASE_EQ (selected_window, minibuf_window))
471 args[i] = Fother_buffer (args[i], Qnil, Qnil);
472 args[i] = Fread_buffer (callint_message, args[i], Qt, Qnil);
473 break;
474
475 case 'B':
476 args[i] = Fread_buffer (callint_message,
477 Fother_buffer (Fcurrent_buffer (),
478 Qnil, Qnil),
479 Qnil, Qnil);
480 break;
481
482 case 'c':
483
484 Fput_text_property (make_fixnum (0),
485 make_fixnum (SCHARS (callint_message)),
486 Qface, Qminibuffer_prompt, callint_message);
487 args[i] = Fread_char (callint_message, Qnil, Qnil);
488 message1_nolog (0);
489
490 if (! CHARACTERP (args[i]))
491 error ("Non-character input-event");
492 visargs[i] = Fchar_to_string (args[i]);
493 break;
494
495 case 'C':
496 visargs[i] = Fcompleting_read (callint_message,
497 Vobarray, Qcommandp,
498 Qt, Qnil, Qnil, Qnil, Qnil);
499 args[i] = Fintern (visargs[i], Qnil);
500 break;
501
502 case 'd':
503 set_marker_both (point_marker, Qnil, PT, PT_BYTE);
504 args[i] = point_marker;
505
506 varies[i] = 1;
507 break;
508
509 case 'D':
510 args[i] = read_file_name (BVAR (current_buffer, directory), Qlambda,
511 Qnil, Qfile_directory_p);
512 break;
513
514 case 'f':
515 args[i] = read_file_name (Qnil, Qlambda, Qnil, Qnil);
516 break;
517
518 case 'F':
519 args[i] = read_file_name (Qnil, Qnil, Qnil, Qnil);
520 break;
521
522 case 'G':
523
524 args[i] = read_file_name (Qnil, Qnil, empty_unibyte_string, Qnil);
525 break;
526
527 case 'i':
528 varies[i] = -1;
529 break;
530
531 case 'k':
532 {
533 specpdl_ref speccount1 = SPECPDL_INDEX ();
534 specbind (Qcursor_in_echo_area, Qt);
535
536 Fput_text_property (make_fixnum (0),
537 make_fixnum (SCHARS (callint_message)),
538 Qface, Qminibuffer_prompt, callint_message);
539 args[i] = Fread_key_sequence (callint_message,
540 Qnil, Qnil, Qnil, Qnil,
541 Qnil);
542 unbind_to (speccount1, Qnil);
543 visargs[i] = Fkey_description (args[i], Qnil);
544
545
546
547 Lisp_Object teml
548 = Faref (args[i], make_fixnum (XFIXNUM (Flength (args[i])) - 1));
549 if (CONSP (teml))
550 teml = XCAR (teml);
551 if (SYMBOLP (teml))
552 {
553 teml = Fget (teml, Qevent_symbol_elements);
554
555 Lisp_Object tem2 = Fmemq (Qdown, Fcdr (teml));
556 if (! NILP (tem2))
557 up_event = Fread_event (Qnil, Qnil, Qnil);
558 }
559 }
560 break;
561
562 case 'K':
563 {
564 specpdl_ref speccount1 = SPECPDL_INDEX ();
565 specbind (Qcursor_in_echo_area, Qt);
566
567 Fput_text_property (make_fixnum (0),
568 make_fixnum (SCHARS (callint_message)),
569 Qface, Qminibuffer_prompt, callint_message);
570 args[i] = Fread_key_sequence_vector (callint_message,
571 Qnil, Qt, Qnil, Qnil,
572 Qnil);
573 visargs[i] = Fkey_description (args[i], Qnil);
574 unbind_to (speccount1, Qnil);
575
576
577
578 Lisp_Object teml
579 = Faref (args[i], make_fixnum (ASIZE (args[i]) - 1));
580 if (CONSP (teml))
581 teml = XCAR (teml);
582 if (SYMBOLP (teml))
583 {
584 teml = Fget (teml, Qevent_symbol_elements);
585
586 Lisp_Object tem2 = Fmemq (Qdown, Fcdr (teml));
587 if (! NILP (tem2))
588 up_event = Fread_event (Qnil, Qnil, Qnil);
589 }
590 }
591 break;
592
593 case 'U':
594 if (!NILP (up_event))
595 {
596 args[i] = make_vector (1, up_event);
597 up_event = Qnil;
598 visargs[i] = Fkey_description (args[i], Qnil);
599 }
600 break;
601
602 case 'e':
603 if (next_event >= key_count)
604 error ("%s must be bound to an event with parameters",
605 (SYMBOLP (function)
606 ? SSDATA (SYMBOL_NAME (function))
607 : "command"));
608 args[i] = AREF (keys, next_event);
609 varies[i] = -1;
610
611
612 if (inhibit_mouse_event_check)
613 next_event++;
614 else
615
616 do
617 next_event++;
618 while (next_event < key_count
619 && ! EVENT_HAS_PARAMETERS (AREF (keys, next_event)));
620
621 break;
622
623 case 'm':
624 check_mark (false);
625
626 args[i] = BVAR (current_buffer, mark);
627 varies[i] = 2;
628 break;
629
630 case 'M':
631
632 args[i] = Fread_string (callint_message,
633 Qnil, Qnil, Qnil, Qt);
634 break;
635
636 case 'N':
637 if (!NILP (prefix_arg))
638 goto have_prefix_arg;
639 FALLTHROUGH;
640 case 'n':
641 args[i] = call1 (Qread_number, callint_message);
642 visargs[i] = Fnumber_to_string (args[i]);
643 break;
644
645 case 'P':
646 args[i] = prefix_arg;
647
648 varies[i] = -1;
649 break;
650
651 case 'p':
652 have_prefix_arg:
653 args[i] = Fprefix_numeric_value (prefix_arg);
654
655 varies[i] = -1;
656 break;
657
658 case 'r':
659 {
660 check_mark (true);
661 set_marker_both (point_marker, Qnil, PT, PT_BYTE);
662 ptrdiff_t mark = marker_position (BVAR (current_buffer, mark));
663
664 args[i] = PT < mark ? point_marker : BVAR (current_buffer, mark);
665 varies[i] = 3;
666 args[++i] = PT > mark ? point_marker : BVAR (current_buffer, mark);
667 varies[i] = 4;
668 }
669 break;
670
671 case 's':
672
673 args[i] = Fread_string (callint_message,
674 Qnil, Qnil, Qnil, Qnil);
675 break;
676
677 case 'S':
678 visargs[i] = Fread_string (callint_message,
679 Qnil, Qnil, Qnil, Qnil);
680 args[i] = Fintern (visargs[i], Qnil);
681 break;
682
683 case 'v':
684
685 args[i] = Fread_variable (callint_message, Qnil);
686 visargs[i] = last_minibuf_string;
687 break;
688
689 case 'x':
690 args[i] = call1 (intern ("read-minibuffer"), callint_message);
691 visargs[i] = last_minibuf_string;
692 break;
693
694 case 'X':
695 args[i] = call1 (intern ("eval-minibuffer"), callint_message);
696 visargs[i] = last_minibuf_string;
697 break;
698
699 case 'Z':
700
701 if (NILP (prefix_arg))
702 {
703
704 varies[i] = -1;
705 }
706 else
707 {
708 args[i]
709 = Fread_non_nil_coding_system (callint_message);
710 visargs[i] = last_minibuf_string;
711 }
712 break;
713
714 case 'z':
715 args[i] = Fread_coding_system (callint_message, Qnil);
716 visargs[i] = last_minibuf_string;
717 break;
718
719
720
721 case '+':
722 default:
723 {
724
725
726 ptrdiff_t bytes_left = string_len - (tem - string);
727 unsigned letter;
728
729
730
731
732 if (bytes_left >= BYTES_BY_CHAR_HEAD (*((unsigned char *) tem)))
733 letter = STRING_CHAR ((unsigned char *) tem);
734 else
735 letter = *((unsigned char *) tem);
736
737 error (("Invalid control letter `%c' (#o%03o, #x%04x)"
738 " in interactive calling string"),
739 (int) letter, letter, letter);
740 }
741 }
742
743 if (varies[i] == 0)
744 arg_from_tty = true;
745
746 if (NILP (visargs[i]) && STRINGP (args[i]))
747 visargs[i] = args[i];
748
749 tem = memchr (tem, '\n', string_len - (tem - string));
750 if (tem) tem++;
751 else tem = string_end;
752 }
753 unbind_to (speccount, Qnil);
754
755 maybe_quit ();
756
757 args[0] = Qfuncall_interactively;
758 args[1] = function;
759
760 if (arg_from_tty || !NILP (record_flag))
761 {
762
763
764 visargs[1] = function;
765 for (ptrdiff_t i = 2; i < nargs; i++)
766 visargs[i] = (varies[i] > 0
767 ? list1 (intern (callint_argfuns[varies[i]]))
768 : quotify_arg (args[i]));
769 call4 (intern ("add-to-history"), intern ("command-history"),
770 Flist (nargs - 1, visargs + 1), Qnil, Qt);
771 }
772
773
774
775 for (ptrdiff_t i = 2; i < nargs; i++)
776 if (varies[i] >= 1 && varies[i] <= 4)
777 XSETINT (args[i], marker_position (args[i]));
778
779 if (record_then_fail)
780 Fbarf_if_buffer_read_only (Qnil);
781
782 Vthis_command = save_this_command;
783 Vthis_original_command = save_this_original_command;
784 Vreal_this_command = save_real_this_command;
785 kset_last_command (current_kboard, save_last_command);
786
787 specbind (Qcommand_debug_status, Qnil);
788
789 Lisp_Object val = Ffuncall (nargs, args);
790 return SAFE_FREE_UNBIND_TO (speccount, val);
791 }
792
793 DEFUN ("prefix-numeric-value", Fprefix_numeric_value, Sprefix_numeric_value,
794 1, 1, 0,
795 doc:
796
797 )
798 (Lisp_Object raw)
799 {
800 Lisp_Object val;
801
802 if (NILP (raw))
803 XSETFASTINT (val, 1);
804 else if (EQ (raw, Qminus))
805 XSETINT (val, -1);
806 else if (CONSP (raw) && FIXNUMP (XCAR (raw)))
807 val = XCAR (raw);
808 else if (FIXNUMP (raw))
809 val = raw;
810 else
811 XSETFASTINT (val, 1);
812
813 return val;
814 }
815
816 void
817 syms_of_callint (void)
818 {
819 point_marker = Fmake_marker ();
820 staticpro (&point_marker);
821
822 callint_message = Qnil;
823 staticpro (&callint_message);
824
825 preserved_fns = pure_list (intern_c_string ("region-beginning"),
826 intern_c_string ("region-end"),
827 intern_c_string ("point"),
828 intern_c_string ("mark"));
829 staticpro (&preserved_fns);
830
831 DEFSYM (Qlist, "list");
832 DEFSYM (Qlet, "let");
833 DEFSYM (Qif, "if");
834 DEFSYM (Qwhen, "when");
835 DEFSYM (Qletx, "let*");
836 DEFSYM (Qsave_excursion, "save-excursion");
837 DEFSYM (Qprogn, "progn");
838 DEFSYM (Qminus, "-");
839 DEFSYM (Qplus, "+");
840 DEFSYM (Qhandle_shift_selection, "handle-shift-selection");
841 DEFSYM (Qread_number, "read-number");
842 DEFSYM (Qfuncall_interactively, "funcall-interactively");
843 DEFSYM (Qcommand_debug_status, "command-debug-status");
844 DEFSYM (Qenable_recursive_minibuffers, "enable-recursive-minibuffers");
845 DEFSYM (Qmouse_leave_buffer_hook, "mouse-leave-buffer-hook");
846
847 DEFVAR_KBOARD ("prefix-arg", Vprefix_arg,
848 doc:
849
850
851
852
853
854
855
856 );
857
858 DEFVAR_KBOARD ("last-prefix-arg", Vlast_prefix_arg,
859 doc:
860 );
861
862 DEFVAR_LISP ("current-prefix-arg", Vcurrent_prefix_arg,
863 doc:
864
865
866
867 );
868 Vcurrent_prefix_arg = Qnil;
869
870 DEFVAR_LISP ("command-history", Vcommand_history,
871 doc:
872
873
874
875 );
876 Vcommand_history = Qnil;
877
878 DEFVAR_LISP ("command-debug-status", Vcommand_debug_status,
879 doc:
880
881 );
882 Vcommand_debug_status = Qnil;
883
884 DEFVAR_LISP ("mark-even-if-inactive", Vmark_even_if_inactive,
885 doc:
886
887
888
889 );
890 Vmark_even_if_inactive = Qt;
891
892 DEFVAR_LISP ("mouse-leave-buffer-hook", Vmouse_leave_buffer_hook,
893 doc:
894
895
896
897
898 );
899 Vmouse_leave_buffer_hook = Qnil;
900
901 DEFVAR_BOOL ("inhibit-mouse-event-check", inhibit_mouse_event_check,
902 doc:
903
904
905
906 );
907 inhibit_mouse_event_check = false;
908
909 defsubr (&Sinteractive);
910 defsubr (&Scall_interactively);
911 defsubr (&Sfuncall_interactively);
912 defsubr (&Sprefix_numeric_value);
913
914 DEFSYM (Qinteractive_args, "interactive-args");
915 }