Commit 97f24412 authored by Robert Cochran's avatar Robert Cochran Committed by Juri Linkov

Add hooks for after tab open, before close, and to prevent closing

* lisp/tab-bar.el (tab-bar-tab-post-open-functions,
tab-bar-tab-prevent-close-functions, tab-bar-tab-pre-close-functions):
New defcustoms
(tab-bar-new-tab-to, tab-bar-close-tab): Use new defcustoms
parent 8e1c5532
Pipeline #4267 failed with stage
in 64 minutes and 48 seconds
...@@ -692,6 +692,15 @@ If `rightmost', create as the last tab." ...@@ -692,6 +692,15 @@ If `rightmost', create as the last tab."
:group 'tab-bar :group 'tab-bar
:version "27.1") :version "27.1")
(defcustom tab-bar-tab-post-open-functions nil
"List of functions to call after creating a new tab.
The current tab is supplied as an argument. Any modifications
made to the tab argument will be applied after all functions are
called."
:type '(repeat function)
:group 'tab-bar
:version "27.1")
(defun tab-bar-new-tab-to (&optional to-index) (defun tab-bar-new-tab-to (&optional to-index)
"Add a new tab at the absolute position TO-INDEX. "Add a new tab at the absolute position TO-INDEX.
TO-INDEX counts from 1. If no TO-INDEX is specified, then add TO-INDEX counts from 1. If no TO-INDEX is specified, then add
...@@ -726,9 +735,13 @@ a new tab at the position specified by `tab-bar-new-tab-to'." ...@@ -726,9 +735,13 @@ a new tab at the position specified by `tab-bar-new-tab-to'."
('right (1+ (or from-index 0))))))) ('right (1+ (or from-index 0)))))))
(setq to-index (max 0 (min (or to-index 0) (length tabs)))) (setq to-index (max 0 (min (or to-index 0) (length tabs))))
(cl-pushnew to-tab (nthcdr to-index tabs)) (cl-pushnew to-tab (nthcdr to-index tabs))
(when (eq to-index 0) (when (eq to-index 0)
;; pushnew handles the head of tabs but not frame-parameter ;; pushnew handles the head of tabs but not frame-parameter
(set-frame-parameter nil 'tabs tabs))) (set-frame-parameter nil 'tabs tabs))
(run-hook-with-args 'tab-bar-tab-post-open-functions
(nth to-index tabs)))
(when (and (not tab-bar-mode) (when (and (not tab-bar-mode)
(or (eq tab-bar-show t) (or (eq tab-bar-show t)
...@@ -780,6 +793,24 @@ If the value is a function, call that function with the tab to be closed as an a ...@@ -780,6 +793,24 @@ If the value is a function, call that function with the tab to be closed as an a
:group 'tab-bar :group 'tab-bar
:version "27.1") :version "27.1")
(defcustom tab-bar-tab-prevent-close-functions nil
"List of functions to call to determine whether to close a tab.
The tab to be closed and a boolean indicating whether or not it
is the only tab in the frame are supplied as arguments. If any
function returns a non-nil value, the tab will not be closed."
:type '(repeat function)
:group 'tab-bar
:version "27.1")
(defcustom tab-bar-tab-pre-close-functions nil
"List of functions to call before closing a tab.
The tab to be closed and a boolean indicating whether or not it
is the only tab in the frame are supplied as arguments,
respectively."
:type '(repeat function)
:group 'tab-bar
:version "27.1")
(defun tab-bar-close-tab (&optional arg to-index) (defun tab-bar-close-tab (&optional arg to-index)
"Close the tab specified by its absolute position ARG. "Close the tab specified by its absolute position ARG.
If no ARG is specified, then close the current tab and switch If no ARG is specified, then close the current tab and switch
...@@ -792,52 +823,63 @@ TO-INDEX counts from 1." ...@@ -792,52 +823,63 @@ TO-INDEX counts from 1."
(interactive "P") (interactive "P")
(let* ((tabs (funcall tab-bar-tabs-function)) (let* ((tabs (funcall tab-bar-tabs-function))
(current-index (tab-bar--current-tab-index tabs)) (current-index (tab-bar--current-tab-index tabs))
(close-index (if (integerp arg) (1- arg) current-index))) (close-index (if (integerp arg) (1- arg) current-index))
(if (= 1 (length tabs)) (last-tab-p (= 1 (length tabs)))
(pcase tab-bar-close-last-tab-choice (prevent-close (run-hook-with-args-until-success
('nil 'tab-bar-tab-prevent-close-functions
(signal 'user-error '("Attempt to delete the sole tab in a frame"))) (nth close-index tabs)
('delete-frame last-tab-p)))
(delete-frame))
('tab-bar-mode-disable (unless prevent-close
(tab-bar-mode -1)) (run-hook-with-args 'tab-bar-tab-pre-close-functions
((pred functionp) (nth close-index tabs)
;; Give the handler function the full extent of the tab's last-tab-p)
;; data, not just it's name and explicit-name flag.
(funcall tab-bar-close-last-tab-choice (tab-bar--tab)))) (if last-tab-p
(pcase tab-bar-close-last-tab-choice
;; More than one tab still open ('nil
(when (eq current-index close-index) (user-error "Attempt to delete the sole tab in a frame"))
;; Select another tab before deleting the current tab ('delete-frame
(let ((to-index (or (if to-index (1- to-index)) (delete-frame))
(pcase tab-bar-close-tab-select ('tab-bar-mode-disable
('left (1- current-index)) (tab-bar-mode -1))
('right (if (> (length tabs) (1+ current-index)) ((pred functionp)
(1+ current-index) ;; Give the handler function the full extent of the tab's
(1- current-index))) ;; data, not just it's name and explicit-name flag.
('recent (tab-bar--tab-index-recent 1 tabs)))))) (funcall tab-bar-close-last-tab-choice (tab-bar--tab))))
(setq to-index (max 0 (min (or to-index 0) (1- (length tabs)))))
(tab-bar-select-tab (1+ to-index)) ;; More than one tab still open
;; Re-read tabs after selecting another tab (when (eq current-index close-index)
(setq tabs (funcall tab-bar-tabs-function)))) ;; Select another tab before deleting the current tab
(let ((to-index (or (if to-index (1- to-index))
(let ((close-tab (nth close-index tabs))) (pcase tab-bar-close-tab-select
(push `((frame . ,(selected-frame)) ('left (1- current-index))
(index . ,close-index) ('right (if (> (length tabs) (1+ current-index))
(tab . ,(if (eq (car close-tab) 'current-tab) (1+ current-index)
(tab-bar--tab) (1- current-index)))
close-tab))) ('recent (tab-bar--tab-index-recent 1 tabs))))))
tab-bar-closed-tabs) (setq to-index (max 0 (min (or to-index 0) (1- (length tabs)))))
(set-frame-parameter nil 'tabs (delq close-tab tabs))) (tab-bar-select-tab (1+ to-index))
;; Re-read tabs after selecting another tab
(when (and tab-bar-mode (setq tabs (funcall tab-bar-tabs-function))))
(and (natnump tab-bar-show)
(<= (length tabs) tab-bar-show))) (let ((close-tab (nth close-index tabs)))
(tab-bar-mode -1)) (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
(and (natnump tab-bar-show)
(<= (length tabs) tab-bar-show)))
(tab-bar-mode -1))
(force-mode-line-update) (force-mode-line-update)
(unless tab-bar-mode (unless tab-bar-mode
(message "Deleted tab and switched to %s" tab-bar-close-tab-select))))) (message "Deleted tab and switched to %s" tab-bar-close-tab-select))))))
(defun tab-bar-close-tab-by-name (name) (defun tab-bar-close-tab-by-name (name)
"Close the tab by NAME." "Close the tab by NAME."
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment