bug#81630: 32.0.50; completions-format 'vertical scrolls the completion window on TAB tapping

Stephen Berman via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <[email protected]>
Newsgroups gmane.emacs.bugs
Message-ID <[email protected]>
On Tue, 18 Aug 2026 13:34:42 -0400 Stefan Monnier <[email protected]> wrote:

>> @@ -1765,7 +1765,11 @@ completion--in-region-1
>>              (with-selected-window window (scroll-down))))
>>           ;; Normal tab
>>           (t
>> -          (if (pos-visible-in-window-p (point-max) window)
>> +          (if (pos-visible-in-window-p
>> +               (if (eq completions-format 'vertical)
>> +                   (1- (point-max))     ; Vertical format has final newline.
>> +                 (point-max))
>> +               window)
>>                ;; If end is in view, scroll up to the end.
>>                (set-window-start window (point-min) nil)
>>              ;; Else scroll down one screen.
>
> Rather than test `completions-format`, we should test if the last char
> is a LF.

Thanks, that's a better approach.  The attached patched works for me; is
that what you had in mind?  (It also covers the S-TAB case, which I
neglected in my first patch.)

Steve Berman
(unnamed) (text/x-patch, 2.6 KB)
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 4da651cc450..4212e9cdc50 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1751,25 +1751,31 @@ completion--in-region-1
          (eq t (frame-visible-p (window-frame minibuffer-scroll-window))))
     (let ((window minibuffer-scroll-window))
       (with-current-buffer (window-buffer window)
-        (cond
-         ;; Here this is possible only when second-tab, but instead of
-         ;; scrolling the completion list window, switch to it below,
-         ;; outside of `with-current-buffer'.
-         ((eq completion-auto-select 'second-tab))
-         ;; Reverse tab
-         ((equal (this-command-keys) [backtab])
-          (if (pos-visible-in-window-p (point-min) window)
-              ;; If beginning is in view, scroll up to the end.
-              (set-window-point window (point-max))
-            ;; Else scroll down one screen.
-            (with-selected-window window (scroll-down))))
-         ;; Normal tab
-         (t
-          (if (pos-visible-in-window-p (point-max) window)
-              ;; If end is in view, scroll up to the end.
-              (set-window-start window (point-min) nil)
-            ;; Else scroll down one screen.
-            (with-selected-window window (scroll-up))))))
+        (let* ((pm (point-max))
+               ;; If completions buffer ends in a newline (e.g. when
+               ;; `completions-format' is 'vertical), disregard that
+               ;; when checking `pos-visible-in-window-p' to prevent
+               ;; unnecessary scrolling (bug#81630).
+               (pt (if (eq (char-before pm) ?\C-j) (1- pm) pm)))
+          (cond
+           ;; Here this is possible only when second-tab, but instead of
+           ;; scrolling the completion list window, switch to it below,
+           ;; outside of `with-current-buffer'.
+           ((eq completion-auto-select 'second-tab))
+           ;; Reverse tab
+           ((equal (this-command-keys) [backtab])
+            (if (pos-visible-in-window-p (point-min) window)
+                ;; If beginning is in view, scroll up to the end.
+                (set-window-point window pt)
+              ;; Else scroll down one screen.
+              (with-selected-window window (scroll-down))))
+           ;; Normal tab
+           (t
+            (if (pos-visible-in-window-p pt window)
+                ;; If end is in view, scroll up to the end.
+                (set-window-start window (point-min) nil)
+              ;; Else scroll down one screen.
+              (with-selected-window window (scroll-up)))))))
       (when (eq completion-auto-select 'second-tab)
         (switch-to-completions))
       nil))
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.