From ffdb2ae377c71ef089f57f44b79dcff6ef8f2aa1 Mon Sep 17 00:00:00 2001 From: Robert Cochran Date: Wed, 23 Oct 2019 17:34:24 -0700 Subject: [PATCH] Add customization option for what do when the last tab is closed * lisp/tab-bar.el (tab-bar-close-last-tab-choice): New custom variable. (tab-bar-close-tab): Handle closing the last tab specially, referring to tab-bar-close-last-tab-choice. --- lisp/tab-bar.el | 84 +++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 617057cf46..d664774b6c 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -634,6 +634,19 @@ tab-bar-close-tab-select :group 'tab-bar :version "27.1") +(defcustom tab-bar-close-last-tab-choice nil + "Defines what to do when the last tab is closed. +If nil, do nothing and show a message, like closing the last window or frame. +If `close-frame', delete the containing frame, as a web browser would do. +If `disable-tab-bar', disable tab-bar-mode so that tabs no longer show in the frame. +If the value is a function, call that function with the tab to be closed as an argument." + :type '(choice (const :tag "Do nothing and show message" nil) + (const :tag "Delete the containing frame" close-frame) + (const :tag "Disable tab-bar-mode" disable-tab-bar) + (function :tag "Function")) + :group 'tab-bar + :version "27.1") + (defun tab-bar-close-tab (&optional arg to-index) "Close the tab specified by its absolute position ARG. If no ARG is specified, then close the current tab and switch @@ -647,38 +660,49 @@ tab-bar-close-tab (let* ((tabs (funcall tab-bar-tabs-function)) (current-index (tab-bar--current-tab-index tabs)) (close-index (if (integerp arg) (1- arg) current-index))) + (if (= 1 (length tabs)) + (pcase tab-bar-close-last-tab-choice + ('nil + (signal 'user-error '("Attempt to delete the sole tab in a frame"))) + ('close-frame + (delete-frame)) + ('disable-tab-bar + (tab-bar-mode -1)) + ((pred functionp) + ;; Give the handler function the full extent of the tab's + ;; data, not just it's name and explicit-name flag. + (funcall tab-bar-close-last-tab-choice (tab-bar--tab)))) + + ;;; More than one tab still open + (when (eq current-index close-index) + (let ((to-index (or (if to-index (1- to-index)) + (pcase tab-bar-close-tab-select + ('left (1- current-index)) + ('right (if (> (length tabs) (1+ current-index)) + (1+ current-index) + (1- current-index))))))) + (setq to-index (max 0 (min (or to-index 0) (1- (length tabs))))) + (tab-bar-select-tab (1+ to-index)) + ;; Re-read tabs after selecting another tab + (setq tabs (funcall tab-bar-tabs-function)))) + + (let ((close-tab (nth close-index tabs))) + (push `((frame . ,(selected-frame)) + (index . ,close-index) + (tab . ,(if (eq (car close-tab) 'current-tab) + (tab-bar--tab) + close-tab))) + tab-bar-closed-tabs) + (set-frame-parameter nil 'tabs (delq close-tab tabs))) - ;; Select another tab before deleting the current tab - (when (eq current-index close-index) - (let ((to-index (or (if to-index (1- to-index)) - (pcase tab-bar-close-tab-select - ('left (1- current-index)) - ('right (if (> (length tabs) (1+ current-index)) - (1+ current-index) - (1- current-index))))))) - (setq to-index (max 0 (min (or to-index 0) (1- (length tabs))))) - (tab-bar-select-tab (1+ to-index)) - ;; Re-read tabs after selecting another tab - (setq tabs (funcall tab-bar-tabs-function)))) - - (let ((close-tab (nth close-index tabs))) - (push `((frame . ,(selected-frame)) - (index . ,close-index) - (tab . ,(if (eq (car close-tab) 'current-tab) - (tab-bar--tab) - close-tab))) - tab-bar-closed-tabs) - (set-frame-parameter nil 'tabs (delq close-tab tabs))) - - (when (and tab-bar-mode - (or (<= (length tabs) 1) ; closed the last tab - (and (natnump tab-bar-show) - (<= (length tabs) tab-bar-show)))) - (tab-bar-mode -1)) + (when (and tab-bar-mode + (and (natnump tab-bar-show) + (<= (length tabs) tab-bar-show))) + (tab-bar-mode -1)) - (force-mode-line-update) - (unless tab-bar-mode - (message "Deleted tab and switched to %s" tab-bar-close-tab-select)))) + (force-mode-line-update) + (unless tab-bar-mode + (message "Deleted tab and switched to %s" tab-bar-close-tab-select))))) (defun tab-bar-close-tab-by-name (name) "Close the tab by NAME." -- 2.21.0