* src/xdisp.c (syms_of_xdisp) <"scroll-minibuffer-conservatively">: New var

Fix bug#44070, which causes the minibuffer display to jump upon minor edit

(redisplay_window): Obey it.
* lisp/simple.el (end-of-buffer): Obey it.

* test/src/xdisp-tests.el (xdisp-tests--in-minibuffer): New macro,
extracted from `xdisp-tests--minibuffer-resizing`.
(xdisp-tests--minibuffer-resizing): Use it.
(xdisp-tests--minibuffer-scroll): New test.
This commit is contained in:
Stefan Monnier
2020-10-31 09:07:53 -04:00
parent c3a20804a8
commit 7103192cd2
5 changed files with 72 additions and 29 deletions

View File

@@ -244,6 +244,7 @@ point vertically in the window, but there are several ways to alter
this behavior.
@vindex scroll-conservatively
@vindex scroll-minibuffer-conservatively
If you set @code{scroll-conservatively} to a small number @var{n},
then moving point just a little off the screen (no more than @var{n}
lines) causes Emacs to scroll just enough to bring point back on
@@ -255,6 +256,9 @@ moves; Emacs always scrolls text just enough to bring point into view,
either at the top or bottom of the window depending on the scroll
direction. By default, @code{scroll-conservatively} is@tie{}0, which
means to always center point in the window.
This said, in minibuffer windows, scrolling is always conservative by
default because @code{scroll-minibuffer-conservatively} is non-nil,
which takes precedence over @code{scroll-conservatively}.
@vindex scroll-step
Another way to control automatic scrolling is to customize the

View File

@@ -85,6 +85,9 @@ useful on systems such as FreeBSD which ships only with "etc/termcap".
* Changes in Emacs 28.1
** Minibuffer scrolling is now conservative by default.
This is controlled by the new variable 'scroll-minibuffer-conservatively'.
+++
** New system for displaying documentation for groups of function.
This can either be used by saying 'M-x shortdoc-display-group' and

View File

@@ -1134,7 +1134,11 @@ is supplied, or Transient Mark mode is enabled and the mark is active."
;; If the end of the buffer is not already on the screen,
;; then scroll specially to put it near, but not at, the bottom.
(overlay-recenter (point))
(recenter -3))))
;; FIXME: Arguably if `scroll-conservatively' is set, then
;; we should pass -1 to `recenter'.
(recenter (if (and scroll-minibuffer-conservatively
(window-minibuffer-p))
-1 -3)))))
(defcustom delete-active-region t
"Whether single-char deletion commands delete an active region.

View File

@@ -18820,6 +18820,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
/* Try to scroll by specified few lines. */
if ((0 < scroll_conservatively
|| (scroll_minibuffer_conservatively && MINI_WINDOW_P (w))
|| 0 < emacs_scroll_step
|| temp_scroll_step
|| NUMBERP (BVAR (current_buffer, scroll_up_aggressively))
@@ -18830,7 +18831,10 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
/* The function returns -1 if new fonts were loaded, 1 if
successful, 0 if not successful. */
int ss = try_scrolling (window, just_this_one_p,
scroll_conservatively,
((scroll_minibuffer_conservatively
&& MINI_WINDOW_P (w))
? SCROLL_LIMIT + 1
: scroll_conservatively),
emacs_scroll_step,
temp_scroll_step, last_line_misfit);
switch (ss)
@@ -34538,7 +34542,14 @@ syms_of_xdisp (void)
DEFSYM (Qredisplay_internal_xC_functionx, "redisplay_internal (C function)");
DEFVAR_BOOL("inhibit-message", inhibit_message,
DEFVAR_BOOL ("scroll-minibuffer-conservatively",
scroll_minibuffer_conservatively,
doc: /* Non-nil means scroll conservatively in minibuffer windows.
When the value is nil, scrolling in minibuffer windows obeys the
settings of `scroll-conservatively'. */);
scroll_minibuffer_conservatively = true; /* bug#44070 */
DEFVAR_BOOL ("inhibit-message", inhibit_message,
doc: /* Non-nil means calls to `message' are not displayed.
They are still logged to the *Messages* buffer.
@@ -34546,7 +34557,7 @@ Do NOT set this globally to a non-nil value, as doing that will
disable messages everywhere, including in I-search and other
places where they are necessary. This variable is intended to
be let-bound around code that needs to disable messages temporarily. */);
inhibit_message = 0;
inhibit_message = false;
message_dolog_marker1 = Fmake_marker ();
staticpro (&message_dolog_marker1);

View File

@@ -21,34 +21,55 @@
(require 'ert)
(defmacro xdisp-tests--in-minibuffer (&rest body)
(declare (debug t) (indent 0))
`(catch 'result
(minibuffer-with-setup-hook
(lambda ()
(let ((redisplay-skip-initial-frame nil)
(executing-kbd-macro nil)) ;Don't skip redisplay
(throw 'result (progn . ,body))))
(let ((executing-kbd-macro t)) ;Force real minibuffer in `read-string'.
(read-string "toto: ")))))
(ert-deftest xdisp-tests--minibuffer-resizing () ;; bug#43519
;; FIXME: This test returns success when run in batch but
;; it's only a lucky accident: it also returned success
;; when bug#43519 was not fixed.
(should
(equal
t
(catch 'result
(minibuffer-with-setup-hook
(lambda ()
(insert "hello")
(let ((ol (make-overlay (point) (point)))
(redisplay-skip-initial-frame nil)
(max-mini-window-height 1)
(text "askdjfhaklsjdfhlkasjdfhklasdhflkasdhflkajsdhflkashdfkljahsdlfkjahsdlfkjhasldkfhalskdjfhalskdfhlaksdhfklasdhflkasdhflkasdhflkajsdhklajsdgh"))
;; (save-excursion (insert text))
;; (sit-for 2)
;; (delete-region (point) (point-max))
(put-text-property 0 1 'cursor t text)
(overlay-put ol 'after-string text)
(let ((executing-kbd-macro nil)) ;Don't skip redisplay
(redisplay 'force))
(throw 'result
;; Make sure we do the see "hello" text.
(prog1 (equal (window-start) (point-min))
;; (list (window-start) (window-end) (window-width))
(delete-overlay ol)))))
(let ((executing-kbd-macro t)) ;Force real minibuffer in `read-string'.
(read-string "toto: ")))))))
(xdisp-tests--in-minibuffer
(insert "hello")
(let ((ol (make-overlay (point) (point)))
(max-mini-window-height 1)
(text "askdjfhaklsjdfhlkasjdfhklasdhflkasdhflkajsdhflkashdfkljahsdlfkjahsdlfkjhasldkfhalskdjfhalskdfhlaksdhfklasdhflkasdhflkasdhflkajsdhklajsdgh"))
;; (save-excursion (insert text))
;; (sit-for 2)
;; (delete-region (point) (point-max))
(put-text-property 0 1 'cursor t text)
(overlay-put ol 'after-string text)
(redisplay 'force)
;; Make sure we do the see "hello" text.
(prog1 (equal (window-start) (point-min))
;; (list (window-start) (window-end) (window-width))
(delete-overlay ol)))))))
(ert-deftest xdisp-tests--minibuffer-scroll () ;; bug#44070
(let ((posns
(xdisp-tests--in-minibuffer
(let ((max-mini-window-height 4))
(dotimes (_ 80) (insert "\nhello"))
(beginning-of-buffer)
(redisplay 'force)
(end-of-buffer)
;; A simple edit like removing the last `o' shouldn't cause
;; the rest of the minibuffer's text to move.
(list
(progn (redisplay 'force) (window-start))
(progn (delete-char -1)
(redisplay 'force) (window-start))
(progn (goto-char (point-min)) (redisplay 'force)
(goto-char (point-max)) (redisplay 'force)
(window-start)))))))
(should (equal (nth 0 posns) (nth 1 posns)))
(should (equal (nth 1 posns) (nth 2 posns)))))
;;; xdisp-tests.el ends here