From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Robert Cochran Newsgroups: gmane.emacs.devel Subject: [PATCH] Enable persistent naming for tabs Date: Tue, 08 Oct 2019 15:26:10 -0700 Message-ID: <87d0f66fi5.fsf@cochranmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="165778"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Oct 09 17:47:52 2019 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1iIEBs-000h0K-2x for ged-emacs-devel@m.gmane.org; Wed, 09 Oct 2019 17:47:52 +0200 Original-Received: from localhost ([::1]:51534 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iIEBp-0002Wo-NS for ged-emacs-devel@m.gmane.org; Wed, 09 Oct 2019 11:47:49 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:55028) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iHy1e-0004Lb-9D for emacs-devel@gnu.org; Tue, 08 Oct 2019 18:32:15 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iHy1c-0002Vl-Kj for emacs-devel@gnu.org; Tue, 08 Oct 2019 18:32:14 -0400 Original-Received: from mail.cochranmail.com ([64.140.150.170]:43138) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iHy1c-0002VT-BE for emacs-devel@gnu.org; Tue, 08 Oct 2019 18:32:12 -0400 Original-Received: from SoraLaptop (unknown [131.191.86.130]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.cochranmail.com (Postfix) with ESMTPSA id 7584F470 for ; Tue, 8 Oct 2019 15:26:14 -0700 (PDT) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 64.140.150.170 X-Mailman-Approved-At: Tue, 08 Oct 2019 21:50:43 -0400 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:240763 Archived-At: --=-=-= Content-Type: text/plain 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 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Allow-tabs-to-have-consistent-given-names.patch Content-Description: Patch to allow consistent names for tab-bar tabs >From 59126587d419b5f57c79a970919894f6e91b5c91 Mon Sep 17 00:00:00 2001 From: Robert Cochran 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 --=-=-=--