summaryrefslogtreecommitdiff
path: root/lisp/window.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/window.el')
-rw-r--r--lisp/window.el492
1 files changed, 346 insertions, 146 deletions
diff --git a/lisp/window.el b/lisp/window.el
index a47a1216d10..7f1265b9ace 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -108,11 +108,14 @@ Return the buffer."
;; Return the buffer.
buffer)))
+;; Defined in help.el.
+(defvar resize-temp-buffer-window-inhibit)
+
(defun temp-buffer-window-show (buffer &optional action)
"Show temporary buffer BUFFER in a window.
Return the window showing BUFFER. Pass ACTION as action argument
to `display-buffer'."
- (let (window frame)
+ (let (resize-temp-buffer-window-inhibit window)
(with-current-buffer buffer
(set-buffer-modified-p nil)
(setq buffer-read-only t)
@@ -130,9 +133,9 @@ to `display-buffer'."
t
window-combination-limit)))
(setq window (display-buffer buffer action)))
- (setq frame (window-frame window))
- (unless (eq frame (selected-frame))
- (raise-frame frame))
+ ;; We used to raise the window's frame here. Do not do that
+ ;; since it would override an `inhibit-switch-frame' entry
+ ;; specified for the action alist used by `display-buffer'.
(setq minibuffer-scroll-window window)
(set-window-hscroll window 0)
(with-selected-window window
@@ -1514,21 +1517,11 @@ Emacs won't change the size of any window displaying that buffer,
unless it has no other choice (like when deleting a neighboring
window).")
-(defun window--preservable-size (window &optional horizontal)
- "Return height of WINDOW as `window-preserve-size' would preserve it.
-Optional argument HORIZONTAL non-nil means to return the width of
-WINDOW as `window-preserve-size' would preserve it."
- (if horizontal
- (window-body-width window t)
- (+ (window-body-height window t)
- (window-header-line-height window)
- (window-mode-line-height window))))
-
(defun window-preserve-size (&optional window horizontal preserve)
- "Preserve height of window WINDOW.
+ "Preserve height of specified WINDOW's body.
WINDOW must be a live window and defaults to the selected one.
-Optional argument HORIZONTAL non-nil means preserve the width of
-WINDOW.
+Optional argument HORIZONTAL non-nil means to preserve the width
+of WINDOW's body.
PRESERVE t means to preserve the current height/width of WINDOW's
body in frame and window resizing operations whenever possible.
@@ -1545,21 +1538,15 @@ WINDOW as argument also removes the respective restraint.
Other values of PRESERVE are reserved for future use."
(setq window (window-normalize-window window t))
(let* ((parameter (window-parameter window 'window-preserved-size))
- (width (nth 1 parameter))
- (height (nth 2 parameter)))
- (if horizontal
- (set-window-parameter
- window 'window-preserved-size
- (list
- (window-buffer window)
- (and preserve (window--preservable-size window t))
- height))
- (set-window-parameter
- window 'window-preserved-size
- (list
- (window-buffer window)
- width
- (and preserve (window--preservable-size window)))))))
+ (width (if horizontal
+ (and preserve (window-body-width window t))
+ (nth 1 parameter)))
+ (height (if horizontal
+ (nth 2 parameter)
+ (and preserve (window-body-height window t)))))
+ (set-window-parameter
+ window 'window-preserved-size
+ (list (window-buffer window) width height))))
(defun window-preserved-size (&optional window horizontal)
"Return preserved height of window WINDOW.
@@ -1567,12 +1554,9 @@ WINDOW must be a live window and defaults to the selected one.
Optional argument HORIZONTAL non-nil means to return preserved
width of WINDOW."
(setq window (window-normalize-window window t))
- (let* ((parameter (window-parameter window 'window-preserved-size))
- (buffer (nth 0 parameter))
- (width (nth 1 parameter))
- (height (nth 2 parameter)))
- (when (eq buffer (window-buffer window))
- (if horizontal width height))))
+ (let ((parameter (window-parameter window 'window-preserved-size)))
+ (when (eq (nth 0 parameter) (window-buffer window))
+ (nth (if horizontal 1 2) parameter))))
(defun window--preserve-size (window horizontal)
"Return non-nil when the height of WINDOW shall be preserved.
@@ -1580,7 +1564,7 @@ Optional argument HORIZONTAL non-nil means to return non-nil when
the width of WINDOW shall be preserved."
(let ((size (window-preserved-size window horizontal)))
(and (numberp size)
- (= size (window--preservable-size window horizontal)))))
+ (= size (window-body-size window horizontal t)))))
(defun window-safe-min-size (&optional window horizontal pixelwise)
"Return safe minimum size of WINDOW.
@@ -2504,15 +2488,23 @@ 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 the least recently used window on frames specified by ALL-FRAMES.
Return a full-width window if possible. A minibuffer window is
never a candidate. A dedicated window is never a candidate
unless DEDICATED is non-nil, so if all windows are dedicated, the
value is nil. Avoid returning the selected window if possible.
Optional argument NOT-SELECTED non-nil means never return the
selected window. Optional argument NO-OTHER non-nil means to
-never return a window whose 'no-other-window' parameter is
+never return a window whose `no-other-window' parameter is
non-nil.
The following non-nil values of the optional argument ALL-FRAMES
@@ -2529,15 +2521,23 @@ 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."
- (let (best-window best-time second-best-window second-best-time time)
- (dolist (window (window-list-1 nil 'nomini all-frames))
+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."
+ (let ((windows (window-list-1 nil 'nomini all-frames))
+ best-window best-time second-best-window second-best-time time)
+ (dolist (window windows)
(when (and (or dedicated (not (window-dedicated-p window)))
(or (not not-selected) (not (eq window (selected-window))))
(or (not no-other)
(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)
@@ -2554,7 +2554,7 @@ never a candidate unless DEDICATED is non-nil, so if all windows
are dedicated, the value is nil. Optional argument NOT-SELECTED
non-nil means never return the selected window. Optional
argument NO-OTHER non-nil means to never return a window whose
-'no-other-window' parameter is non-nil.
+`no-other-window' parameter is non-nil.
The following non-nil values of the optional argument ALL-FRAMES
have special meanings:
@@ -2590,7 +2590,7 @@ never a candidate unless DEDICATED is non-nil, so if all windows
are dedicated, the value is nil. Optional argument NOT-SELECTED
non-nil means never return the selected window. Optional
argument NO-OTHER non-nil means to never return a window whose
-'no-other-window' parameter is non-nil.
+`no-other-window' parameter is non-nil.
The following non-nil values of the optional argument ALL-FRAMES
have special meanings:
@@ -4181,8 +4181,8 @@ another live window on that frame to serve as its selected
window. This option allows to control which window gets selected
instead.
-The possible choices are 'mru' (the default) to select the most
-recently used window on that frame, and 'pos' to choose the
+The possible choices are `mru' (the default) to select the most
+recently used window on that frame, and `pos' to choose the
window at the frame coordinates of point of the previously
selected window. If this is nil, choose the frame's first window
instead. A window with a non-nil `no-other-window' parameter is
@@ -4594,7 +4594,9 @@ as well. In that case, if this option specifies a function, it
will be called with the third argument nil.
Under certain circumstances `switch-to-prev-buffer' may ignore
-this option, for example, when there is only one buffer left."
+this option, for example, when there is only one buffer left.
+
+Also see `switch-to-prev-buffer-skip-regexp'."
:type
'(choice (const :tag "Never" nil)
(const :tag "This frame" this)
@@ -4605,16 +4607,37 @@ this option, for example, when there is only one buffer left."
:version "27.1"
:group 'windows)
+(defcustom switch-to-prev-buffer-skip-regexp nil
+ "Buffers that `switch-to-prev-buffer' and `switch-to-next-buffer' should skip.
+The value can either be a regexp or a list of regexps. Buffers whose
+names match these regexps are skipped by `switch-to-prev-buffer'
+and `switch-to-next-buffer'.
+
+Also see `switch-to-prev-buffer-skip'."
+ :type '(choice regexp
+ (repeat regexp))
+ :version "29.1"
+ :group 'windows)
+
(defun switch-to-prev-buffer-skip-p (skip window buffer &optional bury-or-kill)
"Return non-nil if `switch-to-prev-buffer' should skip BUFFER.
SKIP is a value derived from `switch-to-prev-buffer-skip', WINDOW
the window `switch-to-prev-buffer' acts upon. Optional argument
BURY-OR-KILL is passed unchanged by `switch-to-prev-buffer' and
omitted in calls from `switch-to-next-buffer'."
- (when skip
- (if (functionp skip)
- (funcall skip window buffer bury-or-kill)
- (get-buffer-window buffer skip))))
+ (or (and skip
+ (if (functionp skip)
+ (funcall skip window buffer bury-or-kill)
+ (get-buffer-window buffer skip)))
+ (and switch-to-prev-buffer-skip-regexp
+ (or (and (stringp switch-to-prev-buffer-skip-regexp)
+ (string-match-p switch-to-prev-buffer-skip-regexp
+ (buffer-name buffer)))
+ (and (consp switch-to-prev-buffer-skip-regexp)
+ (catch 'found
+ (dolist (regexp switch-to-prev-buffer-skip-regexp)
+ (when (string-match-p regexp (buffer-name buffer))
+ (throw 'tag t)))))))))
(defun switch-to-prev-buffer (&optional window bury-or-kill)
"In WINDOW switch to previous buffer.
@@ -4902,10 +4925,7 @@ the buffer `*scratch*', creating it if necessary."
(setq frame (or frame (selected-frame)))
(or (get-next-valid-buffer (nreverse (buffer-list frame))
buffer visible-ok frame)
- (get-buffer "*scratch*")
- (let ((scratch (get-buffer-create "*scratch*")))
- (set-buffer-major-mode scratch)
- scratch)))
+ (get-scratch-buffer-create)))
(defcustom frame-auto-hide-function #'iconify-frame
"Function called to automatically hide frames.
@@ -5023,7 +5043,11 @@ minibuffer window or is dedicated to its buffer."
BUFFER-OR-NAME may be a buffer or the name of an existing buffer
and defaults to the current buffer.
-Interactively, prompt for the buffer.
+Interactively, this command will prompt for the buffer name. A
+prefix argument of 0 (zero) means that only windows in the
+current terminal's frames will be deleted. Any other prefix
+argument means that only windows in the current frame will be
+deleted.
The following non-nil values of the optional argument FRAME
have special meanings:
@@ -5060,7 +5084,21 @@ If the buffer specified by BUFFER-OR-NAME is shown in a
minibuffer window, do nothing for that window. For any window
that does not show that buffer, remove the buffer from that
window's lists of previous and next buffers."
- (interactive "bDelete windows on (buffer):\nP")
+ (interactive
+ (let ((frame (cond
+ ((and (numberp current-prefix-arg)
+ (zerop current-prefix-arg))
+ 0)
+ (current-prefix-arg t))))
+ (list (read-buffer "Delete windows on (buffer): "
+ nil nil
+ (lambda (buf)
+ (get-buffer-window
+ (if (consp buf) (car buf) buf)
+ (cond
+ ((null frame) t)
+ ((numberp frame) frame)))))
+ frame)))
(let ((buffer (window-normalize-buffer buffer-or-name))
;; Handle the "inverted" meaning of the FRAME argument wrt other
;; `window-list-1' based function.
@@ -5120,6 +5158,14 @@ all window-local buffer lists."
:version "27.1"
:group 'windows)
+(defun window--quit-restore-select-window (window)
+ "Select WINDOW after having quit another one.
+Do not select an inactive minibuffer window."
+ (when (and (window-live-p window)
+ (or (not (window-minibuffer-p window))
+ (minibuffer-window-active-p window)))
+ (select-window window)))
+
(defun quit-restore-window (&optional window bury-or-kill)
"Quit WINDOW and deal with its buffer.
WINDOW must be a live window and defaults to the selected one.
@@ -5133,7 +5179,7 @@ parameter to nil. See Info node `(elisp) Quitting Windows' for
more details.
If WINDOW's dedicated flag is t, try to delete WINDOW. If it
-equals the value 'side', restore that value when WINDOW is not
+equals the value `side', restore that value when WINDOW is not
deleted.
Optional second argument BURY-OR-KILL tells how to proceed with
@@ -5158,6 +5204,7 @@ nil means to not handle the buffer in a particular way. This
(setq window (window-normalize-window window t))
(let* ((buffer (window-buffer window))
(quit-restore (window-parameter window 'quit-restore))
+ (quit-restore-2 (nth 2 quit-restore))
(prev-buffer (catch 'prev-buffer
(dolist (buf (window-prev-buffers window))
(unless (eq (car buf) buffer)
@@ -5169,15 +5216,13 @@ nil means to not handle the buffer in a particular way. This
((and dedicated (not (eq dedicated 'side))
(window--delete window 'dedicated (eq bury-or-kill 'kill)))
;; If the previously selected window is still alive, select it.
- (when (window-live-p (nth 2 quit-restore))
- (select-window (nth 2 quit-restore))))
+ (window--quit-restore-select-window quit-restore-2))
((and (not prev-buffer)
(eq (nth 1 quit-restore) 'tab)
(eq (nth 3 quit-restore) buffer))
(tab-bar-close-tab)
;; If the previously selected window is still alive, select it.
- (when (window-live-p (nth 2 quit-restore))
- (select-window (nth 2 quit-restore))))
+ (window--quit-restore-select-window quit-restore-2))
((and (not prev-buffer)
(or (eq (nth 1 quit-restore) 'frame)
(and (eq (nth 1 quit-restore) 'window)
@@ -5189,8 +5234,7 @@ nil means to not handle the buffer in a particular way. This
;; Delete WINDOW if possible.
(window--delete window nil (eq bury-or-kill 'kill)))
;; If the previously selected window is still alive, select it.
- (when (window-live-p (nth 2 quit-restore))
- (select-window (nth 2 quit-restore))))
+ (window--quit-restore-select-window quit-restore-2))
((and (listp (setq quad (nth 1 quit-restore)))
(buffer-live-p (car quad))
(eq (nth 3 quit-restore) buffer))
@@ -5234,8 +5278,8 @@ nil means to not handle the buffer in a particular way. This
;; Reset the quit-restore parameter.
(set-window-parameter window 'quit-restore nil)
;; Select old window.
- (when (window-live-p (nth 2 quit-restore))
- (select-window (nth 2 quit-restore))))
+ ;; If the previously selected window is still alive, select it.
+ (window--quit-restore-select-window quit-restore-2))
(t
;; Show some other buffer in WINDOW and reset the quit-restore
;; parameter.
@@ -5248,8 +5292,8 @@ nil means to not handle the buffer in a particular way. This
(when (eq dedicated 'side)
(set-window-dedicated-p window 'side))
(window--delete window nil (eq bury-or-kill 'kill))
- (when (window-live-p (nth 2 quit-restore))
- (select-window (nth 2 quit-restore))))))
+ ;; If the previously selected window is still alive, select it.
+ (window--quit-restore-select-window quit-restore-2))))
;; Deal with the buffer.
(cond
@@ -5714,12 +5758,12 @@ right, if any."
;;; Balancing windows.
;; The following routine uses the recycled code from an old version of
-;; `window--resize-child-windows'. It's not very pretty, but coding it the way the
-;; new `window--resize-child-windows' code does would hardly make it any shorter or
-;; more readable (FWIW we'd need three loops - one to calculate the
-;; minimum sizes per window, one to enlarge or shrink windows until the
-;; new parent-size matches, and one where we shrink the largest/enlarge
-;; the smallest window).
+;; `window--resize-child-windows'. It's not very pretty, but coding it
+;; the way the new `window--resize-child-windows' code does would hardly
+;; make it any shorter or more readable (FWIW we'd need three loops -
+;; one to calculate the minimum sizes per window, one to enlarge or
+;; shrink windows until the new parent-size matches, and one where we
+;; shrink the largest/enlarge the smallest window).
(defun balance-windows-2 (window horizontal)
"Subroutine of `balance-windows-1'.
WINDOW must be a vertical combination (horizontal if HORIZONTAL
@@ -5730,9 +5774,10 @@ is non-nil)."
(first (window-child window))
(sub first)
(number-of-children 0)
+ (rest 0)
(parent-size (window-new-pixel window))
(total-sum parent-size)
- failed size sub-total sub-delta sub-amount rest)
+ failed size sub-total sub-delta sub-amount)
(while sub
(if (window-size-fixed-p sub horizontal)
(progn
@@ -7257,11 +7302,15 @@ Return WINDOW if BUFFER and WINDOW are live."
(inhibit-modification-hooks t))
(funcall (cdr (assq 'body-function alist)) window)))
- (let ((quit-restore (window-parameter window 'quit-restore))
- (height (cdr (assq 'window-height alist)))
- (width (cdr (assq 'window-width alist)))
- (size (cdr (assq 'window-size alist)))
- (preserve-size (cdr (assq 'preserve-size alist))))
+ (let* ((frame (window-frame window))
+ (quit-restore (window-parameter window 'quit-restore))
+ (window-height (assq 'window-height alist))
+ (height (cdr window-height))
+ (window-width (assq 'window-width alist))
+ (width (cdr window-width))
+ (window-size (assq 'window-size alist))
+ (size (cdr window-size))
+ (preserve-size (cdr (assq 'preserve-size alist))))
(cond
((or (eq type 'frame)
(and (eq (car quit-restore) 'same)
@@ -7272,29 +7321,43 @@ Return WINDOW if BUFFER and WINDOW are live."
;; Adjust size of frame if asked for. We probably should do
;; that only for a single window frame.
(cond
- ((not size))
+ ((not size)
+ (when window-size
+ (setq resize-temp-buffer-window-inhibit t)))
((consp size)
- (let ((width (car size))
- (height (cdr size))
- (frame (window-frame window)))
- (when (and (numberp width) (numberp height))
- (set-frame-height
- frame (+ (frame-height frame)
- (- height (window-total-height window))))
- (set-frame-width
- frame (+ (frame-width frame)
- (- width (window-total-width window)))))))
- ((functionp size)
- (ignore-errors (funcall size window)))))
+ ;; Modifying the parameters of a newly created frame might
+ ;; not work everywhere, but then `temp-buffer-resize-mode'
+ ;; will certainly fail in a similar fashion.
+ (if (eq (car size) 'body-chars)
+ (let ((width (+ (frame-text-width frame)
+ (* (frame-char-width frame) (cadr size))
+ (- (window-body-width window t))))
+ (height (+ (frame-text-height frame)
+ (* (frame-char-height frame) (cddr size))
+ (- (window-body-height window t)))))
+ (modify-frame-parameters
+ frame `((height . (text-pixels . ,height))
+ (width . (text-pixels . ,width)))))
+ (let ((width (- (+ (frame-width frame) (car size))
+ (window-total-width window)))
+ (height (- (+ (frame-height frame) (cdr size))
+ (window-total-height window))))
+ (modify-frame-parameters
+ frame `((height . ,height) (width . ,width)))))
+ (setq resize-temp-buffer-window-inhibit t))
+ ((functionp size)
+ (ignore-errors (funcall size window))
+ (setq resize-temp-buffer-window-inhibit t))))
((or (eq type 'window)
(and (eq (car quit-restore) 'same)
(eq (nth 1 quit-restore) 'window)))
;; A window that never showed another buffer but BUFFER ever
- ;; since it was created on an existing frame.
- ;;
- ;; Adjust width and/or height of window if asked for.
+ ;; since it was created on an existing frame. Adjust its width
+ ;; and/or height if asked for.
(cond
- ((not height))
+ ((not height)
+ (when window-height
+ (setq resize-temp-buffer-window-inhibit 'vertical)))
((numberp height)
(let* ((new-height
(if (integerp height)
@@ -7305,12 +7368,23 @@ Return WINDOW if BUFFER and WINDOW are live."
(delta (- new-height (window-total-height window))))
(when (and (window--resizable-p window delta nil 'safe)
(window-combined-p window))
- (window-resize window delta nil 'safe))))
- ((functionp height)
- (ignore-errors (funcall height window))))
+ (window-resize window delta nil 'safe)))
+ (setq resize-temp-buffer-window-inhibit 'vertical))
+ ((and (consp height) (eq (car height) 'body-lines))
+ (let* ((delta (- (* (frame-char-height frame) (cdr height))
+ (window-body-height window t))))
+ (and (window--resizable-p window delta nil 'safe nil nil nil t)
+ (window-combined-p window)
+ (window-resize window delta nil 'safe t)))
+ (setq resize-temp-buffer-window-inhibit 'vertical))
+ ((functionp height)
+ (ignore-errors (funcall height window))
+ (setq resize-temp-buffer-window-inhibit 'vertical)))
;; Adjust width of window if asked for.
(cond
- ((not width))
+ ((not width)
+ (when window-width
+ (setq resize-temp-buffer-window-inhibit 'horizontal)))
((numberp width)
(let* ((new-width
(if (integerp width)
@@ -7321,13 +7395,24 @@ Return WINDOW if BUFFER and WINDOW are live."
(delta (- new-width (window-total-width window))))
(when (and (window--resizable-p window delta t 'safe)
(window-combined-p window t))
- (window-resize window delta t 'safe))))
+ (window-resize window delta t 'safe)))
+ (setq resize-temp-buffer-window-inhibit 'horizontal))
+ ((and (consp width) (eq (car width) 'body-columns))
+ (let* ((delta (- (* (frame-char-width frame) (cdr width))
+ (window-body-width window t))))
+ (and (window--resizable-p window delta t 'safe nil nil nil t)
+ (window-combined-p window t)
+ (window-resize window delta t 'safe t)))
+ (setq resize-temp-buffer-window-inhibit 'horizontal))
((functionp width)
- (ignore-errors (funcall width window))))
+ (ignore-errors (funcall width window))
+ (setq resize-temp-buffer-window-inhibit 'horizontal)))
+
;; Preserve window size if asked for.
(when (consp preserve-size)
(window-preserve-size window t (car preserve-size))
(window-preserve-size window nil (cdr preserve-size)))))
+
;; Assign any window parameters specified.
(let ((parameters (cdr (assq 'window-parameters alist))))
(dolist (parameter parameters)
@@ -7366,6 +7451,7 @@ The actual non-nil value of this variable will be copied to the
(const display-buffer-pop-up-window)
(const display-buffer-same-window)
(const display-buffer-pop-up-frame)
+ (const display-buffer-full-frame)
(const display-buffer-in-child-frame)
(const display-buffer-below-selected)
(const display-buffer-at-bottom)
@@ -7415,9 +7501,9 @@ Its value takes effect before processing the ACTION argument of
If non-nil, this is an alist of elements (CONDITION . ACTION),
where:
- CONDITION is either a regexp matching buffer names, or a
- function that takes two arguments - a buffer name and the
- ACTION argument of `display-buffer' - and returns a boolean.
+ CONDITION is passed to `buffer-match-p', along with the buffer
+ that is to be displayed and the ACTION argument of
+ `display-buffer', to check if ACTION should be used.
ACTION is a cons cell (FUNCTIONS . ALIST), where FUNCTIONS is an
action function or a list of action functions and ALIST is an
@@ -7470,22 +7556,16 @@ all fail. It should never be set by programs or users. See
`display-buffer'.")
(put 'display-buffer-fallback-action 'risky-local-variable t)
-(defun display-buffer-assq-regexp (buffer-name alist action)
- "Retrieve ALIST entry corresponding to BUFFER-NAME.
-This returns the cdr of the alist entry ALIST if either its key
-is a string that matches BUFFER-NAME, as reported by
-`string-match-p'; or if the key is a function that returns
-non-nil when called with three arguments: the ALIST key,
-BUFFER-NAME and ACTION. ACTION should have the form of the
-action argument passed to `display-buffer'."
+(defun display-buffer-assq-regexp (buffer-or-name alist action)
+ "Retrieve ALIST entry corresponding to buffer specified by BUFFER-OR-NAME.
+This returns the cdr of the alist entry ALIST if the entry's
+key (its car) and BUFFER-OR-NAME satisfy `buffer-match-p', using
+the key as CONDITION argument of `buffer-match-p'. ACTION should
+have the form of the action argument passed to `display-buffer'."
(catch 'match
(dolist (entry alist)
- (let ((key (car entry)))
- (when (or (and (stringp key)
- (string-match-p key buffer-name))
- (and (functionp key)
- (funcall key buffer-name action)))
- (throw 'match (cdr entry)))))))
+ (when (buffer-match-p (car entry) buffer-or-name action)
+ (throw 'match (cdr entry))))))
(defvar display-buffer--same-window-action
'(display-buffer-same-window
@@ -7518,6 +7598,7 @@ to an expression containing one of these \"action\" functions:
`display-buffer-use-least-recent-window' -- Try to avoid re-using
windows that have recently been switched to.
`display-buffer-pop-up-window' -- Pop up a new window.
+ `display-buffer-full-frame' -- Delete other windows and use the full frame.
`display-buffer-below-selected' -- Use or pop up a window below
the selected one.
`display-buffer-at-bottom' -- Use or pop up a window at the
@@ -7530,7 +7611,7 @@ to an expression containing one of these \"action\" functions:
For instance:
- (setq display-buffer-alist '((\".*\" display-buffer-at-bottom)))
+ (setq display-buffer-alist \\='((\".*\" display-buffer-at-bottom)))
Buffer display can be further customized to a very high degree;
the rest of this docstring explains some of the many
@@ -7570,6 +7651,9 @@ Action alist entries are:
window from being used for display.
`inhibit-switch-frame' -- A non-nil value prevents any frame
used for showing the buffer from being raised or selected.
+ Note that a window manager may still raise a new frame and
+ give it focus, effectively overriding the value specified
+ here.
`reusable-frames' -- The value specifies the set of frames to
search for a window that already displays the buffer.
Possible values are nil (the selected frame), t (any live
@@ -7579,20 +7663,33 @@ Action alist entries are:
frame parameters to give a new frame, if one is created.
`window-height' -- The value specifies the desired height of the
window chosen and is either an integer (the total height of
- the window), a floating point number (the fraction of its
- total height with respect to the total height of the frame's
- root window) or a function to be called with one argument -
- the chosen window. The function is supposed to adjust the
- height of the window; its return value is ignored. Suitable
- functions are `shrink-window-if-larger-than-buffer' and
- `fit-window-to-buffer'.
+ the window specified in frame lines), a floating point
+ number (the fraction of its total height with respect to the
+ total height of the frame's root window), a cons cell whose
+ car is `body-lines' and whose cdr is an integer that
+ specifies the height of the window's body in frame lines, or
+ a function to be called with one argument - the chosen
+ window. That function is supposed to adjust the height of
+ the window. Suitable functions are `fit-window-to-buffer'
+ and `shrink-window-if-larger-than-buffer'.
`window-width' -- The value specifies the desired width of the
window chosen and is either an integer (the total width of
- the window), a floating point number (the fraction of its
- total width with respect to the width of the frame's root
- window) or a function to be called with one argument - the
- chosen window. The function is supposed to adjust the width
- of the window; its return value is ignored.
+ the window specified in frame lines), a floating point
+ number (the fraction of its total width with respect to the
+ width of the frame's root window), a cons cell whose car is
+ `body-columns' and whose cdr is an integer that specifies the
+ width of the window's body in frame columns, or a function to
+ be called with one argument - the chosen window. That
+ function is supposed to adjust the width of the window.
+ `window-size' -- This entry is only useful for windows appearing
+ alone on their frame and specifies the desired size of that
+ window either as a cons of integers (the total width and
+ height of the window on that frame), a cons cell whose car is
+ `body-chars' and whose cdr is a cons of integers (the desired
+ width and height of the window's body in columns and lines of
+ its frame), or a function to be called with one argument -
+ the chosen window. That function is supposed to adjust the
+ size of the frame.
`preserve-size' -- The value should be either (t . nil) to
preserve the width of the chosen window, (nil . t) to
preserve its height or (t . t) to preserve its height and
@@ -7608,9 +7705,9 @@ Action alist entries are:
to fill the window body with some contents that might depend
on dimensions of the displayed window.
-The entries `window-height', `window-width' and `preserve-size'
-are applied only when the window used for displaying the buffer
-never showed another buffer before.
+The entries `window-height', `window-width', `window-size' and
+`preserve-size' are applied only when the window used for
+displaying the buffer never showed another buffer before.
The ACTION argument can also have a non-nil and non-list value.
This means to display the buffer in a window other than the
@@ -7638,7 +7735,7 @@ specified by the ACTION argument."
;; Otherwise, use the defined actions.
(let* ((user-action
(display-buffer-assq-regexp
- (buffer-name buffer) display-buffer-alist action))
+ buffer display-buffer-alist action))
(special-action (display-buffer--special-action buffer))
;; Extra actions from the arguments to this function:
(extra-action
@@ -7735,6 +7832,23 @@ indirectly called by the latter."
(window-dedicated-p))
(window--display-buffer buffer (selected-window) 'reuse alist)))
+(defun display-buffer-full-frame (buffer alist)
+ "Display BUFFER in the current frame, taking the entire frame.
+ALIST is an association list of action symbols and values. See
+Info node `(elisp) Buffer Display Action Alists' for details of
+such alists.
+
+This is an action function for buffer display, see Info
+node `(elisp) Buffer Display Action Functions'. It should be
+called only by `display-buffer' or a function directly or
+indirectly called by the latter."
+ (when-let ((window (or (display-buffer-reuse-window buffer alist)
+ (display-buffer-same-window buffer alist)
+ (display-buffer-pop-up-window buffer alist)
+ (display-buffer-use-some-window buffer alist))))
+ (delete-other-windows window)
+ window))
+
(defun display-buffer--maybe-same-window (buffer alist)
"Conditionally display BUFFER in the selected window.
ALIST is an association list of action symbols and values. See
@@ -8531,6 +8645,14 @@ currently selected window; otherwise it will be displayed in
another window."
(pop-to-buffer buffer display-buffer--same-window-action norecord))
+(defcustom display-comint-buffer-action display-buffer--same-window-action
+ "`display-buffer' action for displaying comint buffers."
+ :type display-buffer--action-custom-type
+ :risky t
+ :version "29.1"
+ :group 'windows
+ :group 'comint)
+
(defun read-buffer-to-switch (prompt)
"Read the name of a buffer to switch to, prompting with PROMPT.
Return the name of the buffer as a string.
@@ -8541,7 +8663,7 @@ from the list of completions and default values."
(let ((rbts-completion-table (internal-complete-buffer-except)))
(minibuffer-with-setup-hook
(lambda ()
- (setq minibuffer-completion-table rbts-completion-table)
+ (setq-local minibuffer-completion-table rbts-completion-table)
;; Since rbts-completion-table is built dynamically, we
;; can't just add it to the default value of
;; icomplete-with-completion-tables, so we add it
@@ -8560,12 +8682,13 @@ If BUFFER-OR-NAME is nil, return the buffer returned by
`other-buffer'. Else, if a buffer specified by BUFFER-OR-NAME
exists, return that buffer. If no such buffer exists, create a
buffer with the name BUFFER-OR-NAME and return that buffer."
- (if buffer-or-name
- (or (get-buffer buffer-or-name)
- (let ((buffer (get-buffer-create buffer-or-name)))
- (set-buffer-major-mode buffer)
- buffer))
- (other-buffer)))
+ (pcase buffer-or-name
+ ('nil (other-buffer))
+ ("*scratch*" (get-scratch-buffer-create))
+ (_ (or (get-buffer buffer-or-name)
+ (let ((buffer (get-buffer-create buffer-or-name)))
+ (set-buffer-major-mode buffer)
+ buffer)))))
(defcustom switch-to-buffer-preserve-window-point t
"If non-nil, `switch-to-buffer' tries to preserve `window-point'.
@@ -9970,6 +10093,11 @@ When point is already on that position, then signal an error."
(defun scroll-up-command (&optional arg)
"Scroll text of selected window upward ARG lines; or near full screen if no ARG.
+Interactively, giving this command a numerical prefix will scroll
+up by that many lines (and down by that many lines if the number
+is negative). Without a prefix, scroll up by a full screen.
+If given a `C-u -' prefix, scroll a full page down instead.
+
If `scroll-error-top-bottom' is non-nil and `scroll-up' cannot
scroll window further, move cursor to the bottom line.
When point is already on that position, then signal an error.
@@ -10002,6 +10130,11 @@ If ARG is the atom `-', scroll downward by nearly full screen."
(defun scroll-down-command (&optional arg)
"Scroll text of selected window down ARG lines; or near full screen if no ARG.
+Interactively, giving this command a numerical prefix will scroll
+down by that many lines (and up by that many lines if the number
+is negative). Without a prefix, scroll down by a full screen.
+If given a `C-u -' prefix, scroll a full page up instead.
+
If `scroll-error-top-bottom' is non-nil and `scroll-down' cannot
scroll window further, move cursor to the top line.
When point is already on that position, then signal an error.
@@ -10032,6 +10165,24 @@ If ARG is the atom `-', scroll upward by nearly full screen."
(put 'scroll-down-command 'scroll-command t)
+(defun scroll-other-window (&optional lines)
+ "Scroll next window upward LINES lines; or near full screen if no ARG.
+See `scroll-up-command' for details."
+ (interactive "P")
+ (with-selected-window (other-window-for-scrolling)
+ (funcall (or (command-remapping #'scroll-up-command)
+ #'scroll-up-command)
+ lines)))
+
+(defun scroll-other-window-down (&optional lines)
+ "Scroll next window downward LINES lines; or near full screen if no ARG.
+See `scroll-down-command' for details."
+ (interactive "P")
+ (with-selected-window (other-window-for-scrolling)
+ (funcall (or (command-remapping #'scroll-down-command)
+ #'scroll-down-command)
+ lines)))
+
;;; Scrolling commands which scroll a line instead of full screen.
(defun scroll-up-line (&optional arg)
@@ -10419,6 +10570,55 @@ displaying that processes's buffer."
(put 'shrink-window-horizontally 'repeat-map 'resize-window-repeat-map)
(put 'shrink-window 'repeat-map 'resize-window-repeat-map)
+(defun window-char-pixel-width (&optional window face)
+ "Return average character width for the font of FACE used in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+If FACE is nil or omitted, the default face is used. If FACE is
+remapped (see `face-remapping-alist'), the function returns the
+information for the remapped face."
+ (with-selected-window (window-normalize-window window t)
+ (let* ((info (font-info (face-font (or face 'default))))
+ (width (aref info 11)))
+ (if (> width 0)
+ width
+ (aref info 10)))))
+
+(defun window-char-pixel-height (&optional window face)
+ "Return character height for the font of FACE used in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+If FACE is nil or omitted, the default face is used. If FACE is
+remapped (see `face-remapping-alist'), the function returns the
+information for the remapped face."
+ (with-selected-window (window-normalize-window window t)
+ (aref (font-info (face-font (or face 'default))) 3)))
+
+(defun window-max-characters-per-line (&optional window face)
+ "Return the number of characters that can be displayed on one line in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+The character width of FACE is used for the calculation. If FACE
+is nil or omitted, the default face is used. If FACE is
+remapped (see `face-remapping-alist'), the function uses the
+remapped face.
+
+This function is different from `window-body-width' in two
+ways. First, it accounts for the portions of the line reserved
+for the continuation glyph. Second, it accounts for the size of
+the font, which may have been adjusted, e.g., using
+`text-scale-increase')."
+ (with-selected-window (window-normalize-window window t)
+ (let* ((window-width (window-body-width window t))
+ (font-width (window-char-pixel-width window face))
+ (ncols (/ window-width font-width)))
+ (if (and (display-graphic-p)
+ overflow-newline-into-fringe
+ (/= (frame-parameter nil 'left-fringe) 0)
+ (/= (frame-parameter nil 'right-fringe) 0))
+ ncols
+ (1- ncols)))))
+
(provide 'window)
;;; window.el ends here