diff --git a/etc/NEWS.26 b/etc/NEWS.26 index 19dd433cda4..94bb45c6feb 100644 --- a/etc/NEWS.26 +++ b/etc/NEWS.26 @@ -110,6 +110,16 @@ be removed prior using the changed 'shadow-*' commands. The old name is an alias of the new name. Future Emacs version will obsolete it. +--- +** 'while-no-input' does not return due to input from subprocesses. +Input that arrived from subprocesses while some code executed inside +the 'while-no-input' form injected an internal buffer-switch event +that counted as input and would cause 'while-no-input' to return, +perhaps prematurely. These buffer-switch events are now by default +ignored by 'while-no-input'; if you need to get the old behavior, +remove 'buffer-switch' from the list of events in +'while-no-input-ignore-events'. + * Lisp Changes in Emacs 26.2 diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index d0d1c3b156a..29ddd491af0 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -1779,7 +1779,24 @@ such that COMBO is equivalent to (and . CLAUSES)." ;;;###autoload (defmacro cl-do (steps endtest &rest body) - "The Common Lisp `do' loop. + "Bind variables and run BODY forms until END-TEST returns non-nil. +First, each VAR is bound to the associated INIT value as if by a `let' form. +Then, in each iteration of the loop, the END-TEST is evaluated; if true, +the loop is finished. Otherwise, the BODY forms are evaluated, then each +VAR is set to the associated STEP expression (as if by a `cl-psetq' form) +and the next iteration begins. + +Once the END-TEST becomes true, the RESULT forms are evaluated (with +the VARs still bound to their values) to produce the result +returned by `cl-do'. + +Note that the entire loop is enclosed in an implicit `nil' block, so +that you can use `cl-return' to exit at any time. + +Also note that END-TEST is checked before evaluating BODY. If END-TEST +is initially non-nil, `cl-do' will exit without running BODY. + +For more details, see `cl-do' description in Info node `(cl) Iteration'. \(fn ((VAR INIT [STEP])...) (END-TEST [RESULT...]) BODY...)" (declare (indent 2) @@ -1791,7 +1808,25 @@ such that COMBO is equivalent to (and . CLAUSES)." ;;;###autoload (defmacro cl-do* (steps endtest &rest body) - "The Common Lisp `do*' loop. + "Bind variables and run BODY forms until END-TEST returns non-nil. +First, each VAR is bound to the associated INIT value as if by a `let*' form. +Then, in each iteration of the loop, the END-TEST is evaluated; if true, +the loop is finished. Otherwise, the BODY forms are evaluated, then each +VAR is set to the associated STEP expression (as if by a `setq' +form) and the next iteration begins. + +Once the END-TEST becomes true, the RESULT forms are evaluated (with +the VARs still bound to their values) to produce the result +returned by `cl-do*'. + +Note that the entire loop is enclosed in an implicit `nil' block, so +that you can use `cl-return' to exit at any time. + +Also note that END-TEST is checked before evaluating BODY. If END-TEST +is initially non-nil, `cl-do*' will exit without running BODY. + +This is to `cl-do' what `let*' is to `let'. +For more details, see `cl-do*' description in Info node `(cl) Iteration'. \(fn ((VAR INIT [STEP])...) (END-TEST [RESULT...]) BODY...)" (declare (indent 2) (debug cl-do)) diff --git a/lisp/subr.el b/lisp/subr.el index 4c05111f516..41dc9aa45f5 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -3570,7 +3570,7 @@ is allowed once again. (Immediately, if `inhibit-quit' is nil.)" ;; Don't throw `throw-on-input' on those events by default. (setq while-no-input-ignore-events '(focus-in focus-out help-echo iconify-frame - make-frame-visible selection-request)) + make-frame-visible selection-request buffer-switch)) (defmacro while-no-input (&rest body) "Execute BODY only as long as there's no pending input. diff --git a/src/keyboard.c b/src/keyboard.c index 1c1f1514ae8..35d74f4a795 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3554,6 +3554,7 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event, case ICONIFY_EVENT: ignore_event = Qiconify_frame; break; case DEICONIFY_EVENT: ignore_event = Qmake_frame_visible; break; case SELECTION_REQUEST_EVENT: ignore_event = Qselection_request; break; + case BUFFER_SWITCH_EVENT: ignore_event = Qbuffer_switch; break; default: ignore_event = Qnil; break; } @@ -11082,6 +11083,8 @@ syms_of_keyboard (void) /* Menu and tool bar item parts. */ DEFSYM (Qmenu_enable, "menu-enable"); + DEFSYM (Qbuffer_switch, "buffer-switch"); + #ifdef HAVE_NTGUI DEFSYM (Qlanguage_change, "language-change"); DEFSYM (Qend_session, "end-session"); diff --git a/src/term.c b/src/term.c index ce24f6915fc..852dc23bd60 100644 --- a/src/term.c +++ b/src/term.c @@ -4008,6 +4008,7 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed) char const *diagnostic = (fd < 0) ? "Could not open file: %s" : "Not a tty device: %s"; emacs_close (fd); + delete_terminal_internal (terminal); maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name); } diff --git a/src/termhooks.h b/src/termhooks.h index 211429169ba..4e341055100 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -733,6 +733,7 @@ extern struct terminal *get_named_terminal (const char *); extern struct terminal *create_terminal (enum output_method, struct redisplay_interface *); extern void delete_terminal (struct terminal *); +extern void delete_terminal_internal (struct terminal *); extern Lisp_Object terminal_glyph_code (struct terminal *, int); /* The initial terminal device, created by initial_term_init. */ diff --git a/src/terminal.c b/src/terminal.c index 18982fe7044..e4803592575 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -314,7 +314,6 @@ create_terminal (enum output_method type, struct redisplay_interface *rif) void delete_terminal (struct terminal *terminal) { - struct terminal **tp; Lisp_Object tail, frame; /* Protect against recursive calls. delete_frame calls the @@ -335,6 +334,14 @@ delete_terminal (struct terminal *terminal) } } + delete_terminal_internal (terminal); +} + +void +delete_terminal_internal (struct terminal *terminal) +{ + struct terminal **tp; + for (tp = &terminal_list; *tp != terminal; tp = &(*tp)->next_terminal) if (! *tp) emacs_abort ();