diff options
| author | Robert Cochran | 2019-10-23 17:34:24 -0700 |
|---|---|---|
| committer | Juri Linkov | 2019-10-27 00:41:45 +0300 |
| commit | 6d2ea60ca874f04c37527b21355f81a2b140d405 (patch) | |
| tree | 1100ad4a2e5f76f28ada4ce1e55e8bf5609f1e7e | |
| parent | f247599e167d34be93badd693a8b4de15daa0a8e (diff) | |
| download | emacs-6d2ea60ca874f04c37527b21355f81a2b140d405.tar.gz emacs-6d2ea60ca874f04c37527b21355f81a2b140d405.zip | |
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.
| -rw-r--r-- | lisp/tab-bar.el | 84 |
1 files changed, 54 insertions, 30 deletions
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 617057cf460..d664774b6c0 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el | |||
| @@ -634,6 +634,19 @@ If `right', select the adjacent right tab." | |||
| 634 | :group 'tab-bar | 634 | :group 'tab-bar |
| 635 | :version "27.1") | 635 | :version "27.1") |
| 636 | 636 | ||
| 637 | (defcustom tab-bar-close-last-tab-choice nil | ||
| 638 | "Defines what to do when the last tab is closed. | ||
| 639 | If nil, do nothing and show a message, like closing the last window or frame. | ||
| 640 | If `close-frame', delete the containing frame, as a web browser would do. | ||
| 641 | If `disable-tab-bar', disable tab-bar-mode so that tabs no longer show in the frame. | ||
| 642 | If the value is a function, call that function with the tab to be closed as an argument." | ||
| 643 | :type '(choice (const :tag "Do nothing and show message" nil) | ||
| 644 | (const :tag "Delete the containing frame" close-frame) | ||
| 645 | (const :tag "Disable tab-bar-mode" disable-tab-bar) | ||
| 646 | (function :tag "Function")) | ||
| 647 | :group 'tab-bar | ||
| 648 | :version "27.1") | ||
| 649 | |||
| 637 | (defun tab-bar-close-tab (&optional arg to-index) | 650 | (defun tab-bar-close-tab (&optional arg to-index) |
| 638 | "Close the tab specified by its absolute position ARG. | 651 | "Close the tab specified by its absolute position ARG. |
| 639 | If no ARG is specified, then close the current tab and switch | 652 | If no ARG is specified, then close the current tab and switch |
| @@ -647,38 +660,49 @@ TO-INDEX counts from 1." | |||
| 647 | (let* ((tabs (funcall tab-bar-tabs-function)) | 660 | (let* ((tabs (funcall tab-bar-tabs-function)) |
| 648 | (current-index (tab-bar--current-tab-index tabs)) | 661 | (current-index (tab-bar--current-tab-index tabs)) |
| 649 | (close-index (if (integerp arg) (1- arg) current-index))) | 662 | (close-index (if (integerp arg) (1- arg) current-index))) |
| 663 | (if (= 1 (length tabs)) | ||
| 664 | (pcase tab-bar-close-last-tab-choice | ||
| 665 | ('nil | ||
| 666 | (signal 'user-error '("Attempt to delete the sole tab in a frame"))) | ||
| 667 | ('close-frame | ||
| 668 | (delete-frame)) | ||
| 669 | ('disable-tab-bar | ||
| 670 | (tab-bar-mode -1)) | ||
| 671 | ((pred functionp) | ||
| 672 | ;; Give the handler function the full extent of the tab's | ||
| 673 | ;; data, not just it's name and explicit-name flag. | ||
| 674 | (funcall tab-bar-close-last-tab-choice (tab-bar--tab)))) | ||
| 675 | |||
| 676 | ;;; More than one tab still open | ||
| 677 | (when (eq current-index close-index) | ||
| 678 | (let ((to-index (or (if to-index (1- to-index)) | ||
| 679 | (pcase tab-bar-close-tab-select | ||
| 680 | ('left (1- current-index)) | ||
| 681 | ('right (if (> (length tabs) (1+ current-index)) | ||
| 682 | (1+ current-index) | ||
| 683 | (1- current-index))))))) | ||
| 684 | (setq to-index (max 0 (min (or to-index 0) (1- (length tabs))))) | ||
| 685 | (tab-bar-select-tab (1+ to-index)) | ||
| 686 | ;; Re-read tabs after selecting another tab | ||
| 687 | (setq tabs (funcall tab-bar-tabs-function)))) | ||
| 688 | |||
| 689 | (let ((close-tab (nth close-index tabs))) | ||
| 690 | (push `((frame . ,(selected-frame)) | ||
| 691 | (index . ,close-index) | ||
| 692 | (tab . ,(if (eq (car close-tab) 'current-tab) | ||
| 693 | (tab-bar--tab) | ||
| 694 | close-tab))) | ||
| 695 | tab-bar-closed-tabs) | ||
| 696 | (set-frame-parameter nil 'tabs (delq close-tab tabs))) | ||
| 650 | 697 | ||
| 651 | ;; Select another tab before deleting the current tab | 698 | (when (and tab-bar-mode |
| 652 | (when (eq current-index close-index) | 699 | (and (natnump tab-bar-show) |
| 653 | (let ((to-index (or (if to-index (1- to-index)) | 700 | (<= (length tabs) tab-bar-show))) |
| 654 | (pcase tab-bar-close-tab-select | 701 | (tab-bar-mode -1)) |
| 655 | ('left (1- current-index)) | ||
| 656 | ('right (if (> (length tabs) (1+ current-index)) | ||
| 657 | (1+ current-index) | ||
| 658 | (1- current-index))))))) | ||
| 659 | (setq to-index (max 0 (min (or to-index 0) (1- (length tabs))))) | ||
| 660 | (tab-bar-select-tab (1+ to-index)) | ||
| 661 | ;; Re-read tabs after selecting another tab | ||
| 662 | (setq tabs (funcall tab-bar-tabs-function)))) | ||
| 663 | |||
| 664 | (let ((close-tab (nth close-index tabs))) | ||
| 665 | (push `((frame . ,(selected-frame)) | ||
| 666 | (index . ,close-index) | ||
| 667 | (tab . ,(if (eq (car close-tab) 'current-tab) | ||
| 668 | (tab-bar--tab) | ||
| 669 | close-tab))) | ||
| 670 | tab-bar-closed-tabs) | ||
| 671 | (set-frame-parameter nil 'tabs (delq close-tab tabs))) | ||
| 672 | |||
| 673 | (when (and tab-bar-mode | ||
| 674 | (or (<= (length tabs) 1) ; closed the last tab | ||
| 675 | (and (natnump tab-bar-show) | ||
| 676 | (<= (length tabs) tab-bar-show)))) | ||
| 677 | (tab-bar-mode -1)) | ||
| 678 | 702 | ||
| 679 | (force-mode-line-update) | 703 | (force-mode-line-update) |
| 680 | (unless tab-bar-mode | 704 | (unless tab-bar-mode |
| 681 | (message "Deleted tab and switched to %s" tab-bar-close-tab-select)))) | 705 | (message "Deleted tab and switched to %s" tab-bar-close-tab-select))))) |
| 682 | 706 | ||
| 683 | (defun tab-bar-close-tab-by-name (name) | 707 | (defun tab-bar-close-tab-by-name (name) |
| 684 | "Close the tab by NAME." | 708 | "Close the tab by NAME." |