diff options
author | martin rudalics <rudalics@gmx.at> | 2023-02-12 10:33:11 +0100 |
---|---|---|
committer | Eli Zaretskii <eliz@gnu.org> | 2023-02-18 19:24:59 +0200 |
commit | 9f508cef85df64ccbafada477bbb17a8439bc839 (patch) | |
tree | a5b47bb28e0906bdf4c4e237f77aa4a631700458 /lisp | |
parent | 5190ea6259a5fd13ba5e87b92b20f450658cf532 (diff) | |
download | emacs-9f508cef85df64ccbafada477bbb17a8439bc839.tar.gz emacs-9f508cef85df64ccbafada477bbb17a8439bc839.tar.bz2 emacs-9f508cef85df64ccbafada477bbb17a8439bc839.zip |
Fix 'display-buffer-use-least-recent-window'
* src/window.c (Fwindow_use_time): Doc fix.
(Fwindow_bump_use_time): Bump use time of the seleceted window as
well. Doc fix.
* lisp/window.el (display-buffer-avoid-small-windows): Remove.
All users changed.
(window--display-buffer): Bump window use time when requested.
(display-buffer--lru-window): New function.
(display-buffer-use-some-window): Use it.
(display-buffer-use-least-recent-window): Rewrite and enhance doc
string.
* doc/lispref/windows.texi (Selecting Windows)
(Buffer Display Action Functions, Buffer Display Action Alists)
(The Zen of Buffer Display): Improve and update documentation of
window selection and display facilities.
Diffstat (limited to 'lisp')
-rw-r--r-- | lisp/window.el | 169 |
1 files changed, 143 insertions, 26 deletions
diff --git a/lisp/window.el b/lisp/window.el index 2d9f746d8fb..083fa9bfd2f 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -2484,14 +2484,6 @@ and no others." (defalias 'some-window 'get-window-with-predicate) -(defcustom display-buffer-avoid-small-windows nil - "If non-nil, windows that have fewer lines than this are avoided. -This is used by `get-lru-window'. The value is interpreted in units -of the frame's canonical line height, like `window-total-height' does." - :type '(choice (const nil) number) - :version "29.1" - :group 'windows) - (defun get-lru-window (&optional all-frames dedicated not-selected no-other) "Return the least recently used window on frames specified by ALL-FRAMES. Return a full-width window if possible. A minibuffer window is @@ -2517,11 +2509,7 @@ have special meanings: - A frame means consider all windows on that frame only. Any other value of ALL-FRAMES means consider all windows on the -selected frame and no others. - -`display-buffer-avoid-small-windows', if non-nil, is also taken into -consideration. Windows whose height is smaller that the value of that -variable will be avoided if larger windows are available." +selected frame and no others." (let ((windows (window-list-1 nil 'nomini all-frames)) best-window best-time second-best-window second-best-time time) (dolist (window windows) @@ -2531,9 +2519,6 @@ variable will be avoided if larger windows are available." (not (window-parameter window 'no-other-window)))) (setq time (window-use-time window)) (if (or (eq window (selected-window)) - (and display-buffer-avoid-small-windows - (< (window-height window) - display-buffer-avoid-small-windows)) (not (window-full-width-p window))) (when (or (not second-best-time) (< time second-best-time)) (setq second-best-time time) @@ -7274,6 +7259,11 @@ entry. Otherwise, if WINDOW is new and the value of dedicated flag to that value. In any other case, reset WINDOW's dedicated flag to nil. +If ALIST contains a non-nil `bump-use-time' entry, bump use time +of WINDOW so further calls of `display-buffer-use-some-window' +and `display-buffer-use-least-recent-window' will try to avoid +it. + Return WINDOW if BUFFER and WINDOW are live." (when (and (buffer-live-p buffer) (window-live-p window)) (display-buffer-record-window type window buffer) @@ -7281,6 +7271,10 @@ Return WINDOW if BUFFER and WINDOW are live." ;; Unless WINDOW already shows BUFFER reset its dedicated flag. (set-window-dedicated-p window nil) (set-window-buffer window buffer)) + (when (cdr (assq 'bump-use-time alist)) + ;; Bump WINDOW's use time so 'display-buffer--lru-window' will try + ;; to avoid it. + (window-bump-use-time window)) (let ((alist-dedicated (assq 'dedicated alist))) ;; Maybe dedicate WINDOW to BUFFER if asked for. (cond @@ -8502,15 +8496,64 @@ indirectly called by the latter." (when (setq window (or best-window second-best-window)) (window--display-buffer buffer window 'reuse alist)))) -(defun display-buffer-use-least-recent-window (buffer alist) - "Display BUFFER in an existing window, but that hasn't been used lately. -This `display-buffer' action function is like -`display-buffer-use-some-window', but will cycle through windows -when displaying buffers repeatedly, and if there's only a single -window, it will split the window." - (when-let ((window (display-buffer-use-some-window - buffer (cons (cons 'inhibit-same-window t) alist)))) - (window-bump-use-time window))) +(defun display-buffer--lru-window (alist) + "Return the least recently used window according to ALIST. +Do not return a minibuffer window or a window dedicated to its +buffer. ALIST is a buffer display action alist as compiled by +`display-buffer'. The following ALIST entries are honored: + +- `lru-frames' specifies the frames to investigate and has the + same meaning as the ALL-FRAMES argument of `get-lru-window'. + +- `lru-time' specifies a use time. Do not return a window whose + use time is higher than this. + +- `window-min-width' specifies a preferred minimum width in + canonical frame columns. If it is the constant `full-width', + prefer a full-width window. + +- `window-min-height' specifies a preferred minimum height in + canonical frame lines. If it is the constant `full-height', + prefer a full-height window. + +If ALIST contains a non-nil `inhibit-same--window' entry, do not +return the selected window." + (let ((windows + (window-list-1 nil 'nomini (cdr (assq 'lru-frames alist)))) + (lru-time (cdr (assq 'lru-time alist))) + (min-width (cdr (assq 'window-min-width alist))) + (min-height (cdr (assq 'window-min-height alist))) + (not-this-window (cdr (assq 'inhibit-same-window alist))) + best-window best-time second-best-window second-best-time time) + (dolist (window windows) + (when (and (not (window-dedicated-p window)) + (or (not not-this-window) + (not (eq window (selected-window))))) + (setq time (window-use-time window)) + (unless (and (numberp lru-time) (> time lru-time)) + (if (or (eq window (selected-window)) + (and min-width + (or (and (numberp min-width) + (< (window-width window) min-width)) + (and (eq min-width 'full-width) + (not (window-full-width-p window))))) + (and min-height + (or (and (numberp min-height) + (< (window-height window) min-height)) + (and (eq min-height 'full-height) + (not (window-full-height-p window)))))) + ;; This window is either selected or does not meet the size + ;; restrictions - so it's only a second best choice. Try to + ;; find a more recently used one that fits. + (when (or (not second-best-time) (< time second-best-time)) + (setq second-best-time time) + (setq second-best-window window)) + ;; This window is not selected and does meet the size + ;; restrictions. It's the best choice so far. + (when (or (not best-time) (< time best-time)) + (setq best-time time) + (setq best-window window)))))) + (or best-window second-best-window))) (defun display-buffer-use-some-window (buffer alist) "Display BUFFER in an existing window. @@ -8534,7 +8577,11 @@ indirectly called by the latter." (window--frame-usable-p (last-nonminibuffer-frame)))) (window ;; Reuse an existing window. - (or (get-lru-window frame nil not-this-window) + (or (display-buffer--lru-window + ;; If ALIST specifies 'lru-frames' or 'window-min-width' + ;; let them prevail. + (append alist `((lru-frames . ,frame) + (window-min-width . full-width)))) (let ((window (get-buffer-window buffer 'visible))) (unless (and not-this-window (eq window (selected-window))) @@ -8564,6 +8611,76 @@ indirectly called by the latter." (unless (cdr (assq 'inhibit-switch-frame alist)) (window--maybe-raise-frame (window-frame window))))))) +(defun display-buffer-use-least-recent-window (buffer alist) + "Display BUFFER trying to avoid windows used recently. +This is similar to `display-buffer-use-some-window' but tries +hard to avoid using a window recently used by `display-buffer'. + +Distinctive features are: + +- Do not use the selected window. + +- Try first to reuse a window that shows BUFFER already on a + frame specified by a `reusable-frames' ALIST entry, using the + selected frame if no such entry has been specified. + +- Next try to show BUFFER in the least recently used window. The + frames to search for such a window can be specified via a + `lru-frames' ALIST entry; if no such entry exists, search the + selected frame only. In addition, try to satisfy constraints + specified by the following ALIST entries, if present: + + `lru-time' specifies a use time. Do not return a window whose + use time is higher than this. When calling this action + function repeatedly (presumably to display several buffers in + a row), an application should first save the use time of the + selected window and pass that same value via such an entry in + each call of `display-buffer'. This reduces the probability + that `display-buffer' uses the same window as a previous + call. + + `window-min-width' specifies a preferred minimum width in + canonical frame columns. If it is the constant `full-width', + prefer a full-width window. + + `window-min-height' specifies a preferred minimum height in + canonical frame lines. If it is the constant `full-height', + prefer a full-height window. + +- If the preceding steps fail, try to pop up a new window on the + selected frame. + +If a window is found, bump the use time of that window to the +highest use time after the selected window. This makes it less +probable that a future invocation of this function uses that +window for another buffer." + (let* ((alist (cons (cons 'inhibit-same-window t) alist)) + (window + (or (display-buffer-reuse-window buffer alist) + (let ((window (display-buffer--lru-window alist))) + (when (window-live-p window) + (let* ((quit-restore (window-parameter window 'quit-restore)) + (quad (nth 1 quit-restore))) + ;; If the window was used by `display-buffer' before, try to + ;; resize it to its old height but don't signal an error. + (when (and (listp quad) + (integerp (nth 3 quad)) + (> (nth 3 quad) (window-total-height window))) + (condition-case nil + (window-resize + window (- (nth 3 quad) (window-total-height window))) + (error nil))) + (prog1 + (window--display-buffer buffer window 'reuse alist) + (window--even-window-sizes window) + (unless (cdr (assq 'inhibit-switch-frame alist)) + (window--maybe-raise-frame (window-frame window))))))) + (display-buffer-pop-up-window buffer alist)))) + ;; Don't bump use time twice. + (when (and window (not (cdr (assq 'bump-use-time alist)))) + (window-bump-use-time window)) + window)) + (defun display-buffer-no-window (_buffer alist) "Display BUFFER in no window. ALIST is an association list of action symbols and values. See |