[PATCH] Enable persistent naming for tabs

classic Classic list List threaded Threaded
24 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[PATCH] Enable persistent naming for tabs

Robert Cochran-2
Hi emacs-devel,

I saw news recently of the new tabs that are on master. They're really
nifty - kudos to Juri Linkov for doing a lot of work on them. :)

I was admittedly a little disappointed, however, to see that the user, or
other Lisp programs, couldn't change the name of a tab persistently - it
*could* be changed, but a lot of the functions that handle tabs
immediately call the automatic naming function, before the UI could even
update to display it. Some applications might want to have a consistent
name divorced from the current buffer, and sometimes it would be nice to
override the automatic name on a per-tab basis as a user.

The solution I went with was another value in the tabs frame-parameter
alist. A new cons with the name `no-auto-name` in the car is used. If
the cdr is nil, then the behavior we have now remains - the tab handling
functions will call the value of `tab-bar-tab-name-function` and update
the name immediately. With a non-nil value, any time
`tab-bar-tab-name-function` would be called, the existing name is
instead substituted.

I've added 2 new functions, `tab-bar-rename-tab` and
`tab-bar-rename-tab-by-name`. Both functions take a new name, and a tag
identifier, either a frame tab index or an existing name,
respectively. The new name is then set on the tab, and the
`no-auto-name` parameter is set non-nil, unless the new name is the
empty string, which is taken to mean 'turn automatic naming back on'.

A couple of things I'm still wondering about: should this be documented
in the manual? I was going to do so, but couldn't really find a good
spot to mention it. If we do add something to the manual, we should
mention `tab-bar-tab-name-function` as well. Do we want to add this to
the default `C-x 6` binds, possibly as `C-x 6 r`? I already set
`tab-rename` as an alias to `tab-bar-rename-tab`, but I'm curious what
other people are thinking on that. Is there a better name for
`no-auto-name`? I couldn't think of a better one... I was aiming to have
a name who's interpretation as 'nil' is 'don't do anything differently',
so as to make the code slightly easier to read, as well as ensuring
saved tabs don't get automatic naming turned on by mistake.

Thanks,
--
~Robert Cochran


From 59126587d419b5f57c79a970919894f6e91b5c91 Mon Sep 17 00:00:00 2001
From: Robert Cochran <[hidden email]>
Date: Mon, 7 Oct 2019 13:41:47 -0700
Subject: [PATCH] Allow tabs to have consistent given names

* lisp/tab-bar.el (tab-bar--tab): Pull automatic name information from
current tab
(tab-bar--current-tab): Pull automatic name information from current
tab, or from new optional template argument
(tab-bar-select-tab): Pass the target tab as a template when setting
current tab
(tab-bar-rename-tab, tab-bar-rename-tab-by-name): New functions
---
 lisp/tab-bar.el | 80 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 66 insertions(+), 14 deletions(-)

diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 91bc589ae2..1a1d5ab2b8 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -301,9 +301,13 @@ tab-bar-make-keymap-1
   (let* ((separator (or tab-bar-separator (if window-system " " "|")))
          (i 0)
          (tabs (funcall tab-bar-tabs-function))
-         (current-tab-name (assq 'name (assq 'current-tab tabs))))
-    (when current-tab-name
-      (setf (cdr current-tab-name) (funcall tab-bar-tab-name-function)))
+         (current-tab-name (assq 'name (assq 'current-tab tabs)))
+         (current-tab-no-auto-name (assq 'no-auto-name (assq 'current-tab tabs))))
+    (when (and current-tab-name
+               current-tab-no-auto-name
+               (not (cdr current-tab-no-auto-name)))
+      (setf (cdr current-tab-name)
+            (funcall tab-bar-tab-name-function)))
     (append
      '(keymap (mouse-1 . tab-bar-handle-mouse))
      (mapcan
@@ -355,16 +359,29 @@ tab-bar-make-keymap-1
 
 
 (defun tab-bar--tab ()
-  `(tab
-    (name . ,(funcall tab-bar-tab-name-function))
-    (time . ,(time-convert nil 'integer))
-    (wc . ,(current-window-configuration))
-    (ws . ,(window-state-get
-            (frame-root-window (selected-frame)) 'writable))))
-
-(defun tab-bar--current-tab ()
-  `(current-tab
-    (name . ,(funcall tab-bar-tab-name-function))))
+  (let* ((tab (assq 'current-tab (frame-parameter nil 'tabs)))
+         (tab-no-auto-name (cdr (assq 'no-auto-name tab))))
+    `(tab
+      (name . ,(if tab-no-auto-name
+                   (cdr (assq 'name tab))
+                 (funcall tab-bar-tab-name-function)))
+      (no-auto-name . ,tab-no-auto-name)
+      (time . ,(time-convert nil 'integer))
+      (wc . ,(current-window-configuration))
+      (ws . ,(window-state-get
+              (frame-root-window (selected-frame)) 'writable)))))
+
+(defun tab-bar--current-tab (&optional tab)
+  ;; `tab` here is an argument meaning 'use tab as template'. This is
+  ;; necessary when switching tabs, otherwise the destination tab
+  ;; inherent the current tab's `no-auto-name` parameter.
+  (let* ((tab (or tab (assq 'current-tab (frame-parameter nil 'tabs))))
+         (tab-no-auto-name (cdr (assq 'no-auto-name tab))))
+    `(current-tab
+      (name . ,(if tab-no-auto-name
+                   (cdr (assq 'name tab))
+                 (funcall tab-bar-tab-name-function)))
+      (no-auto-name . ,tab-no-auto-name))))
 
 (defun tab-bar--current-tab-index (&optional tabs)
   ;; FIXME: could be replaced with 1-liner using seq-position
@@ -433,7 +450,7 @@ tab-bar-select-tab
 
         (when from-index
           (setf (nth from-index tabs) from-tab))
-        (setf (nth to-index tabs) (tab-bar--current-tab)))
+        (setf (nth to-index tabs) (tab-bar--current-tab (nth to-index tabs))))
 
       (when tab-bar-mode
         (force-mode-line-update)))))
@@ -587,6 +604,40 @@ tab-close-other
           (force-mode-line-update)
         (message "Deleted all other tabs")))))
 
+(defun tab-bar-rename-tab (name &optional arg)
+  "Rename the tab specified by its absolute position ARG.
+If no ARG is specified, then rename the current tab.
+ARG counts from 1.
+If NAME is the empty string, then use the automatic name
+function `tab-bar-tab-name-function'."
+  (interactive "sNew name for tab (leave blank for automatic naming): \nP")
+  (let* ((tabs (tab-bar-tabs))
+         (tab-index (if arg
+                        (1- (max 0 (min arg (length tabs))))
+                      (tab-bar--current-tab-index tabs)))
+         (tab-to-rename (nth tab-index tabs))
+         (tab-no-auto-name (> (length name) 0))
+         (tab-new-name (if tab-no-auto-name
+                           name
+                         (funcall tab-bar-tab-name-function))))
+    (setf (cdr (assq 'name tab-to-rename)) tab-new-name
+          (cdr (assq 'no-auto-name tab-to-rename)) tab-no-auto-name
+          (frame-parameter nil 'tabs) tabs)
+    (if (tab-bar-mode)
+        (force-mode-line-update)
+      (message "Renamed tab to '%s'" tab-new-name))))
+
+(defun tab-bar-rename-tab-by-name (tab-name new-name)
+  "Rename the tab named TAB-NAME.
+If NEW-NAME is the empty string, then use the automatic name
+function `tab-bar-tab-name-function'."
+  (interactive (list (completing-read "Rename tab by name: "
+                                      (mapcar (lambda (tab)
+                                                (cdr (assq 'name tab)))
+                                              (tab-bar-tabs)))
+                     (read-from-minibuffer "New name for tab (leave blank for automatic naming): ")))
+  (tab-bar-rename-tab new-name (tab-bar--tab-index-by-name tab-name)))
+
 
 ;;; Short aliases
 
@@ -595,6 +646,7 @@ 'tab-close
 (defalias 'tab-select   'tab-bar-select-tab)
 (defalias 'tab-next     'tab-bar-switch-to-next-tab)
 (defalias 'tab-previous 'tab-bar-switch-to-prev-tab)
+(defalias 'tab-rename   'tab-bar-rename-tab)
 (defalias 'tab-list     'tab-bar-list)
 
 
--
2.21.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Eli Zaretskii
> From: Robert Cochran <[hidden email]>
> Date: Tue, 08 Oct 2019 15:26:10 -0700
>
> The solution I went with was another value in the tabs frame-parameter
> alist. A new cons with the name `no-auto-name` in the car is used. If
> the cdr is nil, then the behavior we have now remains - the tab handling
> functions will call the value of `tab-bar-tab-name-function` and update
> the name immediately. With a non-nil value, any time
> `tab-bar-tab-name-function` would be called, the existing name is
> instead substituted.

Isn't this unnecessarily complicated?  Why not have the name assigned
by tab-bar-tab-name-function stick instead?

Thanks.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
In reply to this post by Robert Cochran-2
> I've added 2 new functions, `tab-bar-rename-tab` and
> `tab-bar-rename-tab-by-name`. Both functions take a new name, and a tag
> identifier, either a frame tab index or an existing name,
> respectively. The new name is then set on the tab, and the
> `no-auto-name` parameter is set non-nil, unless the new name is the
> empty string, which is taken to mean 'turn automatic naming back on'.

Thanks, this is a useful feature.  Like the feature of renaming buffers
(and using it often to rename such buffers as *Info* and *shell*
to match better their content) tab renaming would help to identify
tab content better.

> A couple of things I'm still wondering about: should this be documented
> in the manual? I was going to do so, but couldn't really find a good
> spot to mention it. If we do add something to the manual, we should
> mention `tab-bar-tab-name-function` as well. Do we want to add this to
> the default `C-x 6` binds, possibly as `C-x 6 r`? I already set
> `tab-rename` as an alias to `tab-bar-rename-tab`, but I'm curious what
> other people are thinking on that. Is there a better name for
> `no-auto-name`? I couldn't think of a better one... I was aiming to have
> a name who's interpretation as 'nil' is 'don't do anything differently',
> so as to make the code slightly easier to read, as well as ensuring
> saved tabs don't get automatic naming turned on by mistake.

You have a good choice of command names and the key binding.
But please give me an additional day to think about a possibility of
avoiding `no-auto-name` to not make code unnecessarily complicated.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Robert Cochran
In reply to this post by Robert Cochran-2

[[ Apparently the email address in the From doesn't actually work right
now... oops, gonna have to fix that... in the mean time, going to use
another address. My appologies if that messes up threading. ]]

> But please give me an additional day to think about a possibility of
> avoiding `no-auto-name` to not make code unnecessarily complicated.

Part of what lead to that implementation is that I wanted to preserve
the current behavior of how the name instantly changes if you change
buffers or windows when you decline to manually name the tab. I
personally feel that not doing so is not a good user experience - it
makes it too easy for the tab name not to reflect the contents without
it being the fault of the user. That's what I'm worried about here. I
don't think that the automatic naming should go away, just that it
should peacefully co-exist with the user or Lisp programs wanting to
name a tab just so.

Other than that, I'm happy to wait a little bit to get the best possible
implementation for the benefit of everyone. Thanks for your attention
and encouragement on this. :)

Cheers,
--
~Robert Cochran

GPG Fingerprint - BD0C 5F8B 381C 64F0 F3CE  E7B9 EC9A 872C 41B2 77C2

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
>> But please give me an additional day to think about a possibility of
>> avoiding `no-auto-name` to not make code unnecessarily complicated.
> [...]
> Other than that, I'm happy to wait a little bit to get the best possible
> implementation for the benefit of everyone. Thanks for your attention
> and encouragement on this. :)

Meanwhile I looked at prior art of how this feature in already implemented
in Emacs.  I think we should avoid needlessly introducing new concepts,
but instead use the existing solutions to reduce entropy and improve
maintainability of code.  Tabs were implemented to represent frame-like
window configurations inside one frame, so tab renaming could work like
frame renaming where M-x set-frame-name reads a new name and sets the
frame parameter `name`.  What it also does is to set additional parameter
`explicit-name`.  Please use the same parameter name in tabs to not
divert too much from frame name handling.

What we could do is to improve both implementations, e.g. neither
set-frame-name nor your patch provide a default value, but it would
be useful to be able to type M-n in the renaming minibuffer to
bring the current name for editing.

Also I don't see a need to add `(explicit-name . nil)` by default.
It seems it should be enough to add only `(explicit-name . t)`
after manual renaming.  But maybe prefilling all possible parameters
initially really simplifies implementation?

Finally what needs to be improved is to make tab-bar--tab and
tab-bar--current-tab consistent.  In your patch tab-bar--tab
gets current-tab directly from parameters, but tab-bar--current-tab
accepts a tab from its argument.  Shouldn't tab-bar--tab also
accept the current tab from its argument?

In other regards your choice of a command name `tab-bar-rename-tab-by-name`
fits nicely into naming convention with the existing `select-frame-by-name`.
We also have `tab-bar-close-tab-by-name`.  There is also the command
`tab-bar-switch-to-tab` that selects a tab by name, it was named after
`switch-to-buffer`, maybe better name would be `tab-bar-select-tab-by-name`?

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
> Hi all,

>
> Another day, another patch :)
>
>>>> But please give me an additional day to think about a possibility of
>>>> avoiding `no-auto-name` to not make code unnecessarily complicated.
>>> [...]
>>> Other than that, I'm happy to wait a little bit to get the best possible
>>> implementation for the benefit of everyone. Thanks for your attention
>>> and encouragement on this. :)
>>
>> Meanwhile I looked at prior art of how this feature in already implemented
>> in Emacs.  I think we should avoid needlessly introducing new concepts,
>> but instead use the existing solutions to reduce entropy and improve
>> maintainability of code.  Tabs were implemented to represent frame-like
>> window configurations inside one frame, so tab renaming could work like
>> frame renaming where M-x set-frame-name reads a new name and sets the
>> frame parameter `name`.  What it also does is to set additional parameter
>> `explicit-name`.  Please use the same parameter name in tabs to not
>> divert too much from frame name handling.
>
> Done. All instances of 'no-auto-name' changed to 'explicit-name'. That's
> honestly a much better name, and being consistent with frames is all the
> better. Thanks for the guidance on that.
Thanks for renaming.

>> What we could do is to improve both implementations, e.g. neither
>> set-frame-name nor your patch provide a default value, but it would
>> be useful to be able to type M-n in the renaming minibuffer to
>> bring the current name for editing.
>
> I'll look into making this happen in a different patch.

Right, this will simplify handling changes.

>> Also I don't see a need to add `(explicit-name . nil)` by default.
>> It seems it should be enough to add only `(explicit-name . t)`
>> after manual renaming.  But maybe prefilling all possible parameters
>> initially really simplifies implementation?
>
> I think that it simplifies implementation - no having to unstitch and
> restitch parameters, just do a couple of assqs. New frames get
> `(explicit-name . nil)` regardless, so I figure we should follow suit.

Yes, frames have `(explicit-name . nil)` for a reason.

>> Finally what needs to be improved is to make tab-bar--tab and
>> tab-bar--current-tab consistent.  In your patch tab-bar--tab
>> gets current-tab directly from parameters, but tab-bar--current-tab
>> accepts a tab from its argument.  Shouldn't tab-bar--tab also
>> accept the current tab from its argument?
>
> I'm going to argue no, and my reasoning is that tab-bar--tab is only
> ever called to convert an 'incomplete' current-tab alist into a full tab
> alist. IOW, we don't need to explicitly provide the context of which tab
> we're going to be using in this case - it will always whatever the
> current tab is. tab-bar--current-tab doesn't even need the context for
> most calls: of the 3 calls to it, only the one in the tab switching
> function provides context, the others take the implicit default of the
> current default tab.
I agree.

>> In other regards your choice of a command name `tab-bar-rename-tab-by-name`
>> fits nicely into naming convention with the existing `select-frame-by-name`.
>> We also have `tab-bar-close-tab-by-name`.  There is also the command
>> `tab-bar-switch-to-tab` that selects a tab by name, it was named after
>> `switch-to-buffer`, maybe better name would be
>> `tab-bar-select-tab-by-name`?
>
> I have no strong naming preference myself.

Maybe we should add an alias `tab-bar-select-tab-by-name`
to `tab-bar-switch-to-tab`.

> I also went ahead and added `C-x 6 r` to the keymap, as well as
> documented both it and `tab-bar-tab-name-function` in the manual.

Thanks, now your patch looks ok to push.

> Something else I would like input on - if you try to close the only tab
> in the frame, then it loses its explicit name if it has one. This is
> because the tab closing function blindly deletes the entry from the tabs
> alist, and hence the explicit-name attribute. What should we do? I think
> we need to signal user-error or similar in interactive contexts, but
> what about when calling from Lisp programs?

Indeed, signaling user-error when closing a single tab would be
the right thing even when called programmatically, because the caller
can check the number of tabs before calling tab-bar-close-tab.

> Thanks,
> --
> ~Robert Cochran
>
> GPG Fingerprint - BD0C 5F8B 381C 64F0 F3CE  E7B9 EC9A 872C 41B2 77C2


From d2b9eb3cbecf740191e33a9eb684671aff0fbbe9 Mon Sep 17 00:00:00 2001
From: Robert Cochran <[hidden email]>
Date: Mon, 7 Oct 2019 13:41:47 -0700
Subject: [PATCH] Allow tabs to have consistent given names

* lisp/tab-bar.el (tab-bar--tab): Pull automatic name information from
current tab
(tab-bar--current-tab): Pull automatic name information from current
tab, or from new optional template argument
(tab-bar-select-tab): Pass the target tab as a template when setting
it as current tab
(tab-bar-rename-tab, tab-bar-rename-tab-by-name): New functions
* doc/emacs/frames.texi (Tab Bars): Document new tab rename functionality.
---
 doc/emacs/frames.texi |  4 ++
 lisp/tab-bar.el       | 93 +++++++++++++++++++++++++++++++++----------
 2 files changed, 77 insertions(+), 20 deletions(-)

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 169eebab3e..5f64c7e8d5 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -1282,6 +1282,10 @@ Tab Bars
 @item C-x 6 d @var{directory} @key{RET}
 Select a Dired buffer for directory @var{directory} in another tab.
 This runs @code{dired-other-tab}.  @xref{Dired}.
+@item C-x 6 r @var{tabname} @key{RET}
+Renames the current tab to @var{tabname}.  You can control the
+programmatic name given to a tab by default by customizing the
+variable @code{tab-bar-tab-name-function}.
 @end table
 
 @vindex tab-bar-new-tab-choice
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index c4eba8600a..2e96072a15 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -304,9 +304,13 @@ tab-bar-make-keymap-1
   (let* ((separator (or tab-bar-separator (if window-system " " "|")))
          (i 0)
          (tabs (funcall tab-bar-tabs-function))
-         (current-tab-name (assq 'name (assq 'current-tab tabs))))
-    (when current-tab-name
-      (setf (cdr current-tab-name) (funcall tab-bar-tab-name-function)))
+         (current-tab-name (assq 'name (assq 'current-tab tabs)))
+         (current-tab-explicit-name (assq 'explicit-name (assq 'current-tab tabs))))
+    (when (and current-tab-name
+               current-tab-explicit-name
+               (not (cdr current-tab-explicit-name)))
+      (setf (cdr current-tab-name)
+            (funcall tab-bar-tab-name-function)))
     (append
      '(keymap (mouse-1 . tab-bar-handle-mouse))
      (mapcan
@@ -358,16 +362,29 @@ tab-bar-make-keymap-1
 
 
 (defun tab-bar--tab ()
-  `(tab
-    (name . ,(funcall tab-bar-tab-name-function))
-    (time . ,(time-convert nil 'integer))
-    (wc . ,(current-window-configuration))
-    (ws . ,(window-state-get
-            (frame-root-window (selected-frame)) 'writable))))
-
-(defun tab-bar--current-tab ()
-  `(current-tab
-    (name . ,(funcall tab-bar-tab-name-function))))
+  (let* ((tab (assq 'current-tab (frame-parameter nil 'tabs)))
+         (tab-explicit-name (cdr (assq 'explicit-name tab))))
+    `(tab
+      (name . ,(if tab-explicit-name
+                   (cdr (assq 'name tab))
+                 (funcall tab-bar-tab-name-function)))
+      (explicit-name . ,tab-explicit-name)
+      (time . ,(time-convert nil 'integer))
+      (wc . ,(current-window-configuration))
+      (ws . ,(window-state-get
+              (frame-root-window (selected-frame)) 'writable)))))
+
+(defun tab-bar--current-tab (&optional tab)
+  ;; `tab` here is an argument meaning 'use tab as template'. This is
+  ;; necessary when switching tabs, otherwise the destination tab
+  ;; inherit the current tab's `explicit-name` parameter.
+  (let* ((tab (or tab (assq 'current-tab (frame-parameter nil 'tabs))))
+         (tab-explicit-name (cdr (assq 'explicit-name tab))))
+    `(current-tab
+      (name . ,(if tab-explicit-name
+                   (cdr (assq 'name tab))
+                 (funcall tab-bar-tab-name-function)))
+      (explicit-name . ,tab-explicit-name))))
 
 (defun tab-bar--current-tab-index (&optional tabs)
   ;; FIXME: could be replaced with 1-liner using seq-position
@@ -436,7 +453,7 @@ tab-bar-select-tab
 
         (when from-index
           (setf (nth from-index tabs) from-tab))
-        (setf (nth to-index tabs) (tab-bar--current-tab)))
+        (setf (nth to-index tabs) (tab-bar--current-tab (nth to-index tabs))))
 
       (when tab-bar-mode
         (force-mode-line-update)))))
@@ -594,16 +611,51 @@ tab-bar-close-other-tabs
           (force-mode-line-update)
         (message "Deleted all other tabs")))))
 
+(defun tab-bar-rename-tab (name &optional arg)
+  "Rename the tab specified by its absolute position ARG.
+If no ARG is specified, then rename the current tab.
+ARG counts from 1.
+If NAME is the empty string, then use the automatic name
+function `tab-bar-tab-name-function'."
+  (interactive "sNew name for tab (leave blank for automatic naming): \nP")
+  (let* ((tabs (tab-bar-tabs))
+         (tab-index (if arg
+                        (1- (max 0 (min arg (length tabs))))
+                      (tab-bar--current-tab-index tabs)))
+         (tab-to-rename (nth tab-index tabs))
+         (tab-explicit-name (> (length name) 0))
+         (tab-new-name (if tab-explicit-name
+                           name
+                         (funcall tab-bar-tab-name-function))))
+    (setf (cdr (assq 'name tab-to-rename)) tab-new-name
+          (cdr (assq 'explicit-name tab-to-rename)) tab-explicit-name
+          (frame-parameter nil 'tabs) tabs)
+    (if (tab-bar-mode)
+        (force-mode-line-update)
+      (message "Renamed tab to '%s'" tab-new-name))))
+
+(defun tab-bar-rename-tab-by-name (tab-name new-name)
+  "Rename the tab named TAB-NAME.
+If NEW-NAME is the empty string, then use the automatic name
+function `tab-bar-tab-name-function'."
+  (interactive (list (completing-read "Rename tab by name: "
+                                      (mapcar (lambda (tab)
+                                                (cdr (assq 'name tab)))
+                                              (tab-bar-tabs)))
+                     (read-from-minibuffer "New name for tab (leave blank for automatic naming): ")))
+  (tab-bar-rename-tab new-name (tab-bar--tab-index-by-name tab-name)))
+
 
 ;;; Short aliases
 
-(defalias 'tab-new         'tab-bar-new-tab)
-(defalias 'tab-close       'tab-bar-close-tab)
+(defalias 'tab-new      'tab-bar-new-tab)
+(defalias 'tab-close    'tab-bar-close-tab)
 (defalias 'tab-close-other 'tab-bar-close-other-tabs)
-(defalias 'tab-select      'tab-bar-select-tab)
-(defalias 'tab-next        'tab-bar-switch-to-next-tab)
-(defalias 'tab-previous    'tab-bar-switch-to-prev-tab)
-(defalias 'tab-list        'tab-bar-list)
+(defalias 'tab-select   'tab-bar-select-tab)
+(defalias 'tab-next     'tab-bar-switch-to-next-tab)
+(defalias 'tab-previous 'tab-bar-switch-to-prev-tab)
+(defalias 'tab-rename   'tab-bar-rename-tab)
+(defalias 'tab-list     'tab-bar-list)
 
 
 ;;; Non-graphical access to frame-local tabs (named window configurations)
@@ -860,6 +912,7 @@ ctl-x-6-map
 (define-key ctl-x-6-map "b" 'switch-to-buffer-other-tab)
 (define-key ctl-x-6-map "f" 'find-file-other-tab)
 (define-key ctl-x-6-map "\C-f" 'find-file-other-tab)
+(define-key ctl-x-6-map "r" 'tab-rename)
 
 
 (provide 'tab-bar)
--
2.21.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
>> I also went ahead and added `C-x 6 r` to the keymap, as well as
>> documented both it and `tab-bar-tab-name-function` in the manual.
>
> Thanks, now your patch looks ok to push.

Now pushed to master, thanks for working on it.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
In reply to this post by Juri Linkov-2
>> Something else I would like input on - if you try to close the only tab
>> in the frame, then it loses its explicit name if it has one. This is
>> because the tab closing function blindly deletes the entry from the tabs
>> alist, and hence the explicit-name attribute. What should we do? I think
>> we need to signal user-error or similar in interactive contexts, but
>> what about when calling from Lisp programs?
>
> Indeed, signaling user-error when closing a single tab would be
> the right thing even when called programmatically, because the caller
> can check the number of tabs before calling tab-bar-close-tab.

Actually web browsers allow closing the last tab, so we should
not prohibit closing too.  What they do after closing, varies:
some close the whole application after closing the last tab -
doing the same in Emacs makes no sense.  Then some of them show
the default page as in the new tab - and this is what we could do.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

T.V Raman
For emacs usage, I'd suggest that 1 tab == the baseline --- 0 tabs
mostly is equivalent to tab-bar not existing.
--

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
> For emacs usage, I'd suggest that 1 tab == the baseline --- 0 tabs
> mostly is equivalent to tab-bar not existing.

This seems the right thing to do.  So closing the last tab
will disable tab-bar-mode.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Robert Cochran
Juri Linkov <[hidden email]> writes:

>> For emacs usage, I'd suggest that 1 tab == the baseline --- 0 tabs
>> mostly is equivalent to tab-bar not existing.
>
> This seems the right thing to do.  So closing the last tab
> will disable tab-bar-mode.

I personally am not fond of this behavior. That is not what I would
expect the button to do, personally. If I was a new user that didn't
know any better, that behavior would be very surprising and confusing, I
think. Plus that makes it a little too easy for a fiddly laptop trackpad
or some other not-super-accurate pointing device to drift over the
'close' button when I was actually trying to aim for the 'new tab'
button.

Honestly, it really seems like we have at least 3 different alternatives
that sound like they could be The Right Thing:

A) Do nothing, as we currently do, but implement a fix to prevent from
trashing the explicit-name property of the tab (I suggest signalling
user-error and bailing out early, as previously mentioned).

B) Close the whole frame, as one usually expects out of a web browser
these days.

C) Disable tab-bar-mode

My personal opinion at this point is that we should offer all 3 as
customize options, as well as provide a 4th option that is 'provide a
function that takes the tab as an argument, and handle it however you
want to handle it'. Something like:

#+BEGIN_SRC elisp
(defcustom tab-bar-close-tab-choice nil
  "Defines what to show in a new tab.
If nil, do not close the tab.
If close-frame, close the entire containing frame, as a web
browser would do.
If disable-tab-bar, turn off 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 the argument."
  :type '(choice (const    :tag "Do nothing" nil)
                 (const    :tag "Close frame" 'close-frame)
                 (const    :tag "Disable tab-bar-mode" 'disable-tab-bar)
                 (function :tag "Function"))
  :group 'tab-bar
  :version "27.1")
#+END_SRC

And then we can go from there. If that sounds like a workable solution,
then I'll provide a patch in the next few days that implements the
defcustom and all the appropriate behavior.

--
~Robert Cochran

GPG Fingerprint - BD0C 5F8B 381C 64F0 F3CE  E7B9 EC9A 872C 41B2 77C2

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
>>> For emacs usage, I'd suggest that 1 tab == the baseline --- 0 tabs
>>> mostly is equivalent to tab-bar not existing.
>>
>> This seems the right thing to do.  So closing the last tab
>> will disable tab-bar-mode.
>
> I personally am not fond of this behavior. That is not what I would
> expect the button to do, personally. If I was a new user that didn't
> know any better, that behavior would be very surprising and confusing, I
> think. Plus that makes it a little too easy for a fiddly laptop trackpad
> or some other not-super-accurate pointing device to drift over the
> 'close' button when I was actually trying to aim for the 'new tab'
> button.
>
> Honestly, it really seems like we have at least 3 different alternatives
> that sound like they could be The Right Thing:
>
> A) Do nothing, as we currently do, but implement a fix to prevent from
> trashing the explicit-name property of the tab (I suggest signalling
> user-error and bailing out early, as previously mentioned).

Both 'C-x 0' and 'C-x 5 0' signal user-error on closing the last
window/frame with:

  Attempt to delete minibuffer or sole ordinary window
  Attempt to delete the sole visible or iconified frame

so the same would make sense for tabs as well.

> B) Close the whole frame, as one usually expects out of a web browser
> these days.

Sometimes this behavior is annoying when the last tab is closed
accidentally.  Some browsers allow to disable such auto-closing,
so after accidentally closing the last tab it's possible to undo
closing (in Emacs tab closing undo is implemented now as well).

> C) Disable tab-bar-mode

While implementing tab closing undo, I added disabling tab-bar-mode
because it was easier to just add this line:

               (or (<= (length tabs) 1) ; closed the last tab

But please remove this from the default behavior because
I noticed that it disables tab-bar on all frames, whereas
it would make more sense to disable tab-bar only on the
selected frame.

> My personal opinion at this point is that we should offer all 3 as
> customize options, as well as provide a 4th option that is 'provide a
> function that takes the tab as an argument, and handle it however you
> want to handle it'. Something like:

I agree.

> #+BEGIN_SRC elisp
> (defcustom tab-bar-close-tab-choice nil
>   "Defines what to show in a new tab.
> If nil, do not close the tab.
> If close-frame, close the entire containing frame, as a web
> browser would do.
> If disable-tab-bar, turn off 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 the argument."
>   :type '(choice (const    :tag "Do nothing" nil)
>                  (const    :tag "Close frame" 'close-frame)
>                  (const    :tag "Disable tab-bar-mode" 'disable-tab-bar)
>                  (function :tag "Function"))
>   :group 'tab-bar
>   :version "27.1")
> #+END_SRC
>
> And then we can go from there. If that sounds like a workable solution,
> then I'll provide a patch in the next few days that implements the
> defcustom and all the appropriate behavior.

Please implement this defcustom (with the nil default value) because
we need to improve the current logic of closing the last tab (maybe
the name should be tab-bar-close-last-tab-choice to suggest that
it applies to closing only the last tab, not to every tab close).

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Kalman Reti-2
In reply to this post by Robert Cochran-2
ooak

On Wed, Oct 9, 2019 at 11:48 AM Robert Cochran <[hidden email]> wrote:
Hi emacs-devel,

I saw news recently of the new tabs that are on master. They're really
nifty - kudos to Juri Linkov for doing a lot of work on them. :)

I was admittedly a little disappointed, however, to see that the user, or
other Lisp programs, couldn't change the name of a tab persistently - it
*could* be changed, but a lot of the functions that handle tabs
immediately call the automatic naming function, before the UI could even
update to display it. Some applications might want to have a consistent
name divorced from the current buffer, and sometimes it would be nice to
override the automatic name on a per-tab basis as a user.

The solution I went with was another value in the tabs frame-parameter
alist. A new cons with the name `no-auto-name` in the car is used. If
the cdr is nil, then the behavior we have now remains - the tab handling
functions will call the value of `tab-bar-tab-name-function` and update
the name immediately. With a non-nil value, any time
`tab-bar-tab-name-function` would be called, the existing name is
instead substituted.

I've added 2 new functions, `tab-bar-rename-tab` and
`tab-bar-rename-tab-by-name`. Both functions take a new name, and a tag
identifier, either a frame tab index or an existing name,
respectively. The new name is then set on the tab, and the
`no-auto-name` parameter is set non-nil, unless the new name is the
empty string, which is taken to mean 'turn automatic naming back on'.

A couple of things I'm still wondering about: should this be documented
in the manual? I was going to do so, but couldn't really find a good
spot to mention it. If we do add something to the manual, we should
mention `tab-bar-tab-name-function` as well. Do we want to add this to
the default `C-x 6` binds, possibly as `C-x 6 r`? I already set
`tab-rename` as an alias to `tab-bar-rename-tab`, but I'm curious what
other people are thinking on that. Is there a better name for
`no-auto-name`? I couldn't think of a better one... I was aiming to have
a name who's interpretation as 'nil' is 'don't do anything differently',
so as to make the code slightly easier to read, as well as ensuring
saved tabs don't get automatic naming turned on by mistake.

Thanks,
--
~Robert Cochran

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Robert Cochran
In reply to this post by Juri Linkov-2
Hi all,

Juri Linkov <[hidden email]> writes:

>> C) Disable tab-bar-mode
>
> While implementing tab closing undo, I added disabling tab-bar-mode
> because it was easier to just add this line:
>
>                (or (<= (length tabs) 1) ; closed the last tab
>
> But please remove this from the default behavior because
> I noticed that it disables tab-bar on all frames, whereas
> it would make more sense to disable tab-bar only on the
> selected frame.
Sorry, I didn't quite understand what you wanted me to do there, so I
didn't try to address it.

>> #+BEGIN_SRC elisp
>> (defcustom tab-bar-close-tab-choice nil
>>   "Defines what to show in a new tab.
>> If nil, do not close the tab.
>> If close-frame, close the entire containing frame, as a web
>> browser would do.
>> If disable-tab-bar, turn off 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 the argument."
>>   :type '(choice (const    :tag "Do nothing" nil)
>>                  (const    :tag "Close frame" 'close-frame)
>>                  (const    :tag "Disable tab-bar-mode" 'disable-tab-bar)
>>                  (function :tag "Function"))
>>   :group 'tab-bar
>>   :version "27.1")
>> #+END_SRC
>>
>> And then we can go from there. If that sounds like a workable solution,
>> then I'll provide a patch in the next few days that implements the
>> defcustom and all the appropriate behavior.
>
> Please implement this defcustom (with the nil default value) because
> we need to improve the current logic of closing the last tab (maybe
> the name should be tab-bar-close-last-tab-choice to suggest that
> it applies to closing only the last tab, not to every tab close).
Implemented in the attached patch. Please let me know what you all
think.

It occurred to me in the process of writing this up that it might be
useful to provide hook variables for creating and closing tabs -
'tab-bar-tab-open-hook' and 'tab-bar-tab-close-hook' perhaps? Standard
fare on those - a list of functions that take the tab as an argument,
probably called as the last task of tab creation and the first task of
tab closing? Thoughts?

Thanks,
--
~Robert Cochran


From 81666f09d51aaa36e7d20ee5e1e038fe22feca0a Mon Sep 17 00:00:00 2001
From: Robert Cochran <[hidden email]>
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 | 71 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 49 insertions(+), 22 deletions(-)

diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 8350b4e694..5c64386f55 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -613,6 +613,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
@@ -627,29 +640,43 @@ tab-bar-close-tab
          (current-index (tab-bar--current-tab-index tabs))
          (close-index (if (integerp arg) (1- arg) current-index)))
 
-    ;; 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))))
-
-    (set-frame-parameter nil 'tabs (delq (nth close-index tabs) tabs))
-
-    (when (and tab-bar-mode
-               (and (natnump tab-bar-show)
-                    (<= (length tabs) tab-bar-show)))
-      (tab-bar-mode -1))
+    (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
+      ;; 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))))
+
+      (set-frame-parameter nil 'tabs (delq (nth close-index tabs) tabs))
 
-    (force-mode-line-update)
-    (unless tab-bar-mode
-      (message "Deleted tab and switched to %s" tab-bar-close-tab-select))))
+      (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)))))
 
 (defun tab-bar-close-tab-by-name (name)
   "Close the tab by NAME."
--
2.21.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Robert Cochran
Robert Cochran <[hidden email]> writes:

> Implemented in the attached patch. Please let me know what you all
> think.
>

Blah, failed to spot-check and pull master before hand. New patch has
been rebased on master, so no more merge errors. Sorry about that!

Thanks,
--
~Robert Cochran


From ffdb2ae377c71ef089f57f44b79dcff6ef8f2aa1 Mon Sep 17 00:00:00 2001
From: Robert Cochran <[hidden email]>
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

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
In reply to this post by Robert Cochran
>>> C) Disable tab-bar-mode
>>
>> While implementing tab closing undo, I added disabling tab-bar-mode
>> because it was easier to just add this line:
>>
>>                (or (<= (length tabs) 1) ; closed the last tab
>>
>> But please remove this from the default behavior because
>
> Sorry, I didn't quite understand what you wanted me to do there, so I
> didn't try to address it.

I see that you already resolved this after rebasing.  Thanks!
Now your patch is pushed to master without merge conflicts.

>> I noticed that it disables tab-bar on all frames, whereas
>> it would make more sense to disable tab-bar only on the
>> selected frame.

I meant we could have separate tab-bar-mode to disable it only
on the selected frame, and global-tab-bar-mode to disable it
globally on all frames.

> It occurred to me in the process of writing this up that it might be
> useful to provide hook variables for creating and closing tabs -
> 'tab-bar-tab-open-hook' and 'tab-bar-tab-close-hook' perhaps? Standard
> fare on those - a list of functions that take the tab as an argument,
> probably called as the last task of tab creation and the first task of
> tab closing? Thoughts?

Not sure if this could be a hook on tab-bar basic events,
or a customizable function.  Also not clear whether to call it
before or after the main body.

We need to collect more examples of use cases to decide
on the implementation.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
In reply to this post by Robert Cochran
> Honestly, it really seems like we have at least 3 different alternatives
> that sound like they could be The Right Thing:
>
> A) Do nothing, as we currently do, but implement a fix to prevent from
> trashing the explicit-name property of the tab (I suggest signalling
> user-error and bailing out early, as previously mentioned).
>
> B) Close the whole frame, as one usually expects out of a web browser
> these days.
>
> C) Disable tab-bar-mode

Do you think that closing the last tab could provide more options like
in web browsers, e.g. https://www.tabmixplus.org/support/viewtopic.php?t=3
i.e. showing the same content that is shown on a new tab.
I'm not sure if everything this is needed.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Robert Cochran
In reply to this post by Juri Linkov-2
Juri Linkov <[hidden email]> writes:

>> It occurred to me in the process of writing this up that it might be
>> useful to provide hook variables for creating and closing tabs -
>> 'tab-bar-tab-open-hook' and 'tab-bar-tab-close-hook' perhaps? Standard
>> fare on those - a list of functions that take the tab as an argument,
>> probably called as the last task of tab creation and the first task of
>> tab closing? Thoughts?
>
> Not sure if this could be a hook on tab-bar basic events,
> or a customizable function.  Also not clear whether to call it
> before or after the main body.
>
> We need to collect more examples of use cases to decide
> on the implementation.

I believe it better to be a hook personally, though admittedly that kind
of depends on how exactly you want to use the functionality. A hook
allows for several interested parties to be able to act on a tab
create/close instead of just one. This allows better for dynamically
adding or removing situationally dependent behavior. For example, maybe
I want to kill some/all of the buffers in the tab when I close it, but
only under certain circumstances, like if it's a tab containing non-file
'work' buffers like those of Magit or mpd. Another is if I open a new
tab, and I want to be prompted to name the tab automatically depending
on the buffers that exist at the time of creation - I have a tendency to
segregate all of my Magit buffers for a repository into a single tab,
and I usually rename the tab so that no matter what Magit sub-buffer I'm
on, the tab still has a consistent name. I can see myself doing similar
for other 'task-oriented' sets of windows and buffers such as gdb, mpd,
etc.

Either way, I suggest that we call any type of user-defined function on
tab creation at the end of the function body, and any type of
user-defined function on tab deletion at the beginning of the function
body. IMO there's nothing reasonable to do on tab creation until after
most of the work has been done already anyways, and that it's too late
to do anything on tab close except at the very beginning, when it's
still an open tab.

Thanks,
--
~Robert Cochran

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
> I believe it better to be a hook personally, though admittedly that kind
> of depends on how exactly you want to use the functionality. A hook
> allows for several interested parties to be able to act on a tab
> create/close instead of just one. This allows better for dynamically
> adding or removing situationally dependent behavior. For example, maybe
> I want to kill some/all of the buffers in the tab when I close it, but
> only under certain circumstances, like if it's a tab containing non-file
> 'work' buffers like those of Magit or mpd.

Maybe we need to add the prefix 'pre-' to indicate that the hook
is called before the command is executed, with a name e.g.:

  tab-bar-pre-close-tab-functions (tab)

This might require an additional utility function to get all buffers
from the tab (it could collect buffers by traversing readable window-state),
with a name:

  tab-bar-tab-buffers (tab)

Such function is also needed for checking if a buffer exists in a tab
to prevent killing a buffer in the current tab with C-x k
when such buffer is still shown in some other tab.

> Another is if I open a new tab, and I want to be prompted to name the
> tab automatically depending on the buffers that exist at the time of
> creation - I have a tendency to segregate all of my Magit buffers for
> a repository into a single tab, and I usually rename the tab so that
> no matter what Magit sub-buffer I'm on, the tab still has a consistent
> name. I can see myself doing similar for other 'task-oriented' sets of
> windows and buffers such as gdb, mpd, etc.

This looks like calling after the tab is created, so maybe a name like

  tab-bar-post-new-tab-functions (tab)

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Enable persistent naming for tabs

Juri Linkov-2
>> Another is if I open a new tab, and I want to be prompted to name the
>> tab automatically depending on the buffers that exist at the time of
>> creation - I have a tendency to segregate all of my Magit buffers for
>> a repository into a single tab, and I usually rename the tab so that
>> no matter what Magit sub-buffer I'm on, the tab still has a consistent
>> name. I can see myself doing similar for other 'task-oriented' sets of
>> windows and buffers such as gdb, mpd, etc.
>
> This looks like calling after the tab is created, so maybe a name like
>
>   tab-bar-post-new-tab-functions (tab)

I just realized we already have tab-bar-new-tab-choice.
Does it serve the same purpose?

Then what is still missing is tab-bar-close-tab-choice,
that is like tab-bar-close-last-tab-choice you added recently,
but could run a hook-like function on closing any tab.

12