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
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
\f
* 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
;; 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.
/* 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))
/* 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)
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.
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);
(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