summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2020-10-31 09:07:53 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2020-10-31 09:07:53 -0400
commit7103192cd2b0434c7acf712d0b7cf5a2f7b19e75 (patch)
tree14333414af14ff4035a27ec26f67ab177394ae01
parentc3a20804a81826ec091a4a096c1987a61e412580 (diff)
downloademacs-7103192cd2b0434c7acf712d0b7cf5a2f7b19e75.tar.gz
* 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.
-rw-r--r--doc/emacs/display.texi4
-rw-r--r--etc/NEWS3
-rw-r--r--lisp/simple.el6
-rw-r--r--src/xdisp.c17
-rw-r--r--test/src/xdisp-tests.el71
5 files changed, 72 insertions, 29 deletions
diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi
index 02859d522e3..7dadb0966f2 100644
--- a/doc/emacs/display.texi
+++ b/doc/emacs/display.texi
@@ -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
diff --git a/etc/NEWS b/etc/NEWS
index 4435d0563be..a52122bceaf 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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
diff --git a/lisp/simple.el b/lisp/simple.el
index a9d79d031e8..d871be104cf 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -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.
diff --git a/src/xdisp.c b/src/xdisp.c
index 0e5dffbe007..cc499f33261 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -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);
diff --git a/test/src/xdisp-tests.el b/test/src/xdisp-tests.el
index 95c39dacc3e..fad90fad531 100644
--- a/test/src/xdisp-tests.el
+++ b/test/src/xdisp-tests.el
@@ -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