diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 61efa332e0b..f05596d5ed9 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -1393,6 +1405,53 @@ tab-bar-tab-post-select-functions :group 'tab-bar :version "30.1") +(defcustom tab-bar-select-keep-windows-function #'tab-bar-select-keep-windows + "Function that keeps windows after selecting a tab. +When a previously selected tab displayed a buffer that was later killed, +this function defines what to do with the window that displayed that buffer +after switching back to the previous tab. By default, either a random +buffer is displayed instead of the killed buffer, or the window gets deleted. +However, with the help of `window-kept-windows-functions' it's possible +to handle such situations better by displaying an information about +the killed buffer." + :type '(choice (const :tag "No special handling" nil) + (const :tag "Show placeholder buffers" + tab-bar-select-keep-windows) + (function :tag "Function")) + :group 'tab-bar + :version "30.1") + +(defun tab-bar-select-keep-windows (_frame windows) + "Display a placeholder buffer in the window with killed buffer. +A button allows to restore a killed file buffer." + (dolist (quad windows) + (when (window-live-p (nth 0 quad)) + (let* ((window (nth 0 quad)) + (old-buffer (nth 1 quad)) + (file (when (bufferp old-buffer) + (buffer-file-name old-buffer))) + (name (or file + (and (fboundp 'buffer-last-name) + (buffer-last-name old-buffer)) + old-buffer)) + (new-buffer (generate-new-buffer + (format "*Old buffer %s*" name)))) + (with-current-buffer new-buffer + (set-auto-mode) + (insert (format-message "This window displayed the %s `%s'.\n" + (if file "file" "buffer") + name)) + (when file + (insert-button + "[Restore]" 'action + (lambda (_button) + (set-window-buffer window (find-file-noselect file)) + (set-window-start window (nth 2 quad) t) + (set-window-point window (nth 3 quad))))) + (goto-char (point-min)) + (setq buffer-read-only t) + (set-window-buffer window new-buffer)))))) + (defvar tab-bar-minibuffer-restore-tab nil "Tab number for `tab-bar-minibuffer-restore-tab'.") @@ -1438,7 +1497,10 @@ tab-bar-select-tab (let* ((from-tab (tab-bar--tab)) (to-tab (nth to-index tabs)) (wc (alist-get 'wc to-tab)) - (ws (alist-get 'ws to-tab))) + (ws (alist-get 'ws to-tab)) + (window-kept-windows-functions + (delq nil (cons tab-bar-select-keep-windows-function + window-kept-windows-functions)))) ;; During the same session, use window-configuration to switch ;; tabs, because window-configurations are more reliable