* Re: [PATCH] Enable persistent naming for tabs
@ 2019-10-10 1:03 Robert Cochran
2019-10-10 21:43 ` Juri Linkov
0 siblings, 1 reply; 24+ messages in thread
From: Robert Cochran @ 2019-10-10 1:03 UTC (permalink / raw)
To: juri; +Cc: emacs-devel
[[ 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
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-10 1:03 [PATCH] Enable persistent naming for tabs Robert Cochran @ 2019-10-10 21:43 ` Juri Linkov [not found] ` <87ftjz6v4d.fsf@cochranmail.com> 0 siblings, 1 reply; 24+ messages in thread From: Juri Linkov @ 2019-10-10 21:43 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel >> 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`? ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <87ftjz6v4d.fsf@cochranmail.com>]
* Re: [PATCH] Enable persistent naming for tabs [not found] ` <87ftjz6v4d.fsf@cochranmail.com> @ 2019-10-13 19:53 ` Juri Linkov 2019-10-15 21:45 ` Juri Linkov 2019-10-20 16:17 ` Juri Linkov 0 siblings, 2 replies; 24+ messages in thread From: Juri Linkov @ 2019-10-13 19:53 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 4396 bytes --] > 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 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: Allow tabs to have explicit names, revision 2 --] [-- Type: text/x-patch, Size: 7164 bytes --] From d2b9eb3cbecf740191e33a9eb684671aff0fbbe9 Mon Sep 17 00:00:00 2001 From: Robert Cochran <robert-git@cochranmail.com> 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 \f (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))) + \f ;;; 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) \f ;;; 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) \f (provide 'tab-bar) -- 2.21.0 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-13 19:53 ` Juri Linkov @ 2019-10-15 21:45 ` Juri Linkov 2019-10-20 16:17 ` Juri Linkov 1 sibling, 0 replies; 24+ messages in thread From: Juri Linkov @ 2019-10-15 21:45 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel >> 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. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-13 19:53 ` Juri Linkov 2019-10-15 21:45 ` Juri Linkov @ 2019-10-20 16:17 ` Juri Linkov 2019-10-20 23:54 ` T.V Raman 1 sibling, 1 reply; 24+ messages in thread From: Juri Linkov @ 2019-10-20 16:17 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel >> 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. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-20 16:17 ` Juri Linkov @ 2019-10-20 23:54 ` T.V Raman 2019-10-21 21:34 ` Juri Linkov 0 siblings, 1 reply; 24+ messages in thread From: T.V Raman @ 2019-10-20 23:54 UTC (permalink / raw) To: Juri Linkov; +Cc: Robert Cochran, emacs-devel For emacs usage, I'd suggest that 1 tab == the baseline --- 0 tabs mostly is equivalent to tab-bar not existing. -- ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-20 23:54 ` T.V Raman @ 2019-10-21 21:34 ` Juri Linkov 2019-10-23 16:22 ` Robert Cochran 0 siblings, 1 reply; 24+ messages in thread From: Juri Linkov @ 2019-10-21 21:34 UTC (permalink / raw) To: T.V Raman; +Cc: Robert Cochran, emacs-devel > 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. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-21 21:34 ` Juri Linkov @ 2019-10-23 16:22 ` Robert Cochran 2019-10-23 20:41 ` Juri Linkov 2019-10-27 23:10 ` Juri Linkov 0 siblings, 2 replies; 24+ messages in thread From: Robert Cochran @ 2019-10-23 16:22 UTC (permalink / raw) To: Juri Linkov; +Cc: emacs-devel, T.V Raman Juri Linkov <juri@linkov.net> 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 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-23 16:22 ` Robert Cochran @ 2019-10-23 20:41 ` Juri Linkov 2019-10-25 15:47 ` Robert Cochran 2019-10-27 23:10 ` Juri Linkov 1 sibling, 1 reply; 24+ messages in thread From: Juri Linkov @ 2019-10-23 20:41 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel, T.V Raman >>> 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). ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-23 20:41 ` Juri Linkov @ 2019-10-25 15:47 ` Robert Cochran 2019-10-25 16:01 ` Robert Cochran 2019-10-26 21:46 ` Juri Linkov 0 siblings, 2 replies; 24+ messages in thread From: Robert Cochran @ 2019-10-25 15:47 UTC (permalink / raw) To: Juri Linkov; +Cc: emacs-devel, Robert Cochran, T.V Raman [-- Attachment #1: Type: text/plain, Size: 2208 bytes --] Hi all, Juri Linkov <juri@linkov.net> 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 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: Patch to add tab-bar-close-last-tab-choice --] [-- Type: text/x-patch, Size: 4626 bytes --] From 81666f09d51aaa36e7d20ee5e1e038fe22feca0a Mon Sep 17 00:00:00 2001 From: Robert Cochran <robert-git@cochranmail.com> 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 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-25 15:47 ` Robert Cochran @ 2019-10-25 16:01 ` Robert Cochran 2019-11-03 22:08 ` Robert Cochran 2019-10-26 21:46 ` Juri Linkov 1 sibling, 1 reply; 24+ messages in thread From: Robert Cochran @ 2019-10-25 16:01 UTC (permalink / raw) To: Robert Cochran; +Cc: T.V Raman, emacs-devel, Juri Linkov [-- Attachment #1: Type: text/plain, Size: 303 bytes --] Robert Cochran <robert-emacs@cochranmail.com> 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 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: Patch to add tab-bar-close-last-tab-choice --] [-- Type: text/x-patch, Size: 5284 bytes --] From ffdb2ae377c71ef089f57f44b79dcff6ef8f2aa1 Mon Sep 17 00:00:00 2001 From: Robert Cochran <robert-git@cochranmail.com> 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 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-25 16:01 ` Robert Cochran @ 2019-11-03 22:08 ` Robert Cochran 2019-11-03 22:37 ` Juri Linkov 0 siblings, 1 reply; 24+ messages in thread From: Robert Cochran @ 2019-11-03 22:08 UTC (permalink / raw) To: Robert Cochran; +Cc: T.V Raman, emacs-devel, Juri Linkov Robert Cochran <robert-emacs@cochranmail.com> writes: > Robert Cochran <robert-emacs@cochranmail.com> 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! > Looks like this patch is still hanging in the air... did we want to wait on this until after we decided that we want post-open and pre-close hooks, or do we want to do something with this regardless? I still think that the hooks/function list and this feature (close-last-tab-choice) are complimentary and should both be implemented. Thanks, -- ~Robert Cochran GPG Fingerprint - BD0C 5F8B 381C 64F0 F3CE E7B9 EC9A 872C 41B2 77C2 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-11-03 22:08 ` Robert Cochran @ 2019-11-03 22:37 ` Juri Linkov 0 siblings, 0 replies; 24+ messages in thread From: Juri Linkov @ 2019-11-03 22:37 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel, T.V Raman >>> 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! > > Looks like this patch is still hanging in the air... did we want to wait > on this until after we decided that we want post-open and pre-close > hooks, or do we want to do something with this regardless? > > I still think that the hooks/function list and this feature > (close-last-tab-choice) are complimentary and should both be > implemented. I don't know where you are looking (maybe in some Emacs mirror?), but your patch was already pushed a week ago. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-25 15:47 ` Robert Cochran 2019-10-25 16:01 ` Robert Cochran @ 2019-10-26 21:46 ` Juri Linkov 2019-10-30 18:35 ` Robert Cochran 1 sibling, 1 reply; 24+ messages in thread From: Juri Linkov @ 2019-10-26 21:46 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel, T.V Raman >>> 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. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-26 21:46 ` Juri Linkov @ 2019-10-30 18:35 ` Robert Cochran 2019-10-30 21:52 ` Juri Linkov 0 siblings, 1 reply; 24+ messages in thread From: Robert Cochran @ 2019-10-30 18:35 UTC (permalink / raw) To: Juri Linkov; +Cc: emacs-devel, T.V Raman Juri Linkov <juri@linkov.net> 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 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-30 18:35 ` Robert Cochran @ 2019-10-30 21:52 ` Juri Linkov 2019-10-30 23:05 ` Juri Linkov 0 siblings, 1 reply; 24+ messages in thread From: Juri Linkov @ 2019-10-30 21:52 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel, T.V Raman > 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) ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-30 21:52 ` Juri Linkov @ 2019-10-30 23:05 ` Juri Linkov 2019-10-31 1:50 ` Robert Cochran 0 siblings, 1 reply; 24+ messages in thread From: Juri Linkov @ 2019-10-30 23:05 UTC (permalink / raw) To: Robert Cochran; +Cc: T.V Raman, emacs-devel >> 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. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-30 23:05 ` Juri Linkov @ 2019-10-31 1:50 ` Robert Cochran 2019-10-31 21:17 ` Juri Linkov 0 siblings, 1 reply; 24+ messages in thread From: Robert Cochran @ 2019-10-31 1:50 UTC (permalink / raw) To: Juri Linkov; +Cc: T.V Raman, emacs-devel Juri Linkov <juri@linkov.net> writes: >>> 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? I don't think so. The function is supposed to return a buffer that is used as the starting buffer for the tab. That precludes doing any sort of manipulation of windows, buffers, and tab names. The function doesn't have lexical access to the tab variable in any way, either. [ From the other message ] >> 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) That name sounds fine by me, perhaps though 'hook' instead of 'functions'. And this is kind of going off into the weeds for a little bit, but maybe we can have an additional argument that indicates whether or not it's the last tab? I know that seems to overlap a little bit with last-tab-choice, but my goal is to try and work in as much mechanism as possible so that the user has plenty of freedom to have things behave exactly as they want. Seems to be in the spirit of Emacs. :) We could also use the return value to see if we should actually close the tab or not (ie if *any* of the tabs return a particular value, nil for the sake of argument, then the tab closing function will bail out early and not close the tab)? I could see this second thing being useful for programmatically 'protecting' a 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. Having such a function could prove useful, yes. I'm not sure we should prevent killing a buffer if it's visible in another tab though. There's nothing stopping you from killing a buffer visible in another frame or another window, at least by default. >> 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) This name also sounds fine, with the same comment about possibly naming with 'hook' instead of 'functions'. Thanks, -- ~Robert Cochran GPG Fingerprint - BD0C 5F8B 381C 64F0 F3CE E7B9 EC9A 872C 41B2 77C2 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-31 1:50 ` Robert Cochran @ 2019-10-31 21:17 ` Juri Linkov 0 siblings, 0 replies; 24+ messages in thread From: Juri Linkov @ 2019-10-31 21:17 UTC (permalink / raw) To: Robert Cochran; +Cc: T.V Raman, emacs-devel >>> 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? > > I don't think so. The function is supposed to return a buffer that is > used as the starting buffer for the tab. That precludes doing any sort > of manipulation of windows, buffers, Manipulation of windows and buffers is possible in a function customized for tab-bar-new-tab-choice. Such function could return (current-buffer) or any other non-buffer value to avoid switch-to-buffer. > and tab names. The function doesn't have lexical access to the tab > variable in any way, either. Modification of tab names is not possible with tab-bar-new-tab-choice indeed. OTOH, naming the tab according to buffers in it is also possible by customizing tab-bar-tab-name-function. However, I'm not sure about prompting for a new name in it. So maybe a new hook is needed after all. >>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) > > That name sounds fine by me, perhaps though 'hook' instead of > 'functions'. I like 'hook' more too because it is shorter than 'functions', but I'm not sure about the current naming convention such as (info "(elisp) Tips for Defining") > And this is kind of going off into the weeds for a little > bit, but maybe we can have an additional argument that indicates whether > or not it's the last tab? I know that seems to overlap a little bit with > last-tab-choice, but my goal is to try and work in as much mechanism as > possible so that the user has plenty of freedom to have things behave > exactly as they want. Seems to be in the spirit of Emacs. :) Right, let's add all additional information. > We could also use the return value to see if we should actually close > the tab or not (ie if *any* of the tabs return a particular value, nil > for the sake of argument, then the tab closing function will bail out > early and not close the tab)? I could see this second thing being useful > for programmatically 'protecting' a tab. Protected tabs is a useful feature in some web browsers/addons. Also there are locked tabs that are more like dedicated windows e.g. https://www.tabmixplus.org/support/viewpage.php?t=3&p=frozen_tabs >>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. > > Having such a function could prove useful, yes. I'm not sure we should > prevent killing a buffer if it's visible in another tab though. There's > nothing stopping you from killing a buffer visible in another frame or > another window, at least by default. No by default, of course. Only as an option. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-23 16:22 ` Robert Cochran 2019-10-23 20:41 ` Juri Linkov @ 2019-10-27 23:10 ` Juri Linkov 1 sibling, 0 replies; 24+ messages in thread From: Juri Linkov @ 2019-10-27 23:10 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel, T.V Raman > 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. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH] Enable persistent naming for tabs @ 2019-10-08 22:26 Robert Cochran 2019-10-09 16:02 ` Eli Zaretskii ` (2 more replies) 0 siblings, 3 replies; 24+ messages in thread From: Robert Cochran @ 2019-10-08 22:26 UTC (permalink / raw) To: emacs-devel [-- Attachment #1: Type: text/plain, Size: 2231 bytes --] 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 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: Patch to allow consistent names for tab-bar tabs --] [-- Type: text/x-patch, Size: 5673 bytes --] From 59126587d419b5f57c79a970919894f6e91b5c91 Mon Sep 17 00:00:00 2001 From: Robert Cochran <robert-git@cochranmail.com> 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 \f (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))) + \f ;;; 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) \f -- 2.21.0 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-08 22:26 Robert Cochran @ 2019-10-09 16:02 ` Eli Zaretskii 2019-10-09 22:58 ` Juri Linkov 2019-10-23 20:53 ` Kalman Reti 2 siblings, 0 replies; 24+ messages in thread From: Eli Zaretskii @ 2019-10-09 16:02 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel > From: Robert Cochran <robert+Emacs@cochranmail.com> > 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. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-08 22:26 Robert Cochran 2019-10-09 16:02 ` Eli Zaretskii @ 2019-10-09 22:58 ` Juri Linkov 2019-10-23 20:53 ` Kalman Reti 2 siblings, 0 replies; 24+ messages in thread From: Juri Linkov @ 2019-10-09 22:58 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel > 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. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Enable persistent naming for tabs 2019-10-08 22:26 Robert Cochran 2019-10-09 16:02 ` Eli Zaretskii 2019-10-09 22:58 ` Juri Linkov @ 2019-10-23 20:53 ` Kalman Reti 2 siblings, 0 replies; 24+ messages in thread From: Kalman Reti @ 2019-10-23 20:53 UTC (permalink / raw) To: Robert Cochran; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 2405 bytes --] ooak On Wed, Oct 9, 2019 at 11:48 AM Robert Cochran <robert+Emacs@cochranmail.com> 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 > > [-- Attachment #2: Type: text/html, Size: 2901 bytes --] ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2019-11-03 22:37 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2019-10-10 1:03 [PATCH] Enable persistent naming for tabs Robert Cochran 2019-10-10 21:43 ` Juri Linkov [not found] ` <87ftjz6v4d.fsf@cochranmail.com> 2019-10-13 19:53 ` Juri Linkov 2019-10-15 21:45 ` Juri Linkov 2019-10-20 16:17 ` Juri Linkov 2019-10-20 23:54 ` T.V Raman 2019-10-21 21:34 ` Juri Linkov 2019-10-23 16:22 ` Robert Cochran 2019-10-23 20:41 ` Juri Linkov 2019-10-25 15:47 ` Robert Cochran 2019-10-25 16:01 ` Robert Cochran 2019-11-03 22:08 ` Robert Cochran 2019-11-03 22:37 ` Juri Linkov 2019-10-26 21:46 ` Juri Linkov 2019-10-30 18:35 ` Robert Cochran 2019-10-30 21:52 ` Juri Linkov 2019-10-30 23:05 ` Juri Linkov 2019-10-31 1:50 ` Robert Cochran 2019-10-31 21:17 ` Juri Linkov 2019-10-27 23:10 ` Juri Linkov -- strict thread matches above, loose matches on Subject: below -- 2019-10-08 22:26 Robert Cochran 2019-10-09 16:02 ` Eli Zaretskii 2019-10-09 22:58 ` Juri Linkov 2019-10-23 20:53 ` Kalman Reti
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).