From: Alan Mackenzie Date: Fri, 14 May 2021 15:52:21 +0000 (+0000) Subject: Various detailed fixes to minibuf.c, etc., to fix bug #48337 X-Git-Tag: emacs-28.0.90~2474 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=780b1db126fcfdbb50da5c1acf24b3c6e614dd9f;p=emacs.git Various detailed fixes to minibuf.c, etc., to fix bug #48337 Also fix some unsafe coding. * lisp/window.el (push-window-buffer-onto-prev): New function, extracted from (record-window-buffer): Refactor by extracting the above, and removing the now redundant parameter DO-MINIBUF. * src/minibuf.c (zip_minibuffer_stacks, read_minibuf): Replace calls to get_minibuffer (0) by nth_minibuffer (0). Replace calls to Qrecord_window_buffer by calls to Qpush_window_buffer_onto_prev. (Factive_minibuffer_window, read_minibuf_unwind): Call abort_emacs should an "impossible" null value be returned by nth_minibuffer. (read_minibuf): Move the get_minibuffer_call to just after the incrementation of minibuf_level as a precaution against a missing buffer in Vminibuffer_list. (nth_minibuffer): Replace XCAR by Fcar, to allow (car nil) to work. (init_minibuf_once): Create the inactive buffer *Minibuf-0*. (syms_of_minibuf): New DEFSYM, Qpush_window_buffer_onto_prev. * src/window.c (restore_window_configuration): Replace some XCARs and XCDRs by Fcar_safe and Fcdr_safe. --- diff --git a/lisp/window.el b/lisp/window.el index db62d3308fb..8928308eb26 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -4361,45 +4361,45 @@ This may be a useful alternative binding for \\[delete-other-windows] ;; The following function is called by `set-window-buffer' _before_ it ;; replaces the buffer of the argument window with the new buffer. -(defun record-window-buffer (&optional window do-minibuf) - "Record WINDOW's buffer. +(defun push-window-buffer-onto-prev (&optional window) + "Push entry for WINDOW's buffer onto WINDOW's prev-buffers list. WINDOW must be a live window and defaults to the selected one. -If WINDOW is a minibuffer, it will only be recorded if DO-MINIBUF -is non-nil." +Any duplicate entries for the buffer in the list are removed." (let* ((window (window-normalize-window window t)) - (buffer (window-buffer window)) - (entry (assq buffer (window-prev-buffers window)))) + (buffer (window-buffer window)) + (w-list (window-prev-buffers window)) + (entry (assq buffer w-list))) + (when entry + (setq w-list (assq-delete-all buffer w-list))) + (let ((start (window-start window)) + (point (window-point window))) + (setq entry + (cons buffer + (with-current-buffer buffer + (if entry + ;; We have an entry, update marker positions. + (list (set-marker (nth 1 entry) start) + (set-marker (nth 2 entry) point)) + (list (copy-marker start) + (copy-marker + ;; Preserve window-point-insertion-type + ;; (Bug#12855) + point window-point-insertion-type)))))) + (set-window-prev-buffers window (cons entry w-list))))) + +(defun record-window-buffer (&optional window) + "Record WINDOW's buffer. +WINDOW must be a live window and defaults to the selected one." + (let* ((window (window-normalize-window window t)) + (buffer (window-buffer window))) ;; Reset WINDOW's next buffers. If needed, they are resurrected by ;; `switch-to-prev-buffer' and `switch-to-next-buffer'. (set-window-next-buffers window nil) ;; Don't record insignificant buffers. - (when (or (not (eq (aref (buffer-name buffer) 0) ?\s)) - (and do-minibuf (minibufferp buffer))) - (when entry - ;; Remove all entries for BUFFER from WINDOW's previous buffers. - (set-window-prev-buffers - window (assq-delete-all buffer (window-prev-buffers window)))) - ;; Add an entry for buffer to WINDOW's previous buffers. - (with-current-buffer buffer - (let ((start (window-start window)) - (point (window-point window))) - (setq entry - (cons buffer - (if entry - ;; We have an entry, update marker positions. - (list (set-marker (nth 1 entry) start) - (set-marker (nth 2 entry) point)) - ;; Make new markers. - (list (copy-marker start) - (copy-marker - ;; Preserve window-point-insertion-type - ;; (Bug#12855). - point window-point-insertion-type))))) - (set-window-prev-buffers - window (cons entry (window-prev-buffers window))))) - + (when (not (eq (aref (buffer-name buffer) 0) ?\s)) + (push-window-buffer-onto-prev window) (run-hooks 'buffer-list-update-hook)))) (defun unrecord-window-buffer (&optional window buffer) diff --git a/src/minibuf.c b/src/minibuf.c index 52d1275451b..428998a639b 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -157,16 +157,15 @@ zip_minibuffer_stacks (Lisp_Object dest_window, Lisp_Object source_window) Fset_window_start (dest_window, Fwindow_start (source_window), Qnil); Fset_window_point (dest_window, Fwindow_point (source_window)); dw->prev_buffers = sw->prev_buffers; - set_window_buffer (source_window, get_minibuffer (0), 0, 0); + set_window_buffer (source_window, nth_minibuffer (0), 0, 0); sw->prev_buffers = Qnil; return; } if (live_minibuffer_p (dw->contents)) - call2 (Qrecord_window_buffer, dest_window, Qt); + call1 (Qpush_window_buffer_onto_prev, dest_window); if (live_minibuffer_p (sw->contents)) - call2 (Qrecord_window_buffer, source_window, Qt); - + call1 (Qpush_window_buffer_onto_prev, source_window); acc = merge_c (dw->prev_buffers, sw->prev_buffers, minibuffer_ent_greater); if (!NILP (acc)) @@ -179,7 +178,7 @@ zip_minibuffer_stacks (Lisp_Object dest_window, Lisp_Object source_window) } dw->prev_buffers = acc; sw->prev_buffers = Qnil; - set_window_buffer (source_window, get_minibuffer (0), 0, 0); + set_window_buffer (source_window, nth_minibuffer (0), 0, 0); } /* If `minibuffer_follows_selected_frame' is t, or we're about to @@ -228,6 +227,8 @@ DEFUN ("active-minibuffer-window", Factive_minibuffer_window, return Qnil; innermost_MB = nth_minibuffer (minibuf_level); + if (NILP (innermost_MB)) + emacs_abort (); FOR_EACH_FRAME (frames, frame) { f = XFRAME (frame); @@ -653,6 +654,10 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, } minibuf_level++; /* Before calling choose_minibuf_frame. */ + /* Ensure now that the latest minibuffer has been created, in case + anything happens which depends on MINNIBUF_LEVEL and + Vminibuffer_list being consistent with eachother. */ + minibuffer = get_minibuffer (minibuf_level); /* Choose the minibuffer window and frame, and take action on them. */ @@ -680,7 +685,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, } MB_frame = XWINDOW (XFRAME (selected_frame)->minibuffer_window)->frame; if (live_minibuffer_p (XWINDOW (minibuf_window)->contents)) - call2 (Qrecord_window_buffer, minibuf_window, Qt); + call1 (Qpush_window_buffer_onto_prev, minibuf_window); record_unwind_protect_void (minibuffer_unwind); record_unwind_protect (restore_window_configuration, @@ -766,7 +771,6 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, /* Switch to the minibuffer. */ - minibuffer = get_minibuffer (minibuf_level); set_minibuffer_mode (minibuffer, minibuf_level); Fset_buffer (minibuffer); @@ -807,7 +811,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, /* Empty out the minibuffers of all frames, except those frames where there is an active minibuffer. Set them to point to ` *Minibuf-0*', which is always empty. */ - empty_minibuf = get_minibuffer (0); + empty_minibuf = nth_minibuffer (0); set_minibuffer_mode (empty_minibuf, 0); /* Display this minibuffer in the proper window. */ @@ -969,9 +973,7 @@ static Lisp_Object nth_minibuffer (EMACS_INT depth) { Lisp_Object tail = Fnthcdr (make_fixnum (depth), Vminibuffer_list); - if (NILP (tail)) - return Qnil; - return XCAR (tail); + return Fcar (tail); } /* Set the major mode of the minibuffer BUF, depending on DEPTH, the @@ -1076,9 +1078,13 @@ read_minibuf_unwind (void) Lisp_Object future_mini_window; Lisp_Object saved_selected_frame = selected_frame; Lisp_Object window, frames; + Lisp_Object expired_MB = nth_minibuffer (minibuf_level); struct window *w; struct frame *f; + if (NILP (expired_MB)) + emacs_abort (); + /* Locate the expired minibuffer. */ FOR_EACH_FRAME (frames, exp_MB_frame) { @@ -1088,7 +1094,7 @@ read_minibuf_unwind (void) { w = XWINDOW (window); if (EQ (w->frame, exp_MB_frame) - && EQ (w->contents, nth_minibuffer (minibuf_level))) + && EQ (w->contents, expired_MB)) goto found; } } @@ -1104,7 +1110,7 @@ read_minibuf_unwind (void) minibuffer when we reset the relevant variables. Don't depend on `minibuf_window' here. This could by now be the mini-window of any frame. */ - Fset_buffer (nth_minibuffer (minibuf_level)); + Fset_buffer (expired_MB); minibuf_level--; /* Restore prompt, etc, from outer minibuffer level. */ @@ -2272,6 +2278,8 @@ init_minibuf_once (void) staticpro (&Vminibuffer_list); staticpro (&Vcommand_loop_level_list); pdumper_do_now_and_after_load (init_minibuf_once_for_pdumper); + /* Ensure our inactive minibuffer exists. */ + get_minibuffer (0); } static void @@ -2337,6 +2345,7 @@ syms_of_minibuf (void) DEFSYM (Qminibuffer_completing_file_name, "minibuffer-completing-file-name"); DEFSYM (Qselect_frame_set_input_focus, "select-frame-set-input-focus"); DEFSYM (Qadd_to_history, "add-to-history"); + DEFSYM (Qpush_window_buffer_onto_prev, "push-window-buffer-onto-prev"); DEFVAR_LISP ("read-expression-history", Vread_expression_history, doc: /* A history list for arguments that are Lisp expressions to evaluate. diff --git a/src/window.c b/src/window.c index 0a14eca58fb..9961c54161d 100644 --- a/src/window.c +++ b/src/window.c @@ -7264,8 +7264,8 @@ restore_window_configuration (Lisp_Object configuration) { if (CONSP (configuration)) Fset_window_configuration (XCAR (configuration), - XCAR (XCDR (configuration)), - XCAR (XCDR (XCDR (configuration)))); + Fcar_safe (XCDR (configuration)), + Fcar_safe (Fcdr_safe (XCDR (configuration)))); else Fset_window_configuration (configuration, Qnil, Qnil); }