From: Stefan Monnier Date: Sat, 31 Oct 2020 13:07:53 +0000 (-0400) Subject: * src/xdisp.c (syms_of_xdisp) <"scroll-minibuffer-conservatively">: New var X-Git-Tag: emacs-28.0.90~5316 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=7103192cd2b0434c7acf712d0b7cf5a2f7b19e75;p=emacs.git * 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. --- 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