* buffer.c (Fbuffer_list): Rewrite doc-string, reformat.
(Fother_buffer): Rewrite doc-string, restructure.
(Fkill_buffer): Call replace_buffer_in_windows and
replace_buffer_in_windows_safely.
(record_buffer): Inhibit quitting and rewrite using quittable
functions.
(Funrecord_buffer): Inhibit quitting around buffer list
manipulations.
* window.h (struct window): Add new members prev_buffers and
next_buffers.
(replace_buffer_in_all_windows): Remove extern.
(replace_buffer_in_windows_safely): Add extern.
* window.c (Fwindow_prev_buffers, Fset_window_prev_buffers)
(Fwindow_next_buffers, Fset_window_next_buffers): New functions.
(windw_loop): Replace UNSHOW_BUFFER by
REPLACE_BUFFER_IN_WINDOWS_SAFELY.
(window_show_other_buffer): Remove.
(window_loop): Replace UNSHOW_BUFFER case by
REPLACE_BUFFER_IN_WINDOWS_SAFELY - the real work is done in
replace-buffer-in-windows which is in window.el.
(Freplace_buffer_in_windows): Move to window.el.
(replace_buffer_in_all_windows): Remove.
(replace_buffer_in_windows, replace_buffer_in_windows_safely):
New functions.
(Fset_window_buffer): Restructure and call
Qrecord_window_buffer.
(make_window): Initialize missing and new Lisp slots.
(syms_of_window): Add Qreplace_buffer_in_windows and
Qrecord_window_buffer.
* help.el (temp-buffer-max-height, temp-buffer-resize-mode)
(resize-temp-buffer-window): Move back from window.el to avoid
calling define-minor-mode in window.el and choke in bootstrap.
* loadup.el (top-level): Load window before files for the sake
of replace-buffer-in-windows.
* simple.el (get-next-valid-buffer, last-buffer, next-buffer)
(previous-buffer): Move to window.el.
* bindings.el (unbury-buffer): Move to window.el.
* window.el (display-buffer): Move group definition to front of
display buffer section.
(record-window-buffer, unrecord-window-buffer)
(set-window-buffer-start-and-point, switch-to-prev-buffer)
(switch-to-next-buffer): New functions.
(get-next-valid-buffer, last-buffer): Move here from simple.el.
(next-buffer): Move here from simple.el. Call
switch-to-next-buffer.
(previous-buffer): Move here from simple.el. Call
switch-to-prev-buffer.
(bury-buffer, quit-restore-window): Switch to previous buffer
when window cannot be deleted.
(unbury-buffer): Move here from bindings.el.
(delete-windows-on): Switch to previous buffer if window cannot
be deleted. Unrecord buffer argument in all live windows.
(replace-buffer-in-windows): Move here from window.c. Switch to
previous buffer if window cannot be deleted. Unrecord argument
buffer in all live windows.
(switch-to-buffer): In doc-string warning suggest using
with-current-buffer instead of set-buffer.
* windows.texi (Buffers and Windows): Describe lists of previous
and next buffers for windows. Describe new commands
switch-to-prev-buffer and switch-to-next-buffer and their impact
on replace-buffer-in-windows.
+2010-07-31 Martin Rudalics <rudalics@gmx.at>
+
+ * windows.texi (Buffers and Windows): Describe lists of previous
+ and next buffers for windows. Describe new commands
+ switch-to-prev-buffer and switch-to-next-buffer and their impact
+ on replace-buffer-in-windows.
+
2010-07-27 Juanma Barranquero <lekktu@gmail.com>
* modes.texi (Defining Minor Modes): Use C-delete in examples,
@deffn Command replace-buffer-in-windows &optional buffer-or-name
This function replaces @var{buffer-or-name} in all windows displaying it
-with some other buffer. It uses @code{other-buffer} (@pxref{Cyclic
-Window Ordering}) to choose the other buffer. In the usual applications
-of this function, you don't care which other buffer is used; you just
-want to make sure that @var{buffer-or-name} is no longer displayed.
+with some other buffer. It uses @code{switch-to-prev-buffer}, see
+below, to choose that other buffer which is usually the last buffer
+displayed before @var{buffer-or-name} in the respective window.
The argument @var{buffer-or-name} may be a buffer or the name of an
existing buffer and defaults to the current buffer.
that window is deleted. If that window is the only window on its frame
and there are other frames left, the window's frame is deleted too. If
there are no other frames left, some other buffer is displayed in that
-window.
+window as explained above.
This function returns @code{nil}.
@end deffn
+ When @code{replace-buffer-in-windows} has to show another buffer in a
+window, it tries to pick the buffer shown there before. For this
+purpose each window remembers the buffers it has displayed earlier and
+the order in which these buffers have been removed from it.
+
+The list of @dfn{previous buffers} of a window is an association list
+where each entry specifies a buffer, the last start position of that
+buffer in the window (@pxref{Window Start and End}) and the last
+position of that buffer's point in the window (@pxref{Window Point}).
+This list is ordered by the times of the removal of the respective
+buffers from the window. In particular, the first element of the list
+references the buffer removed most recently. The function
+@code{set-window-buffer} pushes an entry for the old buffer of its
+window argument on that list before it shows its buffer argument in the
+window.
+
+The list of @dfn{next buffers} of a window is a list of buffers that
+have been recently re-shown by the function @code{switch-to-prev-buffer}
+and is used to avoid that that function switches to such a buffer again
+before showing other interesting buffers.
+
+The lists of previous and next buffers and the global buffer list
+(@pxref{The Buffer List}) allow to effectively display all buffers in a
+window while giving preference to the buffers previously shown in that
+window. The commands used for this purpose are
+@code{switch-to-prev-buffer} and @code{switch-to-next-buffer} described
+below.
+
+The following functions directly operate on the lists of previous and
+next buffers.
+
+@defun window-prev-buffers &optional window
+This function returns an alist specifying the buffers previously shown
+in @var{window} together with their window start and point positions.
+The argument @var{window} must be a live window and defaults to the
+selected one.
+@end defun
+
+@defun set-window-prev-buffers window prev-buffers
+This function sets @var{window}'s previous buffers to the value of
+@var{prev-buffers}. The argument @var{window} must be a live window and
+defaults to the selected one. This function returns
+@var{prev-buffers}.
+
+If non-@code{nil}, @var{prev-buffers} must specify an alist of triples
+specifying a buffer and two markers for that buffer's start and point
+position in @var{window}.
+@end defun
+
+@defun window-next-buffers &optional window
+This function returns the list of buffers recently re-shown in
+@var{window}. The argument @var{window} must be a live window and
+defaults to the selected one.
+@end defun
+
+@defun set-window-next-buffers window next-buffers
+This function sets @var{window}'s next buffers to @var{next-buffers}.
+@var{window} must be a live window and defaults to the selected one.
+This fucntion returns @var{next-buffers}.
+
+If non-@code{nil}, the argument @var{next-buffers} should specify a list
+of buffers that shall be preferably not shown by the command
+@code{switch-to-prev-buffer}, see below.
+@end defun
+
+The following command is used by @code{replace-buffer-in-windows},
+@code{bury-buffer} and @code{quit-restore-window} to show another buffer
+in a window. It can be also used interactively to cycle through the
+list of all buffers in a window, preferably showing the buffers recently
+shown (but not buried or killed) in that window.
+
+@deffn Command switch-to-prev-buffer &optional window bury-or-kill
+This function displays the previous buffer in @var{window}. The
+argument @var{window} must be a live window and defaults to the selected
+one. If the optional argument @var{bury-or-kill} is non-@code{nil},
+this means that the buffer currently shown in @var{window} is about to
+be buried or killed and consequently shall not be switched to in future
+invocations of this command.
+
+The previous buffer is usually the buffer shown before the buffer
+currently shown in @var{window}. However, a buffer that has been buried
+or killed or has been already shown by a recent invocation of
+@code{switch-to-prev-buffer} does not qualify as previous buffer.
+
+If repeated invocations of this command have already shown all buffers
+previously shown in @var{window}, further invocations will show buffers
+from the global buffer list starting with the buffer returned by
+@code{last-buffer} (@pxref{The Buffer List}).
+@end deffn
+
+The following command can be used to undo the effect of the last undone
+@code{switch-to-prev-buffer} command.
+
+@deffn Command switch-to-next-buffer &optional window
+This functions switches to the next buffer in @var{window} thus undoing
+the effect of the last @code{switch-to-prev-buffer} command in
+@var{window}. The argument @var{window} must be a live window and
+defaults to the selected one.
+
+If there is no recent invocation of a @code{switch-to-prev-buffer} that
+can be undone, @code{switch-to-next-buffer} will try to show the first
+buffer from the global buffer list as returned by @code{other-buffer}
+(@pxref{The Buffer List}).
+@end deffn
+
+ Together, @code{switch-to-prev-buffer} and
+@code{switch-to-next-buffer} permit to navigate the global buffer list
+much like @code{bury-buffer} and @code{unbury-buffer}. In contrast with
+the latter, however, they may show a buffer even if it is already shown
+in another window. Moreover, they try to restore the window specific
+start and point positions of buffers which should handle viewing one and
+the same buffer in multiple windows more easily.
+
+
@node Switching Buffers
@section Switching to a Buffer in Some Window
@cindex switching to a buffer
+2010-07-30 Martin Rudalics <rudalics@gmx.at>
+
+ * help.el (temp-buffer-max-height, temp-buffer-resize-mode)
+ (resize-temp-buffer-window): Move back from window.el to avoid
+ calling define-minor-mode in window.el and choke in bootstrap.
+
+2010-07-29 Martin Rudalics <rudalics@gmx.at>
+
+ * loadup.el (top-level): Load window before files for the sake
+ of replace-buffer-in-windows.
+
+ * simple.el (get-next-valid-buffer, last-buffer, next-buffer)
+ (previous-buffer): Move to window.el.
+
+ * bindings.el (unbury-buffer): Move to window.el.
+
+ * window.el (display-buffer): Move group definition to front of
+ display buffer section.
+ (record-window-buffer, unrecord-window-buffer)
+ (set-window-buffer-start-and-point, switch-to-prev-buffer)
+ (switch-to-next-buffer): New functions.
+ (get-next-valid-buffer, last-buffer): Move here from simple.el.
+ (next-buffer): Move here from simple.el. Call
+ switch-to-next-buffer.
+ (previous-buffer): Move here from simple.el. Call
+ switch-to-prev-buffer.
+ (bury-buffer, quit-restore-window): Switch to previous buffer
+ when window cannot be deleted.
+ (unbury-buffer): Move here from bindings.el.
+ (delete-windows-on): Switch to previous buffer if window cannot
+ be deleted. Unrecord buffer argument in all live windows.
+ (replace-buffer-in-windows): Move here from window.c. Switch to
+ previous buffer if window cannot be deleted. Unrecord argument
+ buffer in all live windows.
+ (switch-to-buffer): In doc-string warning suggest using
+ with-current-buffer instead of set-buffer.
+
2010-07-28 Chong Yidong <cyd@stupidchicken.com>
* emacs-lisp/package.el (package-load-list, package-archives)
(put 'mode-line-buffer-identification 'risky-local-variable t)
(make-variable-buffer-local 'mode-line-buffer-identification)
-(defun unbury-buffer () "\
-Switch to the last buffer in the buffer list."
- (interactive)
- (switch-to-buffer (last-buffer)))
-
(defun mode-line-unbury-buffer (event) "\
Call `unbury-buffer' in this window."
(interactive "e")
(setq minor-modes (cdr minor-modes)))))
result))
\f
+;;; Automatic resizing of temporary buffers.
+
+(defcustom temp-buffer-max-height (lambda (buffer) (/ (- (frame-height) 2) 2))
+ "Maximum height of a window displaying a temporary buffer.
+This is effective only when Temp Buffer Resize mode is enabled.
+The value is the maximum height (in lines) which
+`resize-temp-buffer-window' will give to a window displaying a
+temporary buffer. It can also be a function to be called to
+choose the height for such a buffer. It gets one argumemt, the
+buffer, and should return a positive integer. At the time the
+function is called, the window to be resized is selected."
+ :type '(choice integer function)
+ :group 'help
+ :version "20.4")
+
+(define-minor-mode temp-buffer-resize-mode
+ "Toggle mode which makes windows smaller for temporary buffers.
+With prefix argument ARG, turn the resizing of windows displaying
+temporary buffers on if ARG is positive or off otherwise.
+
+This mode makes a window the right height for its contents, but
+never more than `temp-buffer-max-height' nor less than
+`window-min-height'.
+
+This mode is used by `help', `apropos' and `completion' buffers,
+and some others."
+ :global t :group 'help
+ (if temp-buffer-resize-mode
+ ;; `help-make-xrefs' may add a `back' button and thus increase the
+ ;; text size, so `resize-temp-buffer-window' must be run *after* it.
+ (add-hook 'temp-buffer-show-hook 'resize-temp-buffer-window 'append)
+ (remove-hook 'temp-buffer-show-hook 'resize-temp-buffer-window)))
+
+(defun resize-temp-buffer-window ()
+ "Resize the selected window to fit its contents.
+Will not make it higher than `temp-buffer-max-height' nor smaller
+than `window-min-height'. Do nothing if the selected window is
+not vertically combined or some of its contents are scrolled out
+of view."
+ (when (and (pos-visible-in-window-p (point-min))
+ (window-iso-combined-p))
+ (fit-window-to-buffer
+ nil
+ (if (functionp temp-buffer-max-height)
+ (funcall temp-buffer-max-height (window-buffer))
+ temp-buffer-max-height))))
+
;;; help windows
(defcustom help-window-select 'other
"Non-nil means select help window for viewing.
(load "env")
(load "format")
(load "bindings")
+(load "window") ; Needed here for `replace-buffer-in-windows'.
(setq load-source-file-function 'load-with-code-conversion)
(load "files")
(load "language/cham")
(load "indent")
-(load "window")
(load "frame")
(load "term/tty-colors")
(load "font-core")
(defgroup paren-matching nil
"Highlight (un)matching of parens and expressions."
:group 'matching)
-
-(defun get-next-valid-buffer (list &optional buffer visible-ok frame)
- "Search LIST for a valid buffer to display in FRAME.
-Return nil when all buffers in LIST are undesirable for display,
-otherwise return the first suitable buffer in LIST.
-
-Buffers not visible in windows are preferred to visible buffers,
-unless VISIBLE-OK is non-nil.
-If the optional argument FRAME is nil, it defaults to the selected frame.
-If BUFFER is non-nil, ignore occurrences of that buffer in LIST."
- ;; This logic is more or less copied from other-buffer.
- (setq frame (or frame (selected-frame)))
- (let ((pred (frame-parameter frame 'buffer-predicate))
- found buf)
- (while (and (not found) list)
- (setq buf (car list))
- (if (and (not (eq buffer buf))
- (buffer-live-p buf)
- (or (null pred) (funcall pred buf))
- (not (eq (aref (buffer-name buf) 0) ?\s))
- (or visible-ok (null (get-buffer-window buf 'visible))))
- (setq found buf)
- (setq list (cdr list))))
- (car list)))
-
-(defun last-buffer (&optional buffer visible-ok frame)
- "Return the last buffer in FRAME's buffer list.
-If BUFFER is the last buffer, return the preceding buffer instead.
-Buffers not visible in windows are preferred to visible buffers,
-unless optional argument VISIBLE-OK is non-nil.
-Optional third argument FRAME nil or omitted means use the
-selected frame's buffer list.
-If no such buffer exists, return 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)))
-
-(defun next-buffer ()
- "Switch to the next buffer in cyclic order."
- (interactive)
- (let ((buffer (current-buffer)))
- (switch-to-buffer (other-buffer buffer t))
- (bury-buffer buffer)))
-
-(defun previous-buffer ()
- "Switch to the previous buffer in cyclic order."
- (interactive)
- (switch-to-buffer (last-buffer (current-buffer) t)))
-
\f
;;; next-error support framework
;; Or maybe not because writing code with wwt is not very transparent.
;; Or better, rewrite wwt as a macro.
-;; Get window-buffer-lists working implementing a separate argument.
-;; But first make sure that `record-buffer' and `unrecord-buffer' always
-;; operate on the correct window/frame (for `bury-buffer' this might be
-;; unintuitive). Probably a special argument for `set-window-buffer' is
-;; needed. `other-buffer' probably gets a window-or-frame argument.
-;; Also handle the case where a buffer is added to a frame's
-;; buried-buffer list although it was never shown there.
-
;; Use (pop-up-windows (or pop-up-windows t)) instead of (pop-up-windows
;; t) wherever this is locally rebound (has some twenty hits in Elisp
;; sources).
-;; Probably `record-buffer' is not needed anymore.
-
;;; Code:
(eval-when-compile (require 'cl))
-(defgroup display-buffer nil
- "Displaying buffers in windows."
- :version "24.1"
- :group 'windows)
-
(defmacro save-selected-window (&rest body)
"Execute BODY, then select the previously selected window.
The value returned is the value of the last form in BODY.
;; The following two functions are like `window-next' and `window-prev'
;; but the WINDOW argument is _not_ optional (so they don't substitute
;; the selected window for nil), and they return nil when WINDOW doesn't
-;; have a parent (like a frame's root or minibuffer window).
+;; have a parent (like a frame's root window or a minibuffer window).
(defsubst window-right (window)
"Return WINDOW's right sibling.
Return nil if WINDOW is the root window of its frame. WINDOW can
(push w delenda))))
(mapc 'delete-window delenda)))
-;; Removing buffers from windows (and maybe their windows too).
+;;; Windows and buffers.
+
+;; `prev-buffers' and `next-buffers' are two reserved window slots used
+;; for (1) determining which buffer to show in the window when its
+;; buffer shall be buried or killed and (2) which buffer to show for
+;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
+
+;; `prev-buffers' consists of <buffer, window-start, window-point>
+;; triples. The entries on this list are ordered by the time their
+;; buffer has been removed from the window, the most recently removed
+;; buffer's entry being first. The window-start and window-point
+;; components are `window-start' and `window-point' at the time the
+;; buffer was removed from the window which implies that the entry must
+;; be added when `set-window-buffer' removes the buffer from the window.
+
+;; `next-buffers' is the list of buffers that have been replaced
+;; recently by `switch-to-prev-buffer'. These buffers are the least
+;; preferred candidates of `switch-to-prev-buffer' and the preferred
+;; candidates of `switch-to-next-buffer' to switch to. This list is
+;; reset to nil by any action changing the window's buffer with the
+;; exception of `switch-to-prev-buffer' and `switch-to-next-buffer'.
+;; `switch-to-prev-buffer' pushes the buffer it just replaced on it,
+;; `switch-to-next-buffer' pops the last pushed buffer from it.
+
+;; Both `prev-buffers' and `next-buffers' may reference killed buffers
+;; if such a buffer was killed while the window was hidden within a
+;; window configuration. Such killed buffers get removed whenever
+;; `switch-to-prev-buffer' or `switch-to-next-buffer' encounter them.
+
+;; The following function is called by `set-window-buffer' _before_ it
+;; replaces the buffer of the argument window with the new buffer.
+(defun record-window-buffer (&optional window)
+ "Record WINDOW's buffer.
+WINDOW must be a live window and defaults to the selected one."
+ (let* ((window (normalize-live-window window))
+ (buffer (window-buffer window))
+ (entry (assq buffer (window-prev-buffers window))))
+ ;; Reset WINDOW's next buffers. If needed, they are resurrected by
+ ;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
+ (set-window-next-buffers window nil)
+
+ (when entry
+ ;; Remove all entries for BUFFER from WINDOW's previous buffers.
+ (set-window-prev-buffers
+ window (assq-delete-all buffer (window-prev-buffers window))))
+
+ ;; Don't record insignificant buffers.
+ (unless (eq (aref (buffer-name buffer) 0) ?\s)
+ ;; Add an entry for buffer to WINDOW's previous buffers.
+ (with-current-buffer buffer
+ (let ((start (window-start window))
+ (point (window-point window)))
+ (setq entry
+ (cons buffer
+ (if entry
+ ;; We have an entry, update marker positions.
+ (list (set-marker (nth 1 entry) start)
+ (set-marker (nth 2 entry) point))
+ ;; Make new markers.
+ (list (copy-marker start)
+ (copy-marker point)))))
+
+ (set-window-prev-buffers
+ window (cons entry (window-prev-buffers window))))))))
+
+(defun unrecord-window-buffer (&optional window buffer)
+ "Unrecord BUFFER in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+BUFFER must be a live buffer and defaults to the buffer of
+WINDOW."
+ (let* ((window (normalize-live-window window))
+ (buffer (or buffer (window-buffer window))))
+ (set-window-prev-buffers
+ window (assq-delete-all buffer (window-prev-buffers window)))
+ (set-window-next-buffers
+ window (delq buffer (window-next-buffers window)))))
+
+(defun set-window-buffer-start-and-point (window buffer &optional start point)
+ "Set WINDOW's buffer to BUFFER.
+Optional argument START non-nil means set WINDOW's start position
+to START. Optional argument POINT non-nil means set WINDOW's
+point to POINT. If WINDOW is selected this also sets BUFFER's
+`point' to POINT. If WINDOW is selected and the buffer it showed
+before was current this also makes BUFFER the current buffer."
+ (let ((selected (eq window (selected-window)))
+ (current (eq (window-buffer window) (current-buffer))))
+ (set-window-buffer window buffer)
+ (when (and selected current)
+ (set-buffer buffer))
+ (when start
+ (set-window-start window start))
+ (when point
+ (if selected
+ (with-current-buffer buffer
+ (goto-char point))
+ (set-window-point window point)))))
+
+(defun switch-to-prev-buffer (&optional window bury-or-kill)
+ "In WINDOW switch to previous buffer.
+WINDOW must be a live window and defaults to the selected one.
+
+Optional argument BURY-OR-KILL non-nil means the buffer currently
+shown in WINDOW is about to be buried or killed and consequently
+shall not be switched to in future invocations of this command."
+ (interactive)
+ (let* ((window (normalize-live-window window))
+ (old-buffer (window-buffer window))
+ ;; Save this since it's destroyed by `set-window-buffer'.
+ (next-buffers (window-next-buffers window))
+ entry new-buffer killed-buffers deletable)
+ (cond
+ ;; When BURY-OR-KILL is non-nil, there's no previous buffer for
+ ;; this window, and we can delete the window (or the frame) do
+ ;; that.
+ ((and bury-or-kill
+ (or (not (window-prev-buffers window))
+ (and (eq (caar (window-prev-buffers window)) old-buffer)
+ (not (cdr (car (window-prev-buffers window))))))
+ (setq deletable (window-deletable-p window)))
+ (if (eq deletable 'frame)
+ (delete-frame (window-frame window))
+ (delete-window window)))
+ ((window-dedicated-p window)
+ (error "Window %s is dedicated to buffer %s" window old-buffer)))
+
+ (unless deletable
+ (catch 'found
+ ;; Scan WINDOW's previous buffers first, skipping entries of next
+ ;; buffers.
+ (dolist (entry (window-prev-buffers window))
+ (when (and (setq new-buffer (car entry))
+ (or (buffer-live-p new-buffer)
+ (not (setq killed-buffers
+ (cons new-buffer killed-buffers))))
+ (not (eq new-buffer old-buffer))
+ (or bury-or-kill
+ (not (memq new-buffer next-buffers))))
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t)))
+ ;; Scan reverted buffer list of WINDOW's frame next, skipping
+ ;; entries of next buffers. Note that when we bury or kill a
+ ;; buffer we don't reverse the global buffer list to avoid showing
+ ;; a buried buffer instead. Otherwise, we must reverse the global
+ ;; buffer list in order to make sure that switching to the
+ ;; previous/next buffer traverse it in opposite directions.
+ (dolist (buffer (if bury-or-kill
+ (buffer-list (window-frame window))
+ (nreverse (buffer-list (window-frame window)))))
+ (when (and (buffer-live-p buffer)
+ (not (eq buffer old-buffer))
+ (not (eq (aref (buffer-name buffer) 0) ?\s))
+ (or bury-or-kill (not (memq buffer next-buffers))))
+ (setq new-buffer buffer)
+ (set-window-buffer-start-and-point window new-buffer)
+ (throw 'found t)))
+ (unless bury-or-kill
+ ;; Scan reverted next buffers last (must not use nreverse
+ ;; here!).
+ (dolist (buffer (reverse next-buffers))
+ ;; Actually, buffer _must_ be live here since otherwise it
+ ;; would have been caught in the scan of previous buffers.
+ (when (and (or (buffer-live-p buffer)
+ (not (setq killed-buffers
+ (cons buffer killed-buffers))))
+ (not (eq buffer old-buffer))
+ (setq entry (assq buffer (window-prev-buffers window))))
+ (setq new-buffer buffer)
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t)))))
+
+ (if bury-or-kill
+ ;; Remove `old-buffer' from WINDOW's previous and (restored list
+ ;; of) next buffers.
+ (progn
+ (set-window-prev-buffers
+ window (assq-delete-all old-buffer (window-prev-buffers window)))
+ (set-window-next-buffers window (delq old-buffer next-buffers)))
+ ;; Move `old-buffer' to head of WINDOW's restored list of next
+ ;; buffers.
+ (set-window-next-buffers
+ window (cons old-buffer (delq old-buffer next-buffers)))))
+
+ ;; Remove killed buffers from WINDOW's previous and next buffers.
+ (when killed-buffers
+ (dolist (buffer killed-buffers)
+ (set-window-prev-buffers
+ window (assq-delete-all buffer (window-prev-buffers window)))
+ (set-window-next-buffers
+ window (delq buffer (window-next-buffers window)))))
+
+ ;; Return new-buffer.
+ new-buffer))
+
+(defun switch-to-next-buffer (&optional window)
+ "In WINDOW switch to next buffer.
+WINDOW must be a live window and defaults to the selected one."
+ (interactive)
+ (let* ((window (normalize-live-window window))
+ (old-buffer (window-buffer window))
+ (next-buffers (window-next-buffers window))
+ new-buffer entry killed-buffers)
+ (when (window-dedicated-p window)
+ (error "Window %s is dedicated to buffer %s" window old-buffer))
+
+ (catch 'found
+ ;; Scan WINDOW's next buffers first.
+ (dolist (buffer next-buffers)
+ (when (and (or (buffer-live-p buffer)
+ (not (setq killed-buffers
+ (cons buffer killed-buffers))))
+ (not (eq buffer old-buffer))
+ (setq entry (assq buffer (window-prev-buffers window))))
+ (setq new-buffer buffer)
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t)))
+ ;; Scan the buffer list of WINDOW's frame next, skipping previous
+ ;; buffers entries.
+ (dolist (buffer (buffer-list (window-frame window)))
+ (when (and (buffer-live-p buffer) (not (eq buffer old-buffer))
+ (not (eq (aref (buffer-name buffer) 0) ?\s))
+ (not (assq buffer (window-prev-buffers window))))
+ (setq new-buffer buffer)
+ (set-window-buffer-start-and-point window new-buffer)
+ (throw 'found t)))
+ ;; Scan WINDOW's reverted previous buffers last (must not use
+ ;; nreverse here!)
+ (dolist (entry (reverse (window-prev-buffers window)))
+ (when (and (setq new-buffer (car entry))
+ (or (buffer-live-p new-buffer)
+ (not (setq killed-buffers
+ (cons new-buffer killed-buffers))))
+ (not (eq new-buffer old-buffer)))
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t))))
+
+ ;; Remove `new-buffer' from and restore WINDOW's next buffers.
+ (set-window-next-buffers window (delq new-buffer next-buffers))
+
+ ;; Remove killed buffers from WINDOW's previous and next buffers.
+ (when killed-buffers
+ (dolist (buffer killed-buffers)
+ (set-window-prev-buffers
+ window (assq-delete-all buffer (window-prev-buffers window)))
+ (set-window-next-buffers
+ window (delq buffer (window-next-buffers window)))))
+
+ ;; Return new-buffer.
+ new-buffer))
+
+(defun get-next-valid-buffer (list &optional buffer visible-ok frame)
+ "Search LIST for a valid buffer to display in FRAME.
+Return nil when all buffers in LIST are undesirable for display,
+otherwise return the first suitable buffer in LIST.
+
+Buffers not visible in windows are preferred to visible buffers,
+unless VISIBLE-OK is non-nil.
+If the optional argument FRAME is nil, it defaults to the selected frame.
+If BUFFER is non-nil, ignore occurrences of that buffer in LIST."
+ ;; This logic is more or less copied from other-buffer.
+ (setq frame (or frame (selected-frame)))
+ (let ((pred (frame-parameter frame 'buffer-predicate))
+ found buf)
+ (while (and (not found) list)
+ (setq buf (car list))
+ (if (and (not (eq buffer buf))
+ (buffer-live-p buf)
+ (or (null pred) (funcall pred buf))
+ (not (eq (aref (buffer-name buf) 0) ?\s))
+ (or visible-ok (null (get-buffer-window buf 'visible))))
+ (setq found buf)
+ (setq list (cdr list))))
+ (car list)))
+
+(defun last-buffer (&optional buffer visible-ok frame)
+ "Return the last buffer in FRAME's buffer list.
+If BUFFER is the last buffer, return the preceding buffer
+instead. Buffers not visible in windows are preferred to visible
+buffers, unless optional argument VISIBLE-OK is non-nil.
+Optional third argument FRAME nil or omitted means use the
+selected frame's buffer list. If no such buffer exists, return
+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)))
+
+(defun bury-buffer (&optional buffer-or-name)
+ "Put BUFFER-OR-NAME at the end of the list of all buffers.
+There it is the least likely candidate for `other-buffer' to
+return; thus, the least likely buffer for \\[switch-to-buffer] to
+select by default.
+
+You can specify a buffer name as BUFFER-OR-NAME, or an actual
+buffer object. If BUFFER-OR-NAME is nil or omitted, bury the
+current buffer. Also, if BUFFER-OR-NAME is nil or omitted,
+remove the current buffer from the selected window if it is
+displayed there."
+ (interactive)
+ (let* ((buffer (normalize-live-buffer buffer-or-name)))
+ ;; If `buffer-or-name' is not on the selected frame we unrecord it
+ ;; although it's not "here" (call it a feature).
+ (unrecord-buffer buffer)
+ ;; Handle case where `buffer-or-name' is nil and the current buffer
+ ;; is shown in the selected window.
+ (cond
+ ((or buffer-or-name (not (eq buffer (window-buffer)))))
+ ((not (window-dedicated-p))
+ (switch-to-prev-buffer nil 'bury))
+ ((frame-root-window-p (selected-window))
+ (iconify-frame (window-frame (selected-window))))
+ ((window-deletable-p)
+ (delete-window)))
+ ;; Always return nil.
+ nil))
+
+(defun unbury-buffer ()
+ "Switch to the last buffer in the buffer list."
+ (interactive)
+ (switch-to-buffer (last-buffer)))
+
+(defun next-buffer ()
+ "In selected window switch to next buffer."
+ (interactive)
+ (switch-to-next-buffer))
+
+(defun previous-buffer ()
+ "In selected window switch to previous buffer."
+ (interactive)
+ (switch-to-prev-buffer))
+
(defun delete-windows-on (&optional buffer-or-name frame)
"Delete all windows showing BUFFER-OR-NAME.
BUFFER-OR-NAME may be a buffer or the name of an existing buffer
window of its frame, that frame is deleted when there are other
frames left."
(interactive "BDelete windows on (buffer):\nP")
- ;; We need a normalize-live-buffer function.
(let ((buffer (normalize-live-buffer buffer-or-name))
;; Handle the "inverted" meaning of the FRAME argument wrt other
;; `window-list-1' based function.
- (all-frames (cond
- ((not frame) t)
- ((eq frame t) nil)
- (t frame))))
+ (all-frames (cond ((not frame) t) ((eq frame t) nil) (t frame))))
(dolist (window (window-list-1 nil nil all-frames))
- (when (eq (window-buffer window) buffer)
- (let ((frame (window-frame window))
- (deletable (window-deletable-p window)))
- (cond
- ;; What if BUFFER-OR-NAME denotes the minibuffer?
- ((eq deletable 'frame)
- ;; Delete frame showing BUFFER-OR-NAME.
- (delete-frame frame))
- (deletable
- (delete-window window))
- (t
- ;; Can't delete window so display another buffer.
- (let ((other-buffer (other-buffer buffer nil frame)))
- ;; Reset dedicated state of window.
+ (if (eq (window-buffer window) buffer)
+ (let ((deletable (window-deletable-p window)))
+ (cond
+ ((eq deletable 'frame)
+ ;; Delete frame.
+ (delete-frame (window-frame window)))
+ (deletable
+ ;; Delete window only.
+ (delete-window window))
+ (t
+ ;; In window switch to previous buffer.
(set-window-dedicated-p window nil)
- (set-window-buffer window other-buffer)
- ;; Make other buffer current if the window did show the
- ;; current buffer before.
- (when (and (eq window (selected-window))
- (eq buffer (current-buffer)))
- (set-buffer other-buffer))))))))))
+ (switch-to-prev-buffer window 'bury))))
+ ;; If a window doesn't show BUFFER, unrecord it nevertheless.
+ (unrecord-window-buffer window buffer)))))
(defun replace-buffer-in-windows (&optional buffer-or-name)
"Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
deleted. If that window is the only window on its frame, that
frame is deleted too when there are other frames left. If there
are no other frames left, some other buffer is displayed in that
-window."
+window.
+
+This function removes the buffer denoted by BUFFER-OR-NAME from
+all window-local buffer lists."
(let ((buffer (normalize-live-buffer buffer-or-name)))
(dolist (window (window-list-1 nil nil t))
- (when (eq (window-buffer window) buffer)
- (let ((frame (window-frame window))
- (deletable (window-deletable-p window)))
- (cond
- ((eq deletable 'frame)
- ;; Delete frame showing BUFFER-OR-NAME.
- (delete-frame frame))
- ((and (window-dedicated-p window) deletable)
- (delete-window window))
- (t
- (let ((other-buffer (other-buffer buffer nil frame)))
- ;; Reset dedicated state of window.
+ (if (eq (window-buffer window) buffer)
+ (let ((deletable (window-deletable-p window)))
+ (cond
+ ((eq deletable 'frame)
+ ;; Delete frame.
+ (delete-frame (window-frame window)))
+ ((and (window-dedicated-p window) deletable)
+ ;; Delete window.
+ (delete-window window))
+ (t
+ ;; Switch to another buffer in window.
(set-window-dedicated-p window nil)
- (set-window-buffer window other-buffer)
- ;; Make other buffer current if the window did show the
- ;; current buffer before.
- (when (and (eq window (selected-window))
- (eq buffer (current-buffer)))
- (set-buffer other-buffer))))))))))
-
-(defun bury-buffer (&optional buffer-or-name)
- "Put BUFFER-OR-NAME at the end of the list of all buffers.
-There it is the least likely candidate for `other-buffer' to
-return; thus, the least likely buffer for \\[switch-to-buffer] to
-select by default.
-
-You can specify a buffer name as BUFFER-OR-NAME, or an actual
-buffer object. If BUFFER-OR-NAME is nil or omitted, bury the
-current buffer. Also, if BUFFER-OR-NAME is nil or omitted,
-remove the current buffer from the selected window if it is
-displayed there."
- (interactive)
- (let ((buffer (normalize-live-buffer buffer-or-name)))
- ;; FIXME: If `buffer-or-name' is not on the selected frame we have a
- ;; problem. We unrecord it although it's not "here".
- (unrecord-buffer buffer)
- ;; Handle case where `buffer-or-name' is nil and the current buffer
- ;; is shown in the selected window.
- (cond
- ((or buffer-or-name (not (eq buffer (window-buffer)))))
- ((not (window-dedicated-p))
- (switch-to-buffer (other-buffer buffer)))
- ((frame-root-window-p (selected-window))
- (iconify-frame (window-frame (selected-window))))
- (t (delete-window)))
- ;; Always return nil.
- nil))
-
-;; FIXME: Most present clients of this don't get it very right.
-(defun kill-or-unrecord-buffer (buffer kill)
- "Unrecord BUFFER. Kill BUFFER if KILL is non-nil."
- (if kill
- (kill-buffer buffer)
- (unrecord-buffer buffer)))
+ (switch-to-prev-buffer window 'kill))))
+ ;; Unrecord BUFFER in WINDOW.
+ (unrecord-window-buffer window buffer)))))
(defun quit-restore-window (&optional window kill)
- "Quit WINDOW possibly restoring its previous contents.
+ "Quit WINDOW in some way.
WINDOW must be a live window and defaults to the selected window.
Return nil.
(cond
((and (eq (car-safe parameters) t)
(setq deletable (window-deletable-p window)))
+ (unrecord-buffer buffer)
;; WINDOW is deletable.
(if (eq deletable 'frame)
;; WINDOW's frame can be deleted.
;; Just delete WINDOW.
(delete-window window))
(when (window-live-p (nth 1 parameters))
- (select-window (nth 1 parameters)))
- ;; FIXME: Along with `window-buffer-list'.
- (kill-or-unrecord-buffer buffer kill))
+ (select-window (nth 1 parameters))))
((and (buffer-live-p (nth 0 parameters))
;; The buffer currently shown in WINDOW must still be the
;; buffer shown when the `quit-restore' parameter was
;; created in the first place.
(eq (window-buffer window) (nth 3 parameters)))
+ ;; Unrecord buffer.
+ (unrecord-buffer buffer)
+ (unrecord-window-buffer window buffer)
;; The `quit-restore' parameters tell us the buffer to display in
;; WINDOW and how to do that.
(set-window-dedicated-p window nil)
window (- (nth 4 parameters) (window-total-size window))))
(set-window-parameter window 'quit-restore nil)
(when (window-live-p (nth 5 parameters))
- (select-window (nth 5 parameters)))
- (kill-or-unrecord-buffer buffer kill))
+ (select-window (nth 5 parameters))))
((and (window-dedicated-p window)
(setq deletable (window-deletable-p window)))
+ (unrecord-buffer buffer)
;; WINDOW is dedicated and deletable.
(if (eq deletable 'frame)
;; WINDOW's frame can be deleted.
(delete-frame (window-frame window))
;; Just delete WINDOW.
- (delete-window window))
- (kill-or-unrecord-buffer buffer kill))
+ (delete-window window)))
(t
;; Otherwise, show another buffer in WINDOW.
- (let ((other-buffer (other-buffer buffer)))
- (set-window-parameter window 'quit-restore nil)
- (set-window-dedicated-p window nil)
- (set-window-buffer window other-buffer)
- (kill-or-unrecord-buffer
- buffer (and kill (not (eq buffer other-buffer)))))))
+ (set-window-parameter window 'quit-restore nil)
+ (unrecord-buffer buffer)
+ (switch-to-prev-buffer window 'bury-or-kill)))
+
+ ;; Kill WINDOW's old-buffer if requested
+ (when kill (kill-buffer buffer))
nil))
\f
;;; Splitting windows.
\f
;;; Displaying buffers.
+(defgroup display-buffer nil
+ "Displaying buffers in windows."
+ :version "24.1"
+ :group 'windows)
+
(defcustom display-buffer-function nil
"If non-nil, function to call to display a buffer.
`display-buffer' calls this function with two arguments, the
do not make the window displaying it the most recently selected
one.
-WARNING: This is NOT the way to work on another buffer
-temporarily within a Lisp program! Use `set-buffer' instead.
-That avoids messing with the window-buffer correspondences."
+WARNING: Do NOT use this function to work on another buffer
+temporarily within a Lisp program! Use `with-current-buffer'
+instead. That avoids messing with the window-buffer
+correspondences."
(interactive
(list (read-buffer-to-switch "Switch to buffer: ")))
(let ((buffer (when buffer-or-name (get-buffer buffer-or-name))))
(when (and (window-iso-combined-p window)
(pos-visible-in-window-p (point-min) window))
(fit-window-to-buffer window (window-total-size window))))
-
-(defcustom temp-buffer-max-height (lambda (buffer) (/ (- (frame-height) 2) 2))
- "Maximum height of a window displaying a temporary buffer.
-This is effective only when Temp Buffer Resize mode is enabled.
-The value is the maximum height (in lines) which
-`resize-temp-buffer-window' will give to a window displaying a
-temporary buffer. It can also be a function to be called to
-choose the height for such a buffer. It gets one argumemt, the
-buffer, and should return a positive integer. At the time the
-function is called, the window to be resized is selected."
- :type '(choice integer function)
- :group 'help
- :version "20.4")
-
-(define-minor-mode temp-buffer-resize-mode
- "Toggle mode which makes windows smaller for temporary buffers.
-With prefix argument ARG, turn the resizing of windows displaying
-temporary buffers on if ARG is positive or off otherwise.
-
-This mode makes a window the right height for its contents, but
-never more than `temp-buffer-max-height' nor less than
-`window-min-height'.
-
-This mode is used by `help', `apropos' and `completion' buffers,
-and some others."
- :global t :group 'help
- (if temp-buffer-resize-mode
- ;; `help-make-xrefs' may add a `back' button and thus increase the
- ;; text size, so `resize-temp-buffer-window' must be run *after* it.
- (add-hook 'temp-buffer-show-hook 'resize-temp-buffer-window 'append)
- (remove-hook 'temp-buffer-show-hook 'resize-temp-buffer-window)))
-
-(defun resize-temp-buffer-window ()
- "Resize the selected window to fit its contents.
-Will not make it higher than `temp-buffer-max-height' nor smaller
-than `window-min-height'. Do nothing if the selected window is
-not vertically combined or some of its contents are scrolled out
-of view."
- (when (and (pos-visible-in-window-p (point-min))
- (window-iso-combined-p))
- (fit-window-to-buffer
- nil
- (if (functionp temp-buffer-max-height)
- (funcall temp-buffer-max-height (window-buffer))
- temp-buffer-max-height))))
\f
(defun kill-buffer-and-window ()
"Kill the current buffer and delete the selected window."
+2010-07-29 Martin Rudalics <rudalics@gmx.at>
+
+ * buffer.c (Fbuffer_list): Rewrite doc-string, reformat.
+ (Fother_buffer): Rewrite doc-string, restructure.
+ (Fkill_buffer): Call replace_buffer_in_windows and
+ replace_buffer_in_windows_safely.
+ (record_buffer): Inhibit quitting and rewrite using quittable
+ functions.
+ (Funrecord_buffer): Inhibit quitting around buffer list
+ manipulations.
+
+ * window.h (struct window): Add new members prev_buffers and
+ next_buffers.
+ (replace_buffer_in_all_windows): Remove extern.
+ (replace_buffer_in_windows_safely): Add extern.
+
+ * window.c (Fwindow_prev_buffers, Fset_window_prev_buffers)
+ (Fwindow_next_buffers, Fset_window_next_buffers): New functions.
+ (windw_loop): Replace UNSHOW_BUFFER by
+ REPLACE_BUFFER_IN_WINDOWS_SAFELY.
+ (window_show_other_buffer): Remove.
+ (window_loop): Replace UNSHOW_BUFFER case by
+ REPLACE_BUFFER_IN_WINDOWS_SAFELY - the real work is done in
+ replace-buffer-in-windows which is in window.el.
+ (Freplace_buffer_in_windows): Move to window.el.
+ (replace_buffer_in_all_windows): Remove.
+ (replace_buffer_in_windows, replace_buffer_in_windows_safely):
+ New functions.
+ (Fset_window_buffer): Restructure and call
+ Qrecord_window_buffer.
+ (make_window): Initialize missing and new Lisp slots.
+ (syms_of_window): Add Qreplace_buffer_in_windows and
+ Qrecord_window_buffer.
+
2010-07-29 Jan Djärv <jan.h.d@swipnet.se>
* vm-limit.c (POINTER): Add typedef for it.
DEFUN ("buffer-list", Fbuffer_list, Sbuffer_list, 0, 1, 0,
doc: /* Return a list of all existing live buffers.
-If the optional arg FRAME is a frame, we return the buffer list
-in the proper order for that frame: the buffers in FRAME's `buffer-list'
-frame parameter come first, followed by the rest of the buffers. */)
+If the optional arg FRAME is a frame, we return the buffer list in the
+proper order for that frame: the buffers show in FRAME come first,
+followed by the rest of the buffers. */)
(Lisp_Object frame)
{
Lisp_Object general;
Lisp_Object args[3];
CHECK_FRAME (frame);
-
framelist = Fcopy_sequence (XFRAME (frame)->buffer_list);
- prevlist = Fnreverse (Fcopy_sequence (XFRAME (frame)->buried_buffer_list));
+ prevlist = Fnreverse (Fcopy_sequence
+ (XFRAME (frame)->buried_buffer_list));
/* Remove from GENERAL any buffer that duplicates one in
FRAMELIST or PREVLIST. */
args[2] = prevlist;
return Fnconc (3, args);
}
-
- return general;
+ else
+ return general;
}
/* Like Fassoc, but use Fstring_equal to compare
DEFUN ("other-buffer", Fother_buffer, Sother_buffer, 0, 3, 0,
doc: /* Return most recently selected buffer other than BUFFER.
-Buffers not visible in windows are preferred to visible buffers,
-unless optional second argument VISIBLE-OK is non-nil.
-If the optional third argument FRAME is non-nil, use that frame's
-buffer list instead of the selected frame's buffer list.
-If no other buffer exists, the buffer `*scratch*' is returned.
-If BUFFER is omitted or nil, some interesting buffer is returned. */)
+Buffers not visible in windows are preferred to visible buffers, unless
+optional second argument VISIBLE-OK is non-nil. Ignore the argument
+BUFFER unless it denotes a live buffer. If the optional third argument
+FRAME is non-nil, use that frame's buffer list instead of the selected
+frame's buffer list.
+
+The buffer is found by scanning the selected or specified frame's buffer
+list first, followed by the list of all buffers. If no other buffer
+exists, return the buffer `*scratch*' (creating it if necessary). */)
(register Lisp_Object buffer, Lisp_Object visible_ok, Lisp_Object frame)
{
Lisp_Object Fset_buffer_major_mode (Lisp_Object buffer);
- register Lisp_Object tail, buf, notsogood, tem, pred, add_ons;
- notsogood = Qnil;
+ Lisp_Object tail, buf, pred;
+ Lisp_Object notsogood = Qnil;
if (NILP (frame))
frame = selected_frame;
CHECK_FRAME (frame);
- tail = Vbuffer_alist;
pred = frame_buffer_predicate (frame);
-
- /* Consider buffers that have been seen in the selected frame
- before other buffers. */
-
- tem = frame_buffer_list (frame);
- add_ons = Qnil;
- while (CONSP (tem))
+ /* Consider buffers that have been seen in the frame first. */
+ tail = XFRAME (frame)->buffer_list;
+ for (; CONSP (tail); tail = XCDR (tail))
{
- if (BUFFERP (XCAR (tem)))
- add_ons = Fcons (Fcons (Qnil, XCAR (tem)), add_ons);
- tem = XCDR (tem);
+ buf = XCAR (tail);
+ if (BUFFERP (buf) && !EQ (buf, buffer)
+ && !NILP (XBUFFER (buf)->name)
+ && (SREF (XBUFFER (buf)->name, 0) != ' ')
+ /* If the frame has a buffer_predicate, disregard buffers that
+ don't fit the predicate. */
+ && (NILP (pred) || !NILP (call1 (pred, buf))))
+ {
+ if (!NILP (visible_ok)
+ || NILP (Fget_buffer_window (buf, Qvisible)))
+ return buf;
+ else if (NILP (notsogood))
+ notsogood = buf;
+ }
}
- tail = nconc2 (Fnreverse (add_ons), tail);
+ /* Consider alist of all buffers next. */
+ tail = Vbuffer_alist;
for (; CONSP (tail); tail = XCDR (tail))
{
buf = Fcdr (XCAR (tail));
- if (EQ (buf, buffer))
- continue;
- if (NILP (buf))
- continue;
- if (NILP (XBUFFER (buf)->name))
- continue;
- if (SREF (XBUFFER (buf)->name, 0) == ' ')
- continue;
- /* If the selected frame has a buffer_predicate,
- disregard buffers that don't fit the predicate. */
- if (!NILP (pred))
+ if (BUFFERP (buf) && !EQ (buf, buffer)
+ && !NILP (XBUFFER (buf)->name)
+ && (SREF (XBUFFER (buf)->name, 0) != ' ')
+ /* If the frame has a buffer_predicate, disregard buffers that
+ don't fit the predicate. */
+ && (NILP (pred) || !NILP (call1 (pred, buf))))
{
- tem = call1 (pred, buf);
- if (NILP (tem))
- continue;
+ if (!NILP (visible_ok)
+ || NILP (Fget_buffer_window (buf, Qvisible)))
+ return buf;
+ else if (NILP (notsogood))
+ notsogood = buf;
}
-
- if (NILP (visible_ok))
- tem = Fget_buffer_window (buf, Qvisible);
- else
- tem = Qnil;
- if (NILP (tem))
- return buf;
- if (NILP (notsogood))
- notsogood = buf;
}
+
if (!NILP (notsogood))
return notsogood;
- buf = Fget_buffer (build_string ("*scratch*"));
- if (NILP (buf))
+ else
{
- buf = Fget_buffer_create (build_string ("*scratch*"));
- Fset_buffer_major_mode (buf);
+ buf = Fget_buffer (build_string ("*scratch*"));
+ if (NILP (buf))
+ {
+ buf = Fget_buffer_create (build_string ("*scratch*"));
+ Fset_buffer_major_mode (buf);
+ }
+ return buf;
}
- return buf;
}
\f
DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo,
tem = Vinhibit_quit;
Vinhibit_quit = Qt;
- replace_buffer_in_all_windows (buffer);
+ replace_buffer_in_windows (buffer);
Vbuffer_alist = Fdelq (Frassq (buffer, Vbuffer_alist), Vbuffer_alist);
frames_discard_buffer (buffer);
+ replace_buffer_in_windows_safely (buffer);
Vinhibit_quit = tem;
/* Delete any auto-save file, if we saved it in this session.
return Qt;
}
\f
-/* Move the assoc for buffer BUF to the front of buffer-alist. Since
- we do this each time BUF is selected visibly, the more recently
- selected buffers are always closer to the front of the list. This
- means that other_buffer is more likely to choose a relevant buffer. */
+/* Move association for BUFFER to the front of buffer (a)lists. Since
+ we do this each time BUFFER is selected visibly, the more recently
+ selected buffers are always closer to the front of those lists. This
+ means that other_buffer is more likely to choose a relevant buffer.
+
+ Note that this moves BUFFER to the front of the buffer lists of the
+ selected frame even if BUFFER is not shown there. If BUFFER is not
+ shown in the selected frame, consider the present behavior a feature.
+ `select-window' gets this right since it shows BUFFER in the selected
+ window when calling us. */
void
-record_buffer (Lisp_Object buf)
+record_buffer (Lisp_Object buffer)
{
- register Lisp_Object link, prev;
- Lisp_Object frame;
- frame = selected_frame;
-
- prev = Qnil;
- for (link = Vbuffer_alist; CONSP (link); link = XCDR (link))
- {
- if (EQ (XCDR (XCAR (link)), buf))
- break;
- prev = link;
- }
-
- /* Effectively do Vbuffer_alist = Fdelq (link, Vbuffer_alist);
- we cannot use Fdelq itself here because it allows quitting. */
+ Lisp_Object aelt, link, tem;
+ register struct frame *f = XFRAME (selected_frame);
+ register struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
- if (NILP (prev))
- Vbuffer_alist = XCDR (Vbuffer_alist);
- else
- XSETCDR (prev, XCDR (XCDR (prev)));
+ CHECK_BUFFER (buffer);
+ /* Update Vbuffer_alist (we know that it has an entry for BUFFER).
+ Don't allow quitting since this might leave the buffer list in an
+ inconsistent state. */
+ tem = Vinhibit_quit;
+ Vinhibit_quit = Qt;
+ aelt = Frassq (buffer, Vbuffer_alist);
+ link = Fmemq (aelt, Vbuffer_alist);
+ Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
XSETCDR (link, Vbuffer_alist);
Vbuffer_alist = link;
+ Vinhibit_quit = tem;
- /* Effectively do a delq on buried_buffer_list. */
-
- prev = Qnil;
- for (link = XFRAME (frame)->buried_buffer_list; CONSP (link);
- link = XCDR (link))
- {
- if (EQ (XCAR (link), buf))
- {
- if (NILP (prev))
- XFRAME (frame)->buried_buffer_list = XCDR (link);
- else
- XSETCDR (prev, XCDR (XCDR (prev)));
- break;
- }
- prev = link;
- }
-
- /* Now move this buffer to the front of frame_buffer_list also. */
-
- prev = Qnil;
- for (link = frame_buffer_list (frame); CONSP (link);
- link = XCDR (link))
- {
- if (EQ (XCAR (link), buf))
- break;
- prev = link;
- }
-
- /* Effectively do delq. */
-
- if (CONSP (link))
- {
- if (NILP (prev))
- set_frame_buffer_list (frame,
- XCDR (frame_buffer_list (frame)));
- else
- XSETCDR (prev, XCDR (XCDR (prev)));
-
- XSETCDR (link, frame_buffer_list (frame));
- set_frame_buffer_list (frame, link);
- }
- else
- set_frame_buffer_list (frame, Fcons (buf, frame_buffer_list (frame)));
+ /* Update buffer list of selected frame. */
+ f->buffer_list = Fcons (buffer, Fdelq (buffer, f->buffer_list));
+ f->buried_buffer_list = Fdelq (buffer, f->buried_buffer_list);
}
DEFUN ("record-buffer", Frecord_buffer, Srecord_buffer, 1, 1, 0,
}
/* Move BUFFER to the end of the buffer (a)lists. Do nothing if the
- buffer is killed. For the selected frame and window buffer lists
- this moves BUFFER there even if it was never shown in that window
- or that frame. If this happens we have a feature
- (`unrecord-buffer' should be called only when BUFFER is shown in
- the selected window). */
+ buffer is killed. For the selected frame's buffer list this moves
+ BUFFER to its end even if it was never shown in that frame. If
+ this happens we have a feature, hence `unrecord-buffer' should be
+ called only when BUFFER was shown in the selected frame. */
DEFUN ("unrecord-buffer", Funrecord_buffer, Sunrecord_buffer, 1, 1, 0,
doc: /* Move BUFFER to the end of the buffer list. */)
(Lisp_Object buffer)
{
- Lisp_Object aelt, link;
+ Lisp_Object aelt, link, tem;
register struct frame *f = XFRAME (selected_frame);
CHECK_BUFFER (buffer);
- /* Update Vbuffer_alist (we know that it has an entry for BUFFER). */
+ /* Update Vbuffer_alist (we know that it has an entry for BUFFER).
+ Don't allow quitting since this might leave the buffer list in an
+ inconsistent state. */
+ tem = Vinhibit_quit;
+ Vinhibit_quit = Qt;
aelt = Frassq (buffer, Vbuffer_alist);
link = Fmemq (aelt, Vbuffer_alist);
Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
XSETCDR (link, Qnil);
Vbuffer_alist = nconc2 (Vbuffer_alist, link);
+ Vinhibit_quit = tem;
- /* Update buffer list of selected frame. */
+ /* Update buffer lists of selected frame. */
f->buffer_list = Fdelq (buffer, f->buffer_list);
f->buried_buffer_list = Fcons (buffer, Fdelq (buffer, f->buried_buffer_list));
}
Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
Lisp_Object Qwindow_deletable_p, Qdelete_window, Qdisplay_buffer;
-Lisp_Object Qget_mru_window;
+Lisp_Object Qreplace_buffer_in_windows, Qget_mru_window;
+Lisp_Object Qrecord_window_buffer;
Lisp_Object Qresize_root_window, Qresize_root_window_vertically;
Lisp_Object Qscroll_up, Qscroll_down, Qscroll_command;
Lisp_Object Qset, Qabove, Qbelow, Qnest, Qgroup, Qresize;
return w->dedicated;
}
+DEFUN ("window-prev-buffers", Fwindow_prev_buffers, Swindow_prev_buffers,
+ 0, 1, 0,
+ doc: /* Return buffers previously shown in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+The return value is either nil or a list of <buffer, window-start,
+window-point> triples where buffer was previously shown in WINDOW. */)
+ (Lisp_Object window)
+{
+ return decode_window (window)->prev_buffers;
+}
+
+DEFUN ("set-window-prev-buffers", Fset_window_prev_buffers,
+ Sset_window_prev_buffers, 2, 2, 0,
+ doc: /* Set WINDOW's previous buffers to PREV-BUFFERS.
+WINDOW must be a live window and defaults to the selected one. Return
+PREV-BUFFERS.
+
+PREV-BUFFERS should be either nil or a list of <buffer, window-start,
+window-point> triples where buffer was previously shown in WINDOW. */)
+ (Lisp_Object window, Lisp_Object prev_buffers)
+{
+ return decode_any_window (window)->prev_buffers = prev_buffers;
+}
+
+DEFUN ("window-next-buffers", Fwindow_next_buffers, Swindow_next_buffers,
+ 0, 1, 0,
+ doc: /* Return list of buffers recently re-shown in WINDOW.
+WINDOW must be a live window and defaults to the selected one. */)
+ (Lisp_Object window)
+{
+ return decode_window (window)->next_buffers;
+}
+
+DEFUN ("set-window-next-buffers", Fset_window_next_buffers,
+ Sset_window_next_buffers, 2, 2, 0,
+ doc: /* Set WINDOW's next buffers to NEXT-BUFFERS.
+WINDOW must be a live window and defaults to the selected one. Return
+NEXT-BUFFERS.
+
+NEXT-BUFFERS should be either nil or a list of buffers that have been
+recently re-shown in WINDOW. */)
+ (Lisp_Object window, Lisp_Object next_buffers)
+{
+ return decode_any_window (window)->next_buffers = next_buffers;
+}
+
DEFUN ("window-parameters", Fwindow_parameters, Swindow_parameters,
0, 1, 0,
doc: /* Return the parameters of WINDOW and their values.
{
WINDOW_LOOP_UNUSED,
GET_BUFFER_WINDOW, /* Arg is buffer */
- UNSHOW_BUFFER, /* Arg is buffer */
+ REPLACE_BUFFER_IN_WINDOWS_SAFELY, /* Arg is buffer */
REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */
CHECK_ALL_WINDOWS
};
-/* Make WINDOW show another buffer. */
-static Lisp_Object
-window_show_other_buffer (Lisp_Object window)
-{
- struct window *w = XWINDOW (window);
-
- /* Undedicate WINDOW. */
- w->dedicated = Qnil;
- /* Make WINDOW show the buffer returned by Fother_buffer. */
- Fset_window_buffer
- (window, Fother_buffer (w->buffer, Qnil, w->frame), Qnil);
- /* If WINDOW is the selected window, make its buffer current. But do
- so only if the window shows the current buffer (Bug#6454). */
- if (EQ (window, selected_window)
- && XBUFFER (w->buffer) == current_buffer)
- Fset_buffer (w->buffer);
-
- return Qnil;
-}
-
static Lisp_Object
window_loop (enum window_loop type, Lisp_Object obj, int mini, Lisp_Object frames)
{
Lisp_Object window, windows, best_window, frame_arg;
+ int frame_best_window_flag = 0;
struct frame *f;
struct gcpro gcpro1;
is visible, since Fwindow_list skips non-visible frames if
that is desired, under the control of frame_arg. */
if (!MINI_WINDOW_P (w)
- /* For UNSHOW_BUFFER, we must always consider all windows. */
- || type == UNSHOW_BUFFER
+ /* For REPLACE_BUFFER_IN_WINDOWS_SAFELY, we must always
+ consider all windows. */
+ || type == REPLACE_BUFFER_IN_WINDOWS_SAFELY
|| (mini && minibuf_level > 0))
switch (type)
{
case GET_BUFFER_WINDOW:
if (EQ (w->buffer, obj)
- /* Don't find any minibuffer window
- except the one that is currently in use. */
+ /* Don't find any minibuffer window except the one that
+ is currently in use. */
&& (MINI_WINDOW_P (w) ? EQ (window, minibuf_window) : 1))
{
- if (NILP (best_window))
- best_window = window;
- else if (EQ (window, selected_window))
+ if (EQ (window, selected_window))
/* Preferably return the selected window. */
RETURN_UNGCPRO (window);
- else if (EQ (XWINDOW (window)->frame, selected_frame))
- /* Prefer windows on the current frame. */
+ else if (EQ (XWINDOW (window)->frame, selected_frame)
+ && !frame_best_window_flag)
+ /* Prefer windows on the current frame (but don't
+ choose another one if we have one already). */
+ {
+ best_window = window;
+ frame_best_window_flag = 1;
+ }
+ else if (NILP (best_window))
best_window = window;
}
break;
- case UNSHOW_BUFFER:
+ case REPLACE_BUFFER_IN_WINDOWS_SAFELY:
+ /* We could simply check whether the buffer shown by window
+ is live, and show another buffer in case it isn't. */
if (EQ (w->buffer, obj))
{
- struct frame *f = XFRAME (w->frame);
-
- /* If this window is dedicated, and in a frame of its own,
- kill the frame. */
- if (EQ (window, FRAME_ROOT_WINDOW (f))
- && !NILP (w->dedicated)
- && other_visible_frames (f))
- {
- /* Skip the other windows on this frame.
- There might be one, the minibuffer! */
- while (CONSP (XCDR (windows))
- && EQ (XWINDOW (XCAR (windows))->frame,
- XWINDOW (XCAR (XCDR (windows)))->frame))
- windows = XCDR (windows);
-
- /* Now we can safely delete the frame. */
- delete_frame (w->frame, Qnil);
- if (WINDOW_LIVE_P (window))
- /* If the window is still alive, deleting the
- frame failed, so show another buffer in it. */
- window_show_other_buffer (window);
- }
- else if (!NILP (w->dedicated) && !NILP (w->parent))
- {
- Lisp_Object window;
- XSETWINDOW (window, w);
- /* If this window is dedicated and not the only window
- in its frame, then kill it. */
- delete_deletable_window (window);
-
- if (WINDOW_LIVE_P (window))
- /* If the window is still alive, deleting the
- window failed, so show another buffer in
- it. */
- window_show_other_buffer (window);
- }
- else
- window_show_other_buffer (window);
+ /* Undedicate WINDOW. */
+ w->dedicated = Qnil;
+ /* Make WINDOW show the buffer returned by Fother_buffer
+ but don't run any hooks. */
+ set_window_buffer
+ (window, Fother_buffer (w->buffer, Qnil, w->frame), 0, 0);
+ /* If WINDOW is the selected window, make its buffer
+ current. But do so only if the window shows the
+ current buffer (Bug#6454). */
+ if (EQ (window, selected_window)
+ && XBUFFER (w->buffer) == current_buffer)
+ Fset_buffer (w->buffer);
}
break;
}
-DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
- Sreplace_buffer_in_windows,
- 0, 1, "bReplace buffer in windows: ",
- doc: /* Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
-BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
-defaults to the current buffer.
-
-When a window showing BUFFER-OR-NAME is dedicated that window is
-deleted. If that window is the only window on its frame, that frame is
-deleted too when there are other frames left. If there are no other
-frames left, some other buffer is displayed in that window. */)
- (Lisp_Object buffer_or_name)
+void
+replace_buffer_in_windows (Lisp_Object buffer)
{
- Lisp_Object buffer;
-
- if (NILP (buffer_or_name))
- buffer = Fcurrent_buffer ();
- else
- {
- buffer = Fget_buffer (buffer_or_name);
- CHECK_BUFFER (buffer);
- }
-
- window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
-
- return Qnil;
+ call1 (Qreplace_buffer_in_windows, buffer);
}
-/* Replace BUFFER with some other buffer in all windows
- of all frames, even those on other keyboards. */
+
+/* Safely replace BUFFER with some other buffer in all windows of all
+ frames, even those on other keyboards. */
void
-replace_buffer_in_all_windows (Lisp_Object buffer)
+replace_buffer_in_windows_safely (Lisp_Object buffer)
{
Lisp_Object tail, frame;
considers frames on the current keyboard. So loop manually over
frames, and handle each one. */
FOR_EACH_FRAME (tail, frame)
- window_loop (UNSHOW_BUFFER, buffer, 1, frame);
+ window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame);
}
\f
/* If *ROWS or *COLS are too small a size for FRAME, set them to the
/* w->buffer is t when the window is first being set up. */
{
if (!EQ (tem, buffer))
- if (EQ (w->dedicated, Qt))
- error ("Window is dedicated to `%s'", SDATA (XBUFFER (tem)->name));
- else
- w->dedicated = Qnil;
+ {
+ if (EQ (w->dedicated, Qt))
+ /* WINDOW is strongly dedicated to its buffer, signal an
+ error. */
+ error ("Window is dedicated to `%s'", SDATA (XBUFFER (tem)->name));
+ else
+ /* WINDOW is weakly dedicated to its buffer, reset
+ dedicatedness. */
+ w->dedicated = Qnil;
+
+ call1 (Qrecord_window_buffer, window);
+ }
unshow_buffer (w);
}
w->start_at_line_beg = w->display_table = w->dedicated = Qnil;
w->base_line_number = w->base_line_pos = w->region_showing = Qnil;
w->column_number_displayed = w->redisplay_end_trigger = Qnil;
+ w->inhibit_recombine = w->window_parameters = Qnil;
+ w->prev_buffers = w->next_buffers = Qnil;
/* Initialize non-Lisp data. */
w->desired_matrix = w->current_matrix = 0;
w->nrows_scale_factor = w->ncols_scale_factor = 1;
Qdisplay_buffer = intern_c_string ("display-buffer");
staticpro (&Qdisplay_buffer);
+ Qreplace_buffer_in_windows = intern_c_string ("replace-buffer-in-windows");
+ staticpro (&Qreplace_buffer_in_windows);
+
+ Qrecord_window_buffer = intern_c_string ("record-window-buffer");
+ staticpro (&Qrecord_window_buffer);
+
Qget_mru_window = intern_c_string ("get-mru-window");
staticpro (&Qget_mru_window);
defsubr (&Sprevious_window);
defsubr (&Sget_buffer_window);
defsubr (&Sdelete_other_windows_internal);
- defsubr (&Sreplace_buffer_in_windows);
defsubr (&Sdelete_window_internal);
defsubr (&Sresize_mini_window_internal);
defsubr (&Sset_window_buffer);
defsubr (&Scompare_window_configurations);
defsubr (&Swindow_list);
defsubr (&Swindow_list_1);
+ defsubr (&Swindow_prev_buffers);
+ defsubr (&Sset_window_prev_buffers);
+ defsubr (&Swindow_next_buffers);
+ defsubr (&Sset_window_next_buffers);
defsubr (&Swindow_parameters);
defsubr (&Swindow_parameter);
defsubr (&Sset_window_parameter);
/* Non-nil means window must not be recombined. */
Lisp_Object inhibit_recombine;
+ /* Alist of <buffer, window-start, window-point> triples listing
+ buffers previously shown in this window. */
+ Lisp_Object prev_buffers;
+
+ /* List of buffers re-shown in this window. */
+ Lisp_Object next_buffers;
+
/* An alist with parameteres. */
Lisp_Object window_parameters;
EXFUN (Fscroll_other_window, 1);
EXFUN (Fset_window_start, 3);
extern void temp_output_buffer_show (Lisp_Object);
-extern void replace_buffer_in_all_windows (Lisp_Object);
+extern void replace_buffer_in_windows_safely (Lisp_Object);
extern void init_window_once (void);
extern void init_window (void);
extern void syms_of_window (void);