diff options
| author | Lars Ingebrigtsen | 2021-01-12 15:12:28 +0100 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-01-12 15:12:38 +0100 |
| commit | ca024b0575c4ea754c4c6e6dbf21ed610e0d1fb8 (patch) | |
| tree | 4b87356a3d9a269d88a7d0a05b04afcba9b7074d | |
| parent | d191f1589b6d06221a58c8c4e6a6441b0a2a2e49 (diff) | |
| download | emacs-ca024b0575c4ea754c4c6e6dbf21ed610e0d1fb8.tar.gz emacs-ca024b0575c4ea754c4c6e6dbf21ed610e0d1fb8.zip | |
Add a new variable `inhibit-interaction'
* doc/lispref/elisp.texi (Top): Add a link.
* doc/lispref/errors.texi (Standard Errors): Mention the new error.
* doc/lispref/minibuf.texi (Minibuffers): Add a link.
(Inhibiting Interaction): New node.
* src/data.c (syms_of_data): Define the `inhibited-interaction' error.
* src/lisp.h: Export the barfing function.
* src/lread.c (Fread_char, Fread_event, Fread_char_exclusive):
Barf if inhibited.
* src/minibuf.c (barf_if_interaction_inhibited): New function.
(Fread_from_minibuffer, Fread_no_blanks_input): Barf if inhibited.
(syms_of_minibuf): Define the `inhibit-interaction' variable.
| -rw-r--r-- | doc/lispref/elisp.texi | 1 | ||||
| -rw-r--r-- | doc/lispref/errors.texi | 5 | ||||
| -rw-r--r-- | doc/lispref/minibuf.texi | 33 | ||||
| -rw-r--r-- | etc/NEWS | 6 | ||||
| -rw-r--r-- | src/data.c | 3 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/lread.c | 23 | ||||
| -rw-r--r-- | src/minibuf.c | 29 | ||||
| -rw-r--r-- | test/src/lread-tests.el | 6 | ||||
| -rw-r--r-- | test/src/minibuf-tests.el | 15 |
10 files changed, 117 insertions, 5 deletions
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index fa548b503aa..12255d122f9 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi | |||
| @@ -739,6 +739,7 @@ Minibuffers | |||
| 739 | * Minibuffer Windows:: Operating on the special minibuffer windows. | 739 | * Minibuffer Windows:: Operating on the special minibuffer windows. |
| 740 | * Minibuffer Contents:: How such commands access the minibuffer text. | 740 | * Minibuffer Contents:: How such commands access the minibuffer text. |
| 741 | * Recursive Mini:: Whether recursive entry to minibuffer is allowed. | 741 | * Recursive Mini:: Whether recursive entry to minibuffer is allowed. |
| 742 | * Inhibiting Interaction:: Running Emacs when no interaction is possible. | ||
| 742 | * Minibuffer Misc:: Various customization hooks and variables. | 743 | * Minibuffer Misc:: Various customization hooks and variables. |
| 743 | 744 | ||
| 744 | Completion | 745 | Completion |
diff --git a/doc/lispref/errors.texi b/doc/lispref/errors.texi index 9ec12714991..fb393b951f1 100644 --- a/doc/lispref/errors.texi +++ b/doc/lispref/errors.texi | |||
| @@ -230,6 +230,11 @@ The message is @samp{Wrong type argument}. @xref{Type Predicates}. | |||
| 230 | 230 | ||
| 231 | @item unknown-image-type | 231 | @item unknown-image-type |
| 232 | The message is @samp{Cannot determine image type}. @xref{Images}. | 232 | The message is @samp{Cannot determine image type}. @xref{Images}. |
| 233 | |||
| 234 | @item inhibited-interaction | ||
| 235 | The message is @samp{User interaction while inhibited}. This error is | ||
| 236 | signalled when @code{inhibit-interaction} is non-@code{nil} and a user | ||
| 237 | interaction function (like @code{read-from-minibuffer}) is called. | ||
| 233 | @end table | 238 | @end table |
| 234 | 239 | ||
| 235 | @ignore The following seem to be unused now. | 240 | @ignore The following seem to be unused now. |
diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi index d316c1f0602..0ce17ed571a 100644 --- a/doc/lispref/minibuf.texi +++ b/doc/lispref/minibuf.texi | |||
| @@ -32,6 +32,7 @@ argument. | |||
| 32 | * Minibuffer Windows:: Operating on the special minibuffer windows. | 32 | * Minibuffer Windows:: Operating on the special minibuffer windows. |
| 33 | * Minibuffer Contents:: How such commands access the minibuffer text. | 33 | * Minibuffer Contents:: How such commands access the minibuffer text. |
| 34 | * Recursive Mini:: Whether recursive entry to minibuffer is allowed. | 34 | * Recursive Mini:: Whether recursive entry to minibuffer is allowed. |
| 35 | * Inhibiting Interaction:: Running Emacs when no interaction is possible. | ||
| 35 | * Minibuffer Misc:: Various customization hooks and variables. | 36 | * Minibuffer Misc:: Various customization hooks and variables. |
| 36 | @end menu | 37 | @end menu |
| 37 | 38 | ||
| @@ -2617,6 +2618,38 @@ to @code{t} in the interactive declaration (@pxref{Using Interactive}). | |||
| 2617 | The minibuffer command @code{next-matching-history-element} (normally | 2618 | The minibuffer command @code{next-matching-history-element} (normally |
| 2618 | @kbd{M-s} in the minibuffer) does the latter. | 2619 | @kbd{M-s} in the minibuffer) does the latter. |
| 2619 | 2620 | ||
| 2621 | @node Inhibiting Interaction | ||
| 2622 | @section Inhibiting Interaction | ||
| 2623 | |||
| 2624 | It's sometimes useful to be able to run Emacs as a headless server | ||
| 2625 | process that responds to commands given over a network connection. | ||
| 2626 | However, Emacs is primarily a platform for interactive usage, so many | ||
| 2627 | commands prompt the user for feedback in certain anomalous situations. | ||
| 2628 | This makes this use case more difficult, since the server process will | ||
| 2629 | just hang waiting for user input. | ||
| 2630 | |||
| 2631 | @vindex inhibit-interaction | ||
| 2632 | Binding the @code{inhibit-interaction} variable to something | ||
| 2633 | non-@code{nil} makes Emacs signal a @code{inhibited-interaction} error | ||
| 2634 | instead of prompting, which can then be used by the server process to | ||
| 2635 | handle these situations. | ||
| 2636 | |||
| 2637 | Here's a typical use case: | ||
| 2638 | |||
| 2639 | @lisp | ||
| 2640 | (let ((inhibit-interaction t)) | ||
| 2641 | (respond-to-client | ||
| 2642 | (condition-case err | ||
| 2643 | (my-client-handling-function) | ||
| 2644 | (inhibited-interaction err)))) | ||
| 2645 | @end lisp | ||
| 2646 | |||
| 2647 | If @code{my-client-handling-function} ends up calling something that | ||
| 2648 | asks the user for something (via @code{y-or-n-p} or | ||
| 2649 | @code{read-from-minibuffer} or the like), an | ||
| 2650 | @code{inhibited-interaction} error is signalled instead. The server | ||
| 2651 | code then catches that error and reports it to the client. | ||
| 2652 | |||
| 2620 | @node Minibuffer Misc | 2653 | @node Minibuffer Misc |
| 2621 | @section Minibuffer Miscellany | 2654 | @section Minibuffer Miscellany |
| 2622 | 2655 | ||
| @@ -1537,6 +1537,12 @@ that makes it a valid button. | |||
| 1537 | 1537 | ||
| 1538 | ** Miscellaneous | 1538 | ** Miscellaneous |
| 1539 | 1539 | ||
| 1540 | +++ | ||
| 1541 | *** New variable 'inhibit-interaction' to make user prompts signal an error. | ||
| 1542 | If this is bound to something non-nil, functions like | ||
| 1543 | `read-from-minibuffer', `read-char' (and related) will signal an | ||
| 1544 | `inhibited-interaction' error. | ||
| 1545 | |||
| 1540 | --- | 1546 | --- |
| 1541 | *** 'process-attributes' now works under OpenBSD, too. | 1547 | *** 'process-attributes' now works under OpenBSD, too. |
| 1542 | 1548 | ||
diff --git a/src/data.c b/src/data.c index d420bf5fc58..35a6890b9bd 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -3760,6 +3760,7 @@ syms_of_data (void) | |||
| 3760 | DEFSYM (Qbuffer_read_only, "buffer-read-only"); | 3760 | DEFSYM (Qbuffer_read_only, "buffer-read-only"); |
| 3761 | DEFSYM (Qtext_read_only, "text-read-only"); | 3761 | DEFSYM (Qtext_read_only, "text-read-only"); |
| 3762 | DEFSYM (Qmark_inactive, "mark-inactive"); | 3762 | DEFSYM (Qmark_inactive, "mark-inactive"); |
| 3763 | DEFSYM (Qinhibited_interaction, "inhibited-interaction"); | ||
| 3763 | 3764 | ||
| 3764 | DEFSYM (Qlistp, "listp"); | 3765 | DEFSYM (Qlistp, "listp"); |
| 3765 | DEFSYM (Qconsp, "consp"); | 3766 | DEFSYM (Qconsp, "consp"); |
| @@ -3844,6 +3845,8 @@ syms_of_data (void) | |||
| 3844 | PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only"); | 3845 | PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only"); |
| 3845 | PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail), | 3846 | PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail), |
| 3846 | "Text is read-only"); | 3847 | "Text is read-only"); |
| 3848 | PUT_ERROR (Qinhibited_interaction, error_tail, | ||
| 3849 | "User interaction while inhibited"); | ||
| 3847 | 3850 | ||
| 3848 | DEFSYM (Qrange_error, "range-error"); | 3851 | DEFSYM (Qrange_error, "range-error"); |
| 3849 | DEFSYM (Qdomain_error, "domain-error"); | 3852 | DEFSYM (Qdomain_error, "domain-error"); |
diff --git a/src/lisp.h b/src/lisp.h index 9d8dbbd629f..f6588685443 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4351,6 +4351,7 @@ extern EMACS_INT minibuf_level; | |||
| 4351 | extern Lisp_Object get_minibuffer (EMACS_INT); | 4351 | extern Lisp_Object get_minibuffer (EMACS_INT); |
| 4352 | extern void init_minibuf_once (void); | 4352 | extern void init_minibuf_once (void); |
| 4353 | extern void syms_of_minibuf (void); | 4353 | extern void syms_of_minibuf (void); |
| 4354 | extern void barf_if_interaction_inhibited (void); | ||
| 4354 | 4355 | ||
| 4355 | /* Defined in callint.c. */ | 4356 | /* Defined in callint.c. */ |
| 4356 | 4357 | ||
diff --git a/src/lread.c b/src/lread.c index 1ff0828e85e..4b168fb84bd 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -767,11 +767,16 @@ is used for reading a character. | |||
| 767 | If the optional argument SECONDS is non-nil, it should be a number | 767 | If the optional argument SECONDS is non-nil, it should be a number |
| 768 | specifying the maximum number of seconds to wait for input. If no | 768 | specifying the maximum number of seconds to wait for input. If no |
| 769 | input arrives in that time, return nil. SECONDS may be a | 769 | input arrives in that time, return nil. SECONDS may be a |
| 770 | floating-point value. */) | 770 | floating-point value. |
| 771 | |||
| 772 | If `inhibit-interaction' is non-nil, this function will signal an | ||
| 773 | `inhibited-interaction' error. */) | ||
| 771 | (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) | 774 | (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) |
| 772 | { | 775 | { |
| 773 | Lisp_Object val; | 776 | Lisp_Object val; |
| 774 | 777 | ||
| 778 | barf_if_interaction_inhibited (); | ||
| 779 | |||
| 775 | if (! NILP (prompt)) | 780 | if (! NILP (prompt)) |
| 776 | message_with_string ("%s", prompt, 0); | 781 | message_with_string ("%s", prompt, 0); |
| 777 | val = read_filtered_event (1, 1, 1, ! NILP (inherit_input_method), seconds); | 782 | val = read_filtered_event (1, 1, 1, ! NILP (inherit_input_method), seconds); |
| @@ -793,9 +798,14 @@ is used for reading a character. | |||
| 793 | If the optional argument SECONDS is non-nil, it should be a number | 798 | If the optional argument SECONDS is non-nil, it should be a number |
| 794 | specifying the maximum number of seconds to wait for input. If no | 799 | specifying the maximum number of seconds to wait for input. If no |
| 795 | input arrives in that time, return nil. SECONDS may be a | 800 | input arrives in that time, return nil. SECONDS may be a |
| 796 | floating-point value. */) | 801 | floating-point value. |
| 802 | |||
| 803 | If `inhibit-interaction' is non-nil, this function will signal an | ||
| 804 | `inhibited-interaction' error. */) | ||
| 797 | (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) | 805 | (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) |
| 798 | { | 806 | { |
| 807 | barf_if_interaction_inhibited (); | ||
| 808 | |||
| 799 | if (! NILP (prompt)) | 809 | if (! NILP (prompt)) |
| 800 | message_with_string ("%s", prompt, 0); | 810 | message_with_string ("%s", prompt, 0); |
| 801 | return read_filtered_event (0, 0, 0, ! NILP (inherit_input_method), seconds); | 811 | return read_filtered_event (0, 0, 0, ! NILP (inherit_input_method), seconds); |
| @@ -822,11 +832,16 @@ is used for reading a character. | |||
| 822 | If the optional argument SECONDS is non-nil, it should be a number | 832 | If the optional argument SECONDS is non-nil, it should be a number |
| 823 | specifying the maximum number of seconds to wait for input. If no | 833 | specifying the maximum number of seconds to wait for input. If no |
| 824 | input arrives in that time, return nil. SECONDS may be a | 834 | input arrives in that time, return nil. SECONDS may be a |
| 825 | floating-point value. */) | 835 | floating-point value. |
| 826 | (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) | 836 | |
| 837 | If `inhibit-interaction' is non-nil, this function will signal an | ||
| 838 | `inhibited-interaction' error. */) | ||
| 839 | (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) | ||
| 827 | { | 840 | { |
| 828 | Lisp_Object val; | 841 | Lisp_Object val; |
| 829 | 842 | ||
| 843 | barf_if_interaction_inhibited (); | ||
| 844 | |||
| 830 | if (! NILP (prompt)) | 845 | if (! NILP (prompt)) |
| 831 | message_with_string ("%s", prompt, 0); | 846 | message_with_string ("%s", prompt, 0); |
| 832 | 847 | ||
diff --git a/src/minibuf.c b/src/minibuf.c index 868e481f843..5df10453739 100644 --- a/src/minibuf.c +++ b/src/minibuf.c | |||
| @@ -1075,6 +1075,13 @@ read_minibuf_unwind (void) | |||
| 1075 | } | 1075 | } |
| 1076 | 1076 | ||
| 1077 | 1077 | ||
| 1078 | void | ||
| 1079 | barf_if_interaction_inhibited (void) | ||
| 1080 | { | ||
| 1081 | if (inhibit_interaction) | ||
| 1082 | xsignal0 (Qinhibited_interaction); | ||
| 1083 | } | ||
| 1084 | |||
| 1078 | DEFUN ("read-from-minibuffer", Fread_from_minibuffer, | 1085 | DEFUN ("read-from-minibuffer", Fread_from_minibuffer, |
| 1079 | Sread_from_minibuffer, 1, 7, 0, | 1086 | Sread_from_minibuffer, 1, 7, 0, |
| 1080 | doc: /* Read a string from the minibuffer, prompting with string PROMPT. | 1087 | doc: /* Read a string from the minibuffer, prompting with string PROMPT. |
| @@ -1119,6 +1126,9 @@ If the variable `minibuffer-allow-text-properties' is non-nil, | |||
| 1119 | then the string which is returned includes whatever text properties | 1126 | then the string which is returned includes whatever text properties |
| 1120 | were present in the minibuffer. Otherwise the value has no text properties. | 1127 | were present in the minibuffer. Otherwise the value has no text properties. |
| 1121 | 1128 | ||
| 1129 | If `inhibit-interaction' is non-nil, this function will signal an | ||
| 1130 | `inhibited-interaction' error. | ||
| 1131 | |||
| 1122 | The remainder of this documentation string describes the | 1132 | The remainder of this documentation string describes the |
| 1123 | INITIAL-CONTENTS argument in more detail. It is only relevant when | 1133 | INITIAL-CONTENTS argument in more detail. It is only relevant when |
| 1124 | studying existing code, or when HIST is a cons. If non-nil, | 1134 | studying existing code, or when HIST is a cons. If non-nil, |
| @@ -1134,6 +1144,8 @@ and some related functions, which use zero-indexing for POSITION. */) | |||
| 1134 | { | 1144 | { |
| 1135 | Lisp_Object histvar, histpos, val; | 1145 | Lisp_Object histvar, histpos, val; |
| 1136 | 1146 | ||
| 1147 | barf_if_interaction_inhibited (); | ||
| 1148 | |||
| 1137 | CHECK_STRING (prompt); | 1149 | CHECK_STRING (prompt); |
| 1138 | if (NILP (keymap)) | 1150 | if (NILP (keymap)) |
| 1139 | keymap = Vminibuffer_local_map; | 1151 | keymap = Vminibuffer_local_map; |
| @@ -1207,11 +1219,17 @@ point positioned at the end, so that SPACE will accept the input. | |||
| 1207 | \(Actually, INITIAL can also be a cons of a string and an integer. | 1219 | \(Actually, INITIAL can also be a cons of a string and an integer. |
| 1208 | Such values are treated as in `read-from-minibuffer', but are normally | 1220 | Such values are treated as in `read-from-minibuffer', but are normally |
| 1209 | not useful in this function.) | 1221 | not useful in this function.) |
| 1222 | |||
| 1210 | Third arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits | 1223 | Third arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits |
| 1211 | the current input method and the setting of`enable-multibyte-characters'. */) | 1224 | the current input method and the setting of`enable-multibyte-characters'. |
| 1225 | |||
| 1226 | If `inhibit-interaction' is non-nil, this function will signal an | ||
| 1227 | `inhibited-interaction' error. */) | ||
| 1212 | (Lisp_Object prompt, Lisp_Object initial, Lisp_Object inherit_input_method) | 1228 | (Lisp_Object prompt, Lisp_Object initial, Lisp_Object inherit_input_method) |
| 1213 | { | 1229 | { |
| 1214 | CHECK_STRING (prompt); | 1230 | CHECK_STRING (prompt); |
| 1231 | barf_if_interaction_inhibited (); | ||
| 1232 | |||
| 1215 | return read_minibuf (Vminibuffer_local_ns_map, initial, prompt, | 1233 | return read_minibuf (Vminibuffer_local_ns_map, initial, prompt, |
| 1216 | 0, Qminibuffer_history, make_fixnum (0), Qnil, 0, | 1234 | 0, Qminibuffer_history, make_fixnum (0), Qnil, 0, |
| 1217 | !NILP (inherit_input_method)); | 1235 | !NILP (inherit_input_method)); |
| @@ -2321,6 +2339,15 @@ This variable also overrides the default character that `read-passwd' | |||
| 2321 | uses to hide passwords. */); | 2339 | uses to hide passwords. */); |
| 2322 | Vread_hide_char = Qnil; | 2340 | Vread_hide_char = Qnil; |
| 2323 | 2341 | ||
| 2342 | DEFVAR_BOOL ("inhibit-interaction", | ||
| 2343 | inhibit_interaction, | ||
| 2344 | doc: /* Non-nil means any user interaction will signal an error. | ||
| 2345 | This variable can be bound when user interaction can't be performed, | ||
| 2346 | for instance when running a headless Emacs server. Functions like | ||
| 2347 | `read-from-minibuffer' (and the like) will signal `inhibited-interaction' | ||
| 2348 | instead. */); | ||
| 2349 | inhibit_interaction = 0; | ||
| 2350 | |||
| 2324 | defsubr (&Sactive_minibuffer_window); | 2351 | defsubr (&Sactive_minibuffer_window); |
| 2325 | defsubr (&Sset_minibuffer_window); | 2352 | defsubr (&Sset_minibuffer_window); |
| 2326 | defsubr (&Sread_from_minibuffer); | 2353 | defsubr (&Sread_from_minibuffer); |
diff --git a/test/src/lread-tests.el b/test/src/lread-tests.el index edf88214f97..f2a60bcf327 100644 --- a/test/src/lread-tests.el +++ b/test/src/lread-tests.el | |||
| @@ -190,4 +190,10 @@ literals (Bug#20852)." | |||
| 190 | (ert-deftest lread-circular-hash () | 190 | (ert-deftest lread-circular-hash () |
| 191 | (should-error (read "#s(hash-table data #0=(#0# . #0#))"))) | 191 | (should-error (read "#s(hash-table data #0=(#0# . #0#))"))) |
| 192 | 192 | ||
| 193 | (ert-deftest test-inhibit-interaction () | ||
| 194 | (let ((inhibit-interaction t)) | ||
| 195 | (should-error (read-char "foo: ")) | ||
| 196 | (should-error (read-event "foo: ")) | ||
| 197 | (should-error (read-char-exclusive "foo: ")))) | ||
| 198 | |||
| 193 | ;;; lread-tests.el ends here | 199 | ;;; lread-tests.el ends here |
diff --git a/test/src/minibuf-tests.el b/test/src/minibuf-tests.el index b9cd255462d..28119fc999e 100644 --- a/test/src/minibuf-tests.el +++ b/test/src/minibuf-tests.el | |||
| @@ -410,5 +410,20 @@ | |||
| 410 | (should (equal (try-completion "baz" '("bAz" "baz")) | 410 | (should (equal (try-completion "baz" '("bAz" "baz")) |
| 411 | (try-completion "baz" '("baz" "bAz")))))) | 411 | (try-completion "baz" '("baz" "bAz")))))) |
| 412 | 412 | ||
| 413 | (ert-deftest test-inhibit-interaction () | ||
| 414 | (let ((inhibit-interaction t)) | ||
| 415 | (should-error (read-from-minibuffer "foo: ")) | ||
| 416 | |||
| 417 | (should-error (y-or-n-p "foo: ")) | ||
| 418 | (should-error (yes-or-no-p "foo: ")) | ||
| 419 | (should-error (read-blanks-no-input "foo: ")) | ||
| 420 | |||
| 421 | ;; See that we get the expected error. | ||
| 422 | (should (eq (condition-case nil | ||
| 423 | (read-from-minibuffer "foo: ") | ||
| 424 | (inhibited-interaction 'inhibit) | ||
| 425 | (error nil)) | ||
| 426 | 'inhibit)))) | ||
| 427 | |||
| 413 | 428 | ||
| 414 | ;;; minibuf-tests.el ends here | 429 | ;;; minibuf-tests.el ends here |