diff options
author | Lars Ingebrigtsen <larsi@gnus.org> | 2021-01-12 15:12:28 +0100 |
---|---|---|
committer | Lars Ingebrigtsen <larsi@gnus.org> | 2021-01-12 15:12:38 +0100 |
commit | ca024b0575c4ea754c4c6e6dbf21ed610e0d1fb8 (patch) | |
tree | 4b87356a3d9a269d88a7d0a05b04afcba9b7074d | |
parent | d191f1589b6d06221a58c8c4e6a6441b0a2a2e49 (diff) | |
download | emacs-ca024b0575c4ea754c4c6e6dbf21ed610e0d1fb8.tar.gz emacs-ca024b0575c4ea754c4c6e6dbf21ed610e0d1fb8.tar.bz2 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 * Minibuffer Windows:: Operating on the special minibuffer windows. * Minibuffer Contents:: How such commands access the minibuffer text. * Recursive Mini:: Whether recursive entry to minibuffer is allowed. +* Inhibiting Interaction:: Running Emacs when no interaction is possible. * Minibuffer Misc:: Various customization hooks and variables. 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}. @item unknown-image-type The message is @samp{Cannot determine image type}. @xref{Images}. + +@item inhibited-interaction +The message is @samp{User interaction while inhibited}. This error is +signalled when @code{inhibit-interaction} is non-@code{nil} and a user +interaction function (like @code{read-from-minibuffer}) is called. @end table @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. * Minibuffer Windows:: Operating on the special minibuffer windows. * Minibuffer Contents:: How such commands access the minibuffer text. * Recursive Mini:: Whether recursive entry to minibuffer is allowed. +* Inhibiting Interaction:: Running Emacs when no interaction is possible. * Minibuffer Misc:: Various customization hooks and variables. @end menu @@ -2617,6 +2618,38 @@ to @code{t} in the interactive declaration (@pxref{Using Interactive}). The minibuffer command @code{next-matching-history-element} (normally @kbd{M-s} in the minibuffer) does the latter. +@node Inhibiting Interaction +@section Inhibiting Interaction + +It's sometimes useful to be able to run Emacs as a headless server +process that responds to commands given over a network connection. +However, Emacs is primarily a platform for interactive usage, so many +commands prompt the user for feedback in certain anomalous situations. +This makes this use case more difficult, since the server process will +just hang waiting for user input. + +@vindex inhibit-interaction +Binding the @code{inhibit-interaction} variable to something +non-@code{nil} makes Emacs signal a @code{inhibited-interaction} error +instead of prompting, which can then be used by the server process to +handle these situations. + +Here's a typical use case: + +@lisp +(let ((inhibit-interaction t)) + (respond-to-client + (condition-case err + (my-client-handling-function) + (inhibited-interaction err)))) +@end lisp + +If @code{my-client-handling-function} ends up calling something that +asks the user for something (via @code{y-or-n-p} or +@code{read-from-minibuffer} or the like), an +@code{inhibited-interaction} error is signalled instead. The server +code then catches that error and reports it to the client. + @node Minibuffer Misc @section Minibuffer Miscellany @@ -1537,6 +1537,12 @@ that makes it a valid button. ** Miscellaneous ++++ +*** New variable 'inhibit-interaction' to make user prompts signal an error. +If this is bound to something non-nil, functions like +`read-from-minibuffer', `read-char' (and related) will signal an +`inhibited-interaction' error. + --- *** 'process-attributes' now works under OpenBSD, too. 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) DEFSYM (Qbuffer_read_only, "buffer-read-only"); DEFSYM (Qtext_read_only, "text-read-only"); DEFSYM (Qmark_inactive, "mark-inactive"); + DEFSYM (Qinhibited_interaction, "inhibited-interaction"); DEFSYM (Qlistp, "listp"); DEFSYM (Qconsp, "consp"); @@ -3844,6 +3845,8 @@ syms_of_data (void) PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only"); PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail), "Text is read-only"); + PUT_ERROR (Qinhibited_interaction, error_tail, + "User interaction while inhibited"); DEFSYM (Qrange_error, "range-error"); 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; extern Lisp_Object get_minibuffer (EMACS_INT); extern void init_minibuf_once (void); extern void syms_of_minibuf (void); +extern void barf_if_interaction_inhibited (void); /* Defined in callint.c. */ 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. If the optional argument SECONDS is non-nil, it should be a number specifying the maximum number of seconds to wait for input. If no input arrives in that time, return nil. SECONDS may be a -floating-point value. */) +floating-point value. + +If `inhibit-interaction' is non-nil, this function will signal an +`inhibited-interaction' error. */) (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) { Lisp_Object val; + barf_if_interaction_inhibited (); + if (! NILP (prompt)) message_with_string ("%s", prompt, 0); val = read_filtered_event (1, 1, 1, ! NILP (inherit_input_method), seconds); @@ -793,9 +798,14 @@ is used for reading a character. If the optional argument SECONDS is non-nil, it should be a number specifying the maximum number of seconds to wait for input. If no input arrives in that time, return nil. SECONDS may be a -floating-point value. */) +floating-point value. + +If `inhibit-interaction' is non-nil, this function will signal an +`inhibited-interaction' error. */) (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) { + barf_if_interaction_inhibited (); + if (! NILP (prompt)) message_with_string ("%s", prompt, 0); return read_filtered_event (0, 0, 0, ! NILP (inherit_input_method), seconds); @@ -822,11 +832,16 @@ is used for reading a character. If the optional argument SECONDS is non-nil, it should be a number specifying the maximum number of seconds to wait for input. If no input arrives in that time, return nil. SECONDS may be a -floating-point value. */) - (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) +floating-point value. + +If `inhibit-interaction' is non-nil, this function will signal an +`inhibited-interaction' error. */) +(Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) { Lisp_Object val; + barf_if_interaction_inhibited (); + if (! NILP (prompt)) message_with_string ("%s", prompt, 0); 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) } +void +barf_if_interaction_inhibited (void) +{ + if (inhibit_interaction) + xsignal0 (Qinhibited_interaction); +} + DEFUN ("read-from-minibuffer", Fread_from_minibuffer, Sread_from_minibuffer, 1, 7, 0, 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, then the string which is returned includes whatever text properties were present in the minibuffer. Otherwise the value has no text properties. +If `inhibit-interaction' is non-nil, this function will signal an + `inhibited-interaction' error. + The remainder of this documentation string describes the INITIAL-CONTENTS argument in more detail. It is only relevant when 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. */) { Lisp_Object histvar, histpos, val; + barf_if_interaction_inhibited (); + CHECK_STRING (prompt); if (NILP (keymap)) keymap = Vminibuffer_local_map; @@ -1207,11 +1219,17 @@ point positioned at the end, so that SPACE will accept the input. \(Actually, INITIAL can also be a cons of a string and an integer. Such values are treated as in `read-from-minibuffer', but are normally not useful in this function.) + Third arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits -the current input method and the setting of`enable-multibyte-characters'. */) +the current input method and the setting of`enable-multibyte-characters'. + +If `inhibit-interaction' is non-nil, this function will signal an +`inhibited-interaction' error. */) (Lisp_Object prompt, Lisp_Object initial, Lisp_Object inherit_input_method) { CHECK_STRING (prompt); + barf_if_interaction_inhibited (); + return read_minibuf (Vminibuffer_local_ns_map, initial, prompt, 0, Qminibuffer_history, make_fixnum (0), Qnil, 0, !NILP (inherit_input_method)); @@ -2321,6 +2339,15 @@ This variable also overrides the default character that `read-passwd' uses to hide passwords. */); Vread_hide_char = Qnil; + DEFVAR_BOOL ("inhibit-interaction", + inhibit_interaction, + doc: /* Non-nil means any user interaction will signal an error. +This variable can be bound when user interaction can't be performed, +for instance when running a headless Emacs server. Functions like +`read-from-minibuffer' (and the like) will signal `inhibited-interaction' +instead. */); + inhibit_interaction = 0; + defsubr (&Sactive_minibuffer_window); defsubr (&Sset_minibuffer_window); 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)." (ert-deftest lread-circular-hash () (should-error (read "#s(hash-table data #0=(#0# . #0#))"))) +(ert-deftest test-inhibit-interaction () + (let ((inhibit-interaction t)) + (should-error (read-char "foo: ")) + (should-error (read-event "foo: ")) + (should-error (read-char-exclusive "foo: ")))) + ;;; 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 @@ (should (equal (try-completion "baz" '("bAz" "baz")) (try-completion "baz" '("baz" "bAz")))))) +(ert-deftest test-inhibit-interaction () + (let ((inhibit-interaction t)) + (should-error (read-from-minibuffer "foo: ")) + + (should-error (y-or-n-p "foo: ")) + (should-error (yes-or-no-p "foo: ")) + (should-error (read-blanks-no-input "foo: ")) + + ;; See that we get the expected error. + (should (eq (condition-case nil + (read-from-minibuffer "foo: ") + (inhibited-interaction 'inhibit) + (error nil)) + 'inhibit)))) + ;;; minibuf-tests.el ends here |