* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename @ 2023-04-02 17:37 Spencer Baugh 2023-04-02 17:57 ` Eli Zaretskii ` (3 more replies) 0 siblings, 4 replies; 40+ messages in thread From: Spencer Baugh @ 2023-04-02 17:37 UTC (permalink / raw) To: 62621 I have a lot of buffers visiting files with the same basename, in directory paths which have long meaningless numeric identifiers. This means that with uniquify, I get buffers named things like: foo<ahlai5Ei>, foo<IHoano7o>, foo<yoeWo3ae> This is not much better than foo<1>, foo<2>, foo<3> for me. What would be great is if uniquify could use things other than the filename when making unique buffer names. For example, project-name from project.el is something that *is* unique for these files, because of my custom project.el integration. Then I'd get something like: foo<proj-emacs>, foo<proj-vi>, foo<proj-nano> However, uniquify is currently not customizable in this way. Could we add support for including additional attributes into the things which uniquify will use? Then I could add project-name as one of those attributes in my configuration, and I'd be happy. I would be happy to implement this feature in uniquify myself, if this is an interesting feature for upstream. Or if you'd prefer some other approach, I'd be happy to hear it and I can implement it. In GNU Emacs 29.0.60 (build 3, x86_64-pc-linux-gnu, X toolkit, cairo version 1.15.12, Xaw scroll bars) of 2023-03-13 built on igm-qws-u22796a Repository revision: e759905d2e0828eac4c8164b09113b40f6899656 Repository branch: emacs-29 Windowing system distributor 'The X.Org Foundation', version 11.0.12011000 System Description: CentOS Linux 7 (Core) Configured using: 'configure --with-x-toolkit=lucid --with-modules --with-gif=ifavailable' Configured features: CAIRO DBUS FREETYPE GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG JSON LIBSELINUX LIBXML2 MODULES NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS X11 XDBE XIM XINPUT2 XPM LUCID ZLIB Important settings: value of $LANG: en_US.UTF-8 locale-coding-system: utf-8-unix ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-04-02 17:37 bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename Spencer Baugh @ 2023-04-02 17:57 ` Eli Zaretskii 2023-04-02 21:59 ` Drew Adams 2023-04-02 18:25 ` Juri Linkov ` (2 subsequent siblings) 3 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-04-02 17:57 UTC (permalink / raw) To: Spencer Baugh; +Cc: 62621 > From: Spencer Baugh <sbaugh@janestreet.com> > Date: Sun, 02 Apr 2023 13:37:36 -0400 > > > I have a lot of buffers visiting files with the same basename, in > directory paths which have long meaningless numeric identifiers. This > means that with uniquify, I get buffers named things like: > > foo<ahlai5Ei>, foo<IHoano7o>, foo<yoeWo3ae> > > This is not much better than foo<1>, foo<2>, foo<3> for me. > > What would be great is if uniquify could use things other than the > filename when making unique buffer names. > > For example, project-name from project.el is something that *is* > unique for these files, because of my custom project.el integration. > Then I'd get something like: > > foo<proj-emacs>, foo<proj-vi>, foo<proj-nano> > > However, uniquify is currently not customizable in this way. Could we > add support for including additional attributes into the things which > uniquify will use? Then I could add project-name as one of those > attributes in my configuration, and I'd be happy. > > I would be happy to implement this feature in uniquify myself, if this > is an interesting feature for upstream. Sounds like a useful feature indeed, provided that the customization will allow more or less arbitrary uniquification, not just by project names. Also, please keep in mind that a single project could have files named the same in different directories. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-04-02 17:57 ` Eli Zaretskii @ 2023-04-02 21:59 ` Drew Adams 0 siblings, 0 replies; 40+ messages in thread From: Drew Adams @ 2023-04-02 21:59 UTC (permalink / raw) To: Eli Zaretskii, Spencer Baugh; +Cc: 62621@debbugs.gnu.org > > However, uniquify is currently not customizable in this way. Could we > > add support for including additional attributes into the things which > > uniquify will use? Then I could add project-name as one of those > > attributes in my configuration, and I'd be happy. > > > > I would be happy to implement this feature in uniquify myself, if this > > is an interesting feature for upstream. > > Sounds like a useful feature indeed, provided that the customization > will allow more or less arbitrary uniquification, not just by project > names. Also, please keep in mind that a single project could have > files named the same in different directories. +1. _____ Off the top of my head (not thought through)... User-definable, e.g., based on some defcustom choice combinations; i.e., different name pieces that can contribute to the overall name. The current behavior of using the dir-name pieces could be one such choice, which could then be combined with other choices. `file-attributes' values (at least some of them) could also be candidates for such combinations. Or useful abbreviations of file-attribute values; e.g., use a relative last-<whatever> number instead of a full last-<whatver> value, to reflect just recency, not bothering about what the absolute values are. Ability to assign arbitrary labels (one or more "tags") to a given buffer would be good as another combining choice. In addition, as an alternative maybe a user-defined function value to compute the overall name. ____ Anyway, any enhancement at all that might be made wrt the naming would be welcome. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-04-02 17:37 bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename Spencer Baugh 2023-04-02 17:57 ` Eli Zaretskii @ 2023-04-02 18:25 ` Juri Linkov 2023-04-14 16:08 ` Spencer Baugh 2023-07-13 22:51 ` sbaugh 3 siblings, 0 replies; 40+ messages in thread From: Juri Linkov @ 2023-04-02 18:25 UTC (permalink / raw) To: Spencer Baugh; +Cc: 62621 > However, uniquify is currently not customizable in this way. Could we > add support for including additional attributes into the things which > uniquify will use? Then I could add project-name as one of those > attributes in my configuration, and I'd be happy. This was discussed recently in bug#59502, but I don't remember why the patch was never applied. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-04-02 17:37 bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename Spencer Baugh 2023-04-02 17:57 ` Eli Zaretskii 2023-04-02 18:25 ` Juri Linkov @ 2023-04-14 16:08 ` Spencer Baugh 2023-07-13 22:51 ` sbaugh 3 siblings, 0 replies; 40+ messages in thread From: Spencer Baugh @ 2023-04-14 16:08 UTC (permalink / raw) To: 62621 FWIW, here is the (unpolished) patch I'm currently using. This is correct but it's not what I think the final form of this should look like. For better or for worse, I have now Deeply Understood uniquify, and I have various ideas for things to do to fix bugs in it and simplify it and add new features... see bug#62732 for my first step. (Which adds tests, even!) After some of those, then I can do this bug. One sneak peak of a feature which I think I can manage to add with some improvements to uniquify.el: a user customization which causes a new behavior in read-buffer, so that when it's running on a subset of buffers (by passing PREDICATE), it reads buffer names which are only uniquified among that subset. (So the buffer names will be shorter when that doesn't cause ambiguity). This would be really cool for project-switch-to-buffer, so that if you have two projects working on the same source repo with the same files open, you don't have to see the extra uniquify cruft at the start of the buffer name when you just want to look at buffers in a single project. diff --git a/lisp/uniquify.el b/lisp/uniquify.el index dee9ecba2ea..53b39920820 100644 --- a/lisp/uniquify.el +++ b/lisp/uniquify.el @@ -210,8 +210,8 @@ uniquify-rationalize-file-buffer-names (with-current-buffer newbuf (setq uniquify-managed nil)) (when dirname (setq dirname (expand-file-name (directory-file-name dirname))) - (let ((fix-list (list (uniquify-make-item base dirname newbuf - nil dirname))) + (let ((fix-list (list (let ((dirname (uniquify-buffer-file-name newbuf dirname))) + (uniquify-make-item base dirname newbuf nil dirname)))) items) (dolist (buffer (buffer-list)) (when (and (not (and uniquify-ignore-buffers-re @@ -258,20 +258,26 @@ uniquify-rationalize-file-buffer-names (uniquify-rationalize fix-list)))) ;; uniquify's version of buffer-file-name; result never contains trailing slash -(defun uniquify-buffer-file-name (buffer) +(require 'project) +(defun uniquify-buffer-file-name (buffer &optional dirname) "Return name of directory, file BUFFER is visiting, or nil if none. Works on ordinary file-visiting buffers and buffers whose mode is mentioned in `uniquify-list-buffers-directory-modes', otherwise returns nil." (with-current-buffer buffer - (let ((filename - (or buffer-file-name - (if (memq major-mode uniquify-list-buffers-directory-modes) - list-buffers-directory)))) - (when filename - (directory-file-name - (file-name-directory - (expand-file-name - (directory-file-name filename)))))))) + (let* ((filename + (or buffer-file-name + (if (memq major-mode uniquify-list-buffers-directory-modes) + list-buffers-directory))) + (dir (or dirname + (directory-file-name + (file-name-directory + (expand-file-name + (directory-file-name filename))))))) + (if-let (pr (project-current nil dir)) + (let* ((pr-dir (project-root pr)) + (pr-rel (file-relative-name dir pr-dir))) + (file-name-concat pr-dir (project-name pr) pr-rel)) + dir)))) (defun uniquify-rerationalize-w/o-cb (fix-list) "Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'." ^ permalink raw reply related [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-04-02 17:37 bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename Spencer Baugh ` (2 preceding siblings ...) 2023-04-14 16:08 ` Spencer Baugh @ 2023-07-13 22:51 ` sbaugh 2023-07-14 6:29 ` Eli Zaretskii 3 siblings, 1 reply; 40+ messages in thread From: sbaugh @ 2023-07-13 22:51 UTC (permalink / raw) To: Spencer Baugh; +Cc: 62621 [-- Attachment #1: Type: text/plain, Size: 410 bytes --] OK, after resolving bug#62732, now at last my nice and short patch for this feature. I've thought quite a bit about how to make this configurable, and I think just letting people write their own arbitrary transformation functions, as I do in this patch, is what we should provide. Making things any more modular is fairly difficult. Packages can come along and provide other fancy functions if they like. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Support-transforming-the-dirname-used-by-uniquify.patch --] [-- Type: text/x-patch, Size: 5674 bytes --] From 5e6260951b31fbd9da826cc2ff56bfbecdbbe7eb Mon Sep 17 00:00:00 2001 From: Spencer Baugh <sbaugh@catern.com> Date: Sun, 9 Jul 2023 22:21:03 -0400 Subject: [PATCH] Support transforming the dirname used by uniquify By transforming the dirname, we can add additional information to use during uniquifying. A basic one: uniquifying buffer names based on the project name. * lisp/progmodes/project.el (project-uniquify-dirname-transform): Add. * lisp/uniquify.el (uniquify-dirname-transform-default) (uniquify-dirname-transform): Add. (bug#62621) (uniquify-rationalize-file-buffer-names, uniquify-buffer-file-name): Use uniquify-dirname-transform. * test/lisp/uniquify-tests.el (uniquify-home, uniquify-project-transform): Add tests. --- lisp/progmodes/project.el | 12 ++++++++++++ lisp/uniquify.el | 22 +++++++++++++++++----- test/lisp/uniquify-tests.el | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 03ed966cc45..11fa93fb70d 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1887,5 +1887,17 @@ project-switch-project (let ((project-current-directory-override dir)) (call-interactively command)))) +;;;###autoload +(defun project-uniquify-dirname-transform (dirname) + "Include `project-name' in DIRNAME if in a project." + (if-let (proj (project-current nil dirname)) + (let ((root (project-root proj))) + (expand-file-name + (file-name-concat + (file-name-directory root) + (project-name proj) + (file-relative-name dirname root)))) + dirname)) + (provide 'project) ;;; project.el ends here diff --git a/lisp/uniquify.el b/lisp/uniquify.el index d1ca455b673..bd49346da45 100644 --- a/lisp/uniquify.el +++ b/lisp/uniquify.el @@ -168,6 +168,16 @@ uniquify-list-buffers-directory-modes That means that when `buffer-file-name' is set to nil, `list-buffers-directory' contains the name of the directory which the buffer is visiting.") +(defcustom uniquify-dirname-transform #'identity + "A function to transform the dirname used to uniquify a buffer. + +It takes a single argument: the directory of the buffer. It +should return a string filename (which does not need to actually +exist in the filesystem) to use for uniquifying the buffer name." + :type '(choice (function-item :tag "Don't change the dirname" identity) + function) + :group 'uniquify) + ;;; Utilities ;; uniquify-fix-list data structure @@ -209,7 +219,8 @@ uniquify-rationalize-file-buffer-names ;; this buffer. (with-current-buffer newbuf (setq uniquify-managed nil)) (when dirname - (setq dirname (expand-file-name (directory-file-name dirname))) + (setq dirname (funcall uniquify-dirname-transform + (expand-file-name (directory-file-name dirname)))) (let ((fix-list (list (uniquify-make-item base dirname newbuf nil))) items) @@ -268,10 +279,11 @@ uniquify-buffer-file-name (if (memq major-mode uniquify-list-buffers-directory-modes) list-buffers-directory)))) (when filename - (directory-file-name - (file-name-directory - (expand-file-name - (directory-file-name filename)))))))) + (funcall uniquify-dirname-transform + (directory-file-name + (file-name-directory + (expand-file-name + (directory-file-name filename))))))))) (defun uniquify-rerationalize-w/o-cb (fix-list) "Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'." diff --git a/test/lisp/uniquify-tests.el b/test/lisp/uniquify-tests.el index abd61fa3504..e533c4b644c 100644 --- a/test/lisp/uniquify-tests.el +++ b/test/lisp/uniquify-tests.el @@ -88,6 +88,21 @@ uniquify-dirs '("a/dir/" "b/dir/"))) (mapc #'kill-buffer bufs))))) +(ert-deftest uniquify-home () + "uniquify works, albeit confusingly, in the presence of directories named \"~\"" + (let (bufs) + (save-excursion + (push (find-file-noselect "~") bufs) + (push (find-file-noselect "./~") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("~<test>" "~<>"))) + (push (find-file-noselect "~/foo") bufs) + (push (find-file-noselect "./~/foo") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("foo<~>" "foo</nonexistent>" "~<test>" "~<>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (ert-deftest uniquify-rename-to-dir () "Giving a buffer a name which matches a directory doesn't rename the buffer" (let ((uniquify-buffer-name-style 'forward) @@ -125,5 +140,23 @@ uniquify-space-prefix (should (equal (buffer-name) "| foo")) (kill-buffer))) +(require 'project) +(ert-deftest uniquify-project-transform () + "`project-uniquify-dirname-transform' works" + (let ((uniquify-dirname-transform #'project-uniquify-dirname-transform) + (project-vc-name "foo1/bar") + bufs) + (save-excursion + (should (file-exists-p "../README")) + (push (find-file-noselect "../README") bufs) + (push (find-file-noselect "other/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<other>" "README<bar>"))) + (push (find-file-noselect "foo2/bar/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<foo2/bar>" "README<other>" "README<foo1/bar>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (provide 'uniquify-tests) ;;; uniquify-tests.el ends here -- 2.41.0 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-13 22:51 ` sbaugh @ 2023-07-14 6:29 ` Eli Zaretskii 2023-07-14 11:28 ` sbaugh 2023-07-18 0:34 ` Dmitry Gutov 0 siblings, 2 replies; 40+ messages in thread From: Eli Zaretskii @ 2023-07-14 6:29 UTC (permalink / raw) To: sbaugh; +Cc: sbaugh, 62621 > Cc: 62621@debbugs.gnu.org > From: sbaugh@catern.com > Date: Thu, 13 Jul 2023 22:51:53 +0000 (UTC) > > I've thought quite a bit about how to make this configurable, and I > think just letting people write their own arbitrary transformation > functions, as I do in this patch, is what we should provide. Making > things any more modular is fairly difficult. Packages can come along > and provide other fancy functions if they like. If there are a couple of simpler alternatives which could be offered via simple symbolic values, we should not force everyone to write functions, IMNSHO. IOW, we should NOT immediately generalize to functions only because such generalization could make sense in some use cases. Repeat after me: Use options whose values are functions are hard on our users, because they require them to be Lisp programmers. > +(defcustom uniquify-dirname-transform #'identity > + "A function to transform the dirname used to uniquify a buffer. "Function to transform buffer's `default-directory' for uniquifying its name." > +It takes a single argument: the directory of the buffer. It > +should return a string filename (which does not need to actually > +exist in the filesystem) to use for uniquifying the buffer name." > + :type '(choice (function-item :tag "Don't change the dirname" identity) > + function) > + :group 'uniquify) The :version tag is missing. Also, the doc string should state that the default is to use the buffer's default-directory without any transformations. It should also include a link to uniquify-buffer-file-name, so that users could consult the uniquify facilities if they need to. Thanks. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 6:29 ` Eli Zaretskii @ 2023-07-14 11:28 ` sbaugh 2023-07-14 12:01 ` Eli Zaretskii 2023-07-18 0:34 ` Dmitry Gutov 1 sibling, 1 reply; 40+ messages in thread From: sbaugh @ 2023-07-14 11:28 UTC (permalink / raw) To: Eli Zaretskii; +Cc: sbaugh, 62621 Eli Zaretskii <eliz@gnu.org> writes: >> Cc: 62621@debbugs.gnu.org >> From: sbaugh@catern.com >> Date: Thu, 13 Jul 2023 22:51:53 +0000 (UTC) >> >> I've thought quite a bit about how to make this configurable, and I >> think just letting people write their own arbitrary transformation >> functions, as I do in this patch, is what we should provide. Making >> things any more modular is fairly difficult. Packages can come along >> and provide other fancy functions if they like. > > If there are a couple of simpler alternatives which could be offered > via simple symbolic values, we should not force everyone to write > functions, IMNSHO. IOW, we should NOT immediately generalize to > functions only because such generalization could make sense in some > use cases. Repeat after me: Use options whose values are functions > are hard on our users, because they require them to be Lisp > programmers. I agree, and I'm happy to change it to use a simple symbolic value 'project instead for the transform I wrote, but I'm not sure how best to handle the dependencies: uniquify.el is in loadup.el, is it OK for it to rely on project-uniquify-dirname-transform being autoloaded? >> +(defcustom uniquify-dirname-transform #'identity >> + "A function to transform the dirname used to uniquify a buffer. > > "Function to transform buffer's `default-directory' for uniquifying its name." Unfortunately, this isn't quite right. uniquify never uses default-directory, counterintuitively - by default, it uses the directory of buffer-file-name, which can differ from default-directory. >> +It takes a single argument: the directory of the buffer. It >> +should return a string filename (which does not need to actually >> +exist in the filesystem) to use for uniquifying the buffer name." >> + :type '(choice (function-item :tag "Don't change the dirname" identity) >> + function) >> + :group 'uniquify) > > The :version tag is missing. > > Also, the doc string should state that the default is to use the > buffer's default-directory without any transformations. It should > also include a link to uniquify-buffer-file-name, so that users could > consult the uniquify facilities if they need to. Will include that in the next version. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 11:28 ` sbaugh @ 2023-07-14 12:01 ` Eli Zaretskii 2023-07-14 12:20 ` Spencer Baugh 0 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-14 12:01 UTC (permalink / raw) To: sbaugh; +Cc: sbaugh, 62621 > From: sbaugh@catern.com > Date: Fri, 14 Jul 2023 11:28:13 +0000 (UTC) > Cc: sbaugh@janestreet.com, 62621@debbugs.gnu.org > > Eli Zaretskii <eliz@gnu.org> writes: > > > If there are a couple of simpler alternatives which could be offered > > via simple symbolic values, we should not force everyone to write > > functions, IMNSHO. IOW, we should NOT immediately generalize to > > functions only because such generalization could make sense in some > > use cases. Repeat after me: Use options whose values are functions > > are hard on our users, because they require them to be Lisp > > programmers. > > I agree, and I'm happy to change it to use a simple symbolic value > 'project instead for the transform I wrote, but I'm not sure how best to > handle the dependencies: uniquify.el is in loadup.el, is it OK for it to > rely on project-uniquify-dirname-transform being autoloaded? I don't understand the difficulty. If the function value could be defined in uniquify.el, why cannot a symbolic value be defined there? If the symbolic values are specific to project, simply let-bind uniquify-dirname-transform to the value of the appropriate project.el defcustom when project.el calls uniquify. > >> +(defcustom uniquify-dirname-transform #'identity > >> + "A function to transform the dirname used to uniquify a buffer. > > > > "Function to transform buffer's `default-directory' for uniquifying its name." > > Unfortunately, this isn't quite right. uniquify never uses > default-directory, counterintuitively - by default, it uses the > directory of buffer-file-name, which can differ from default-directory. That's a minor issue, just use "buffer's directory" instead. But I wonder why uniquify does something counterintuitive like that. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 12:01 ` Eli Zaretskii @ 2023-07-14 12:20 ` Spencer Baugh 2023-07-14 12:29 ` Eli Zaretskii 2023-07-14 16:31 ` Juri Linkov 0 siblings, 2 replies; 40+ messages in thread From: Spencer Baugh @ 2023-07-14 12:20 UTC (permalink / raw) To: Eli Zaretskii; +Cc: sbaugh, 62621 Eli Zaretskii <eliz@gnu.org> writes: >> From: sbaugh@catern.com >> Date: Fri, 14 Jul 2023 11:28:13 +0000 (UTC) >> Cc: sbaugh@janestreet.com, 62621@debbugs.gnu.org >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> > If there are a couple of simpler alternatives which could be offered >> > via simple symbolic values, we should not force everyone to write >> > functions, IMNSHO. IOW, we should NOT immediately generalize to >> > functions only because such generalization could make sense in some >> > use cases. Repeat after me: Use options whose values are functions >> > are hard on our users, because they require them to be Lisp >> > programmers. >> >> I agree, and I'm happy to change it to use a simple symbolic value >> 'project instead for the transform I wrote, but I'm not sure how best to >> handle the dependencies: uniquify.el is in loadup.el, is it OK for it to >> rely on project-uniquify-dirname-transform being autoloaded? > > I don't understand the difficulty. If the function value could be > defined in uniquify.el, why cannot a symbolic value be defined there? I don't understand your question :) Here's concretely the diff I would apply. This makes uniquify.el mention a function from project.el. Is that OK? diff --git a/lisp/uniquify.el b/lisp/uniquify.el index bd49346da45..4783830b184 100644 --- a/lisp/uniquify.el +++ b/lisp/uniquify.el @@ -168,14 +168,10 @@ uniquify-list-buffers-directory-modes That means that when `buffer-file-name' is set to nil, `list-buffers-directory' contains the name of the directory which the buffer is visiting.") -(defcustom uniquify-dirname-transform #'identity - "A function to transform the dirname used to uniquify a buffer. - -It takes a single argument: the directory of the buffer. It -should return a string filename (which does not need to actually -exist in the filesystem) to use for uniquifying the buffer name." - :type '(choice (function-item :tag "Don't change the dirname" identity) - function) +(defcustom uniquify-dirname-transform nil + "How to transform the dirname used to uniquify a buffer." + :type '(choice (const :tag "Don't change the dirname" nil) + (const :tag "Include project-name when uniquifying" 'project)) :group 'uniquify) ;;; Utilities @@ -279,11 +275,14 @@ uniquify-buffer-file-name (if (memq major-mode uniquify-list-buffers-directory-modes) list-buffers-directory)))) (when filename - (funcall uniquify-dirname-transform - (directory-file-name - (file-name-directory - (expand-file-name - (directory-file-name filename))))))))) + (funcall + (cond ((not uniquify-dirname-transform) #'identity) + ((eq uniquify-dirname-transform 'project) #'project-uniquify-dirname-transform) + (t (error "bad uniquify-dirname-transform: %s" uniquify-dirname-transform))) + (directory-file-name + (file-name-directory + (expand-file-name + (directory-file-name filename))))))))) (defun uniquify-rerationalize-w/o-cb (fix-list) "Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'." > If the symbolic values are specific to project, simply let-bind > uniquify-dirname-transform to the value of the appropriate project.el > defcustom when project.el calls uniquify. These customizations are in effect all the time, not just when the user is calling a project.el command. e.g. rename-buffer triggers uniquify. >> >> +(defcustom uniquify-dirname-transform #'identity >> >> + "A function to transform the dirname used to uniquify a buffer. >> > >> > "Function to transform buffer's `default-directory' for uniquifying its name." >> >> Unfortunately, this isn't quite right. uniquify never uses >> default-directory, counterintuitively - by default, it uses the >> directory of buffer-file-name, which can differ from default-directory. > > That's a minor issue, just use "buffer's directory" instead. > > But I wonder why uniquify does something counterintuitive like that. I assume it's something like "default-directory changes (such as by M-x cd) shouldn't change the buffer name too". Although personally I would be totally fine with cd changing the buffer name... The fact that uniquify doesn't use default-directory also means it's unable to uniquify buffers which aren't visiting files, which can be annoying. For example, if uniquify used default-directory then it could uniquify *compilation* buffers for different projects, renaming them based on the directory. But because it can't, every package has to come up with their own special buffer-renaming scheme... include project.el. I could add support for making uniquify use default-directory instead, if that's interesting. ^ permalink raw reply related [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 12:20 ` Spencer Baugh @ 2023-07-14 12:29 ` Eli Zaretskii 2023-07-14 12:46 ` Spencer Baugh 2023-07-14 16:31 ` Juri Linkov 1 sibling, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-14 12:29 UTC (permalink / raw) To: Spencer Baugh; +Cc: sbaugh, 62621 > From: Spencer Baugh <sbaugh@janestreet.com> > Cc: sbaugh@catern.com, 62621@debbugs.gnu.org > Date: Fri, 14 Jul 2023 08:20:02 -0400 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> I agree, and I'm happy to change it to use a simple symbolic value > >> 'project instead for the transform I wrote, but I'm not sure how best to > >> handle the dependencies: uniquify.el is in loadup.el, is it OK for it to > >> rely on project-uniquify-dirname-transform being autoloaded? > > > > I don't understand the difficulty. If the function value could be > > defined in uniquify.el, why cannot a symbolic value be defined there? > > I don't understand your question :) > > Here's concretely the diff I would apply. This makes uniquify.el mention a > function from project.el. Is that OK? No. > > If the symbolic values are specific to project, simply let-bind > > uniquify-dirname-transform to the value of the appropriate project.el > > defcustom when project.el calls uniquify. > > These customizations are in effect all the time, not just when the user > is calling a project.el command. e.g. rename-buffer triggers uniquify. Then you can set the buffer-local value of uniquify-dirname-transform in the project.el buffers. Would that solve the problem? > >> Unfortunately, this isn't quite right. uniquify never uses > >> default-directory, counterintuitively - by default, it uses the > >> directory of buffer-file-name, which can differ from default-directory. > > > > That's a minor issue, just use "buffer's directory" instead. > > > > But I wonder why uniquify does something counterintuitive like that. > > I assume it's something like "default-directory changes (such as by M-x > cd) shouldn't change the buffer name too". default-directory of a file-visiting buffer doesn't change. > The fact that uniquify doesn't use default-directory also means it's > unable to uniquify buffers which aren't visiting files Exactly. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 12:29 ` Eli Zaretskii @ 2023-07-14 12:46 ` Spencer Baugh 2023-07-14 13:51 ` Eli Zaretskii 2023-07-18 1:37 ` Dmitry Gutov 0 siblings, 2 replies; 40+ messages in thread From: Spencer Baugh @ 2023-07-14 12:46 UTC (permalink / raw) To: Eli Zaretskii; +Cc: sbaugh, 62621 Eli Zaretskii <eliz@gnu.org> writes: >> From: Spencer Baugh <sbaugh@janestreet.com> >> Cc: sbaugh@catern.com, 62621@debbugs.gnu.org >> Date: Fri, 14 Jul 2023 08:20:02 -0400 >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> >> I agree, and I'm happy to change it to use a simple symbolic value >> >> 'project instead for the transform I wrote, but I'm not sure how best to >> >> handle the dependencies: uniquify.el is in loadup.el, is it OK for it to >> >> rely on project-uniquify-dirname-transform being autoloaded? >> > >> > I don't understand the difficulty. If the function value could be >> > defined in uniquify.el, why cannot a symbolic value be defined there? >> >> I don't understand your question :) >> >> Here's concretely the diff I would apply. This makes uniquify.el mention a >> function from project.el. Is that OK? > > No. I figured. So now you see the issue with the symbolic approach. If the defcustom just takes a function, though, that solves the dependency issue. Because the user's config handles taking the function from project.el and putting it in the variable from uniquify.el. >> > If the symbolic values are specific to project, simply let-bind >> > uniquify-dirname-transform to the value of the appropriate project.el >> > defcustom when project.el calls uniquify. >> >> These customizations are in effect all the time, not just when the user >> is calling a project.el command. e.g. rename-buffer triggers uniquify. > > Then you can set the buffer-local value of uniquify-dirname-transform > in the project.el buffers. Would that solve the problem? The buffers it should affect are all file-visiting buffers. project.el doesn't currently have any code which runs for every new buffer. I guess we've considered adding that, but I'm not sure this is a good reason... >> >> Unfortunately, this isn't quite right. uniquify never uses >> >> default-directory, counterintuitively - by default, it uses the >> >> directory of buffer-file-name, which can differ from default-directory. >> > >> > That's a minor issue, just use "buffer's directory" instead. >> > >> > But I wonder why uniquify does something counterintuitive like that. >> >> I assume it's something like "default-directory changes (such as by M-x >> cd) shouldn't change the buffer name too". > > default-directory of a file-visiting buffer doesn't change. I don't think that's true. If I open ~/.emacs.d/init.el then (cd "/") then default-directory in that file-visiting buffer is / instead of ~/.emacs.d >> The fact that uniquify doesn't use default-directory also means it's >> unable to uniquify buffers which aren't visiting files > > Exactly. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 12:46 ` Spencer Baugh @ 2023-07-14 13:51 ` Eli Zaretskii 2023-07-14 14:14 ` Spencer Baugh 2023-07-18 1:37 ` Dmitry Gutov 1 sibling, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-14 13:51 UTC (permalink / raw) To: Spencer Baugh; +Cc: sbaugh, 62621 > From: Spencer Baugh <sbaugh@janestreet.com> > Cc: sbaugh@catern.com, 62621@debbugs.gnu.org > Date: Fri, 14 Jul 2023 08:46:00 -0400 > > > Eli Zaretskii <eliz@gnu.org> writes: > > >> Here's concretely the diff I would apply. This makes uniquify.el mention a > >> function from project.el. Is that OK? > > > > No. > > I figured. So now you see the issue with the symbolic approach. No, I don't. Not a significant problem, anyway, and not why it's different from using a function. > If the defcustom just takes a function, though, that solves the > dependency issue. Because the user's config handles taking the function > from project.el and putting it in the variable from uniquify.el. Ease of implementation is an important factor, but the ease of using Emacs takes precedence. So saying that some implementation alternative should be taken only because it is easier is not a winning argument. And I don't really understand how this will work in practice: if the user-defined function is supposed to be in effect only for buffers under project.el, how is this different from using symbols? > >> > If the symbolic values are specific to project, simply let-bind > >> > uniquify-dirname-transform to the value of the appropriate project.el > >> > defcustom when project.el calls uniquify. > >> > >> These customizations are in effect all the time, not just when the user > >> is calling a project.el command. e.g. rename-buffer triggers uniquify. > > > > Then you can set the buffer-local value of uniquify-dirname-transform > > in the project.el buffers. Would that solve the problem? > > The buffers it should affect are all file-visiting buffers. project.el > doesn't currently have any code which runs for every new buffer. I > guess we've considered adding that, but I'm not sure this is a good > reason... I'm sure this can be resolved, quite easily, actually. So I don't think I understand what you are trying to say here. > > default-directory of a file-visiting buffer doesn't change. > > I don't think that's true. If I open ~/.emacs.d/init.el then (cd "/") > then default-directory in that file-visiting buffer is / instead of > ~/.emacs.d You can shoot yourself in the foot if you like, but why would you? Anyway, are we still trying to reach some goal, or are we just trying to counter each other's arguments? ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 13:51 ` Eli Zaretskii @ 2023-07-14 14:14 ` Spencer Baugh 2023-07-14 19:10 ` Eli Zaretskii 0 siblings, 1 reply; 40+ messages in thread From: Spencer Baugh @ 2023-07-14 14:14 UTC (permalink / raw) To: Eli Zaretskii; +Cc: sbaugh, 62621 Eli Zaretskii <eliz@gnu.org> writes: >> From: Spencer Baugh <sbaugh@janestreet.com> >> Cc: sbaugh@catern.com, 62621@debbugs.gnu.org >> Date: Fri, 14 Jul 2023 08:46:00 -0400 >> >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> >> Here's concretely the diff I would apply. This makes uniquify.el mention a >> >> function from project.el. Is that OK? >> > >> > No. >> >> I figured. So now you see the issue with the symbolic approach. > > No, I don't. Not a significant problem, anyway, and not why it's > different from using a function. > >> If the defcustom just takes a function, though, that solves the >> dependency issue. Because the user's config handles taking the function >> from project.el and putting it in the variable from uniquify.el. > > Ease of implementation is an important factor, but the ease of using > Emacs takes precedence. So saying that some implementation > alternative should be taken only because it is easier is not a winning > argument. I agree. > And I don't really understand how this will work in practice: if the > user-defined function is supposed to be in effect only for buffers > under project.el, The transform is supposed to be in effect for all buffers, and internally it runs some code to decide whether to change the buffer name. > how is this different from using symbols? I can't contrast that to "using symbols" because I just don't understand what you mean by "using symbols". Is the diff I posted what you mean by "using symbols", or did you mean something else? >> >> > If the symbolic values are specific to project, simply let-bind >> >> > uniquify-dirname-transform to the value of the appropriate project.el >> >> > defcustom when project.el calls uniquify. >> >> >> >> These customizations are in effect all the time, not just when the user >> >> is calling a project.el command. e.g. rename-buffer triggers uniquify. >> > >> > Then you can set the buffer-local value of uniquify-dirname-transform >> > in the project.el buffers. Would that solve the problem? >> >> The buffers it should affect are all file-visiting buffers. project.el >> doesn't currently have any code which runs for every new buffer. I >> guess we've considered adding that, but I'm not sure this is a good >> reason... > > I'm sure this can be resolved, quite easily, actually. So I don't > think I understand what you are trying to say here. > >> > default-directory of a file-visiting buffer doesn't change. >> >> I don't think that's true. If I open ~/.emacs.d/init.el then (cd "/") >> then default-directory in that file-visiting buffer is / instead of >> ~/.emacs.d > > You can shoot yourself in the foot if you like, but why would you? I agree this is fairly useless but (info "(emacs) File Names") at least mentions using M-x cd in the context of file-visiting buffers: When you visit a file, Emacs sets ‘default-directory’ in the visiting buffer to the directory of its file. When you create a new buffer that is not visiting a file, via a command like ‘C-x b’, its default directory is usually copied from the buffer that was current at the time (*note Select Buffer::). You can use the command ‘M-x pwd’ to see the value of ‘default-directory’ in the current buffer. The command ‘M-x cd’ prompts for a directory’s name, and sets the buffer’s ‘default-directory’ to that directory (doing this does not change the buffer’s file name, if any). Nevertheless, I would be happy to make uniquify use default-directory instead, it will change how this behaves but it's probably OK. I can do that in a separate bug. > Anyway, are we still trying to reach some goal, or are we just trying > to counter each other's arguments? I'm not trying to counter your arguments, I just don't understand what you mean by "using symbols". I'm happy to have the configuration be symbol-based but you said "No." to the approach I posted and I don't know what other approach you are envisioning. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 14:14 ` Spencer Baugh @ 2023-07-14 19:10 ` Eli Zaretskii 2023-07-14 19:15 ` sbaugh 0 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-14 19:10 UTC (permalink / raw) To: Spencer Baugh; +Cc: sbaugh, 62621 > From: Spencer Baugh <sbaugh@janestreet.com> > Cc: sbaugh@catern.com, 62621@debbugs.gnu.org > Date: Fri, 14 Jul 2023 10:14:39 -0400 > > Eli Zaretskii <eliz@gnu.org> writes: > > > And I don't really understand how this will work in practice: if the > > user-defined function is supposed to be in effect only for buffers > > under project.el, > > The transform is supposed to be in effect for all buffers, and > internally it runs some code to decide whether to change the buffer > name. Still unclear why you thought functions can do what other values cannot. > > how is this different from using symbols? > > I can't contrast that to "using symbols" because I just don't understand > what you mean by "using symbols". It means the defcustom's value is a symbol, like 'numbered or 'append-directory, not a function. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 19:10 ` Eli Zaretskii @ 2023-07-14 19:15 ` sbaugh 2023-07-15 5:42 ` Eli Zaretskii 2023-07-18 0:19 ` Dmitry Gutov 0 siblings, 2 replies; 40+ messages in thread From: sbaugh @ 2023-07-14 19:15 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Spencer Baugh, 62621 Eli Zaretskii <eliz@gnu.org> writes: >> From: Spencer Baugh <sbaugh@janestreet.com> >> Cc: sbaugh@catern.com, 62621@debbugs.gnu.org >> Date: Fri, 14 Jul 2023 10:14:39 -0400 >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> > And I don't really understand how this will work in practice: if the >> > user-defined function is supposed to be in effect only for buffers >> > under project.el, >> >> The transform is supposed to be in effect for all buffers, and >> internally it runs some code to decide whether to change the buffer >> name. > > Still unclear why you thought functions can do what other values > cannot. > >> > how is this different from using symbols? >> >> I can't contrast that to "using symbols" because I just don't understand >> what you mean by "using symbols". > > It means the defcustom's value is a symbol, like 'numbered or > 'append-directory, not a function. Yes. But how would you implement it so that setting the defcustom to 'project causes the project-uniquify-dirname-transform logic to be used by uniquify.el, without mentioning project-uniquify-dirname-transform or other project functions in uniquify.el? ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 19:15 ` sbaugh @ 2023-07-15 5:42 ` Eli Zaretskii 2023-07-15 6:20 ` Eli Zaretskii 2023-07-18 0:19 ` Dmitry Gutov 1 sibling, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-15 5:42 UTC (permalink / raw) To: sbaugh; +Cc: sbaugh, 62621 > From: sbaugh@catern.com > Date: Fri, 14 Jul 2023 19:15:50 +0000 (UTC) > Cc: Spencer Baugh <sbaugh@janestreet.com>, 62621@debbugs.gnu.org > > Eli Zaretskii <eliz@gnu.org> writes: > > >> I can't contrast that to "using symbols" because I just don't understand > >> what you mean by "using symbols". > > > > It means the defcustom's value is a symbol, like 'numbered or > > 'append-directory, not a function. > > Yes. But how would you implement it so that setting the defcustom to > 'project causes the project-uniquify-dirname-transform logic to be used > by uniquify.el, without mentioning project-uniquify-dirname-transform or > other project functions in uniquify.el? You can use autoloading, for example. Or explicitly (require 'project) when that value is seen. Or any number of other solutions we have for such situations. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-15 5:42 ` Eli Zaretskii @ 2023-07-15 6:20 ` Eli Zaretskii 0 siblings, 0 replies; 40+ messages in thread From: Eli Zaretskii @ 2023-07-15 6:20 UTC (permalink / raw) To: sbaugh, sbaugh; +Cc: 62621 > Cc: sbaugh@janestreet.com, 62621@debbugs.gnu.org > Date: Sat, 15 Jul 2023 08:42:06 +0300 > From: Eli Zaretskii <eliz@gnu.org> > > > From: sbaugh@catern.com > > Date: Fri, 14 Jul 2023 19:15:50 +0000 (UTC) > > Cc: Spencer Baugh <sbaugh@janestreet.com>, 62621@debbugs.gnu.org > > > > Yes. But how would you implement it so that setting the defcustom to > > 'project causes the project-uniquify-dirname-transform logic to be used > > by uniquify.el, without mentioning project-uniquify-dirname-transform or > > other project functions in uniquify.el? > > You can use autoloading, for example. Or explicitly > (require 'project) when that value is seen. Or any > number of other solutions we have for such situations. Or even add a setter to this new defcustom which would set the uniquify variable to a project-specific function, and you already had that situation solved, right? IOW, we have a lot of possible solutions for this kind of problems, just select one of them. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 19:15 ` sbaugh 2023-07-15 5:42 ` Eli Zaretskii @ 2023-07-18 0:19 ` Dmitry Gutov 1 sibling, 0 replies; 40+ messages in thread From: Dmitry Gutov @ 2023-07-18 0:19 UTC (permalink / raw) To: sbaugh, Eli Zaretskii; +Cc: Spencer Baugh, 62621 On 14/07/2023 22:15, sbaugh@catern.com wrote: >>>> how is this different from using symbols? >>> I can't contrast that to "using symbols" because I just don't understand >>> what you mean by "using symbols". >> It means the defcustom's value is a symbol, like 'numbered or >> 'append-directory, not a function. > Yes. But how would you implement it so that setting the defcustom to > 'project causes the project-uniquify-dirname-transform logic to be used > by uniquify.el, without mentioning project-uniquify-dirname-transform or > other project functions in uniquify.el? Yeah, that sounds odd to me too. If we allow symbolic values in a defcustom, somewhere in the same package there has to be a mapping between the symbols and the functions corresponding to them. Which would have to refer to a function from project.el in this case. Of course, we could alternatively have some sort of registry for third-party code to jack into upon loading or etc, but that sounds like a massive overkill for this case. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 12:46 ` Spencer Baugh 2023-07-14 13:51 ` Eli Zaretskii @ 2023-07-18 1:37 ` Dmitry Gutov 2023-07-18 16:03 ` Spencer Baugh 2023-07-18 17:51 ` Juri Linkov 1 sibling, 2 replies; 40+ messages in thread From: Dmitry Gutov @ 2023-07-18 1:37 UTC (permalink / raw) To: Spencer Baugh, Eli Zaretskii; +Cc: sbaugh, 62621 On 14/07/2023 15:46, Spencer Baugh wrote: >>>> If the symbolic values are specific to project, simply let-bind >>>> uniquify-dirname-transform to the value of the appropriate project.el >>>> defcustom when project.el calls uniquify. >>> These customizations are in effect all the time, not just when the user >>> is calling a project.el command. e.g. rename-buffer triggers uniquify. >> Then you can set the buffer-local value of uniquify-dirname-transform >> in the project.el buffers. Would that solve the problem? > The buffers it should affect are all file-visiting buffers. project.el > doesn't currently have any code which runs for every new buffer. I > guess we've considered adding that, but I'm not sure this is a good > reason... I'm not sure every project.el user will want this particular behavior anyway. project-switch-buffer is handy, but personally, I still most often use 'C-x b'. But there definitely is demand for this option, as evidenced by the previously mentioned bug#59502, as well as this (unexpectedly, years-old) thread: https://lists.gnu.org/archive/html/emacs-devel/2021-03/msg00083.html Speaking of those, do you think it would be feasible to also offer these tweaks (as options, or for particular buffers): - Make the presence of the buffer name mandatory. As shown in the examples in bug#59502, it could be useful to always see in buffers like *eshell* produced by project-eshell. Or project-vc-dir, for example. - Hide the parent directory from the uniquification logic (only keeping the project name). So that, for example, if I call 'M-x project-eshell' and then 'C-u M-x project-eshell', the generated buffer names would not try to use the parent segment to uniquify, and just stay as <project-name>/*eshell* and <project-name>/*eshell-2*. There is currently some bespoke logic for naming these particular buffers, but if we could move to uniquify (and obey its custom vars), that would probably be an improvement. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-18 1:37 ` Dmitry Gutov @ 2023-07-18 16:03 ` Spencer Baugh 2023-07-19 2:47 ` Dmitry Gutov 2023-07-18 17:51 ` Juri Linkov 1 sibling, 1 reply; 40+ messages in thread From: Spencer Baugh @ 2023-07-18 16:03 UTC (permalink / raw) To: Dmitry Gutov; +Cc: sbaugh, Eli Zaretskii, 62621 Dmitry Gutov <dmitry@gutov.dev> writes: > On 14/07/2023 15:46, Spencer Baugh wrote: >>>>> If the symbolic values are specific to project, simply let-bind >>>>> uniquify-dirname-transform to the value of the appropriate project.el >>>>> defcustom when project.el calls uniquify. >>>> These customizations are in effect all the time, not just when the user >>>> is calling a project.el command. e.g. rename-buffer triggers uniquify. >>> Then you can set the buffer-local value of uniquify-dirname-transform >>> in the project.el buffers. Would that solve the problem? >> The buffers it should affect are all file-visiting buffers. project.el >> doesn't currently have any code which runs for every new buffer. I >> guess we've considered adding that, but I'm not sure this is a good >> reason... > > I'm not sure every project.el user will want this particular behavior > anyway. project-switch-buffer is handy, but personally, I still most > often use 'C-x b'. > > But there definitely is demand for this option, as evidenced by the > previously mentioned bug#59502, as well as this (unexpectedly, > years-old) thread: > https://lists.gnu.org/archive/html/emacs-devel/2021-03/msg00083.html > > Speaking of those, do you think it would be feasible to also offer > these tweaks (as options, or for particular buffers): > > - Make the presence of the buffer name mandatory. As shown in the > examples in bug#59502, it could be useful to always see in buffers > like *eshell* produced by project-eshell. Or project-vc-dir, for > example. (I assume you mean "make the presence of the project name mandatory") I think there is a good solution to this which was not mentioned in bug#59502 only add the project name (or dirname or whatever) to the buffer when that's necessary to give the buffer a unique name. That reduces overhead when working only with one project, and neatly fits in to how uniquify already works for file-visiting buffers. To do this, I think we'd need to change commands to use a function other than get-buffer-create when accessing e.g. *xref* or *eshell*, which like create-file-buffer gets a chance to uniquify the buffer name. It's a bit tricky though: we want commands to access and reuse existing a project-specific buffer if there is one, but commands doesn't know the name of that buffer so can't find it that way. find-file has solved this same problem ages ago, of reusing an existing buffer if we find-file a buffer-file-name which is already open. I think we may need something similar for non-file-visiting buffers. Maybe some kind of mechanism to find a buffer with basename "*eshell*" whose default-directory contains our current default-directory? Kind of a "locate-dominating-buffer"? > - Hide the parent directory from the uniquification logic (only > keeping the project name). So that, for example, if I call 'M-x > project-eshell' and then 'C-u M-x project-eshell', the generated > buffer names would not try to use the parent segment to uniquify, > and just stay as <project-name>/*eshell* and > <project-name>/*eshell-2*. There is currently some bespoke logic for > naming these particular buffers, but if we could move to uniquify > (and obey its custom vars), that would probably be an improvement. Hm, so if two *eshell* buffers are in the same project, they should first be uniquified from other *eshell* buffers by adding the project name, and then uniquified from each other by adding numbers to the end of the buffer name. I think I can implement this pretty easily in uniquify.el: if a set of conflicting buffers all have the same dirname, then resolve the conflict by adding numbers to the end. (Actually I was a bit surprised to realize that uniquify wasn't doing this already, but I guess it's because it previously has only worked for file-visiting buffers, which as I mentioned above are kept unique by buffer-file-name, so there can't be conflicts between two buffer names if you include their entire buffer-file-name in the buffer name.) --- Incidentally, another feature which I've been thinking about at the intersection of project.el and uniquify.el: We could rerun uniquify on project-buffers in a mode where it just outputs sufficiently unique names without actually renaming the buffers, and then use that in project-switch-to-buffer. So then when picking the buffer, you are picking from buffer names which are unique *in that specific project*. It's otherwise kind of annoying to me that project-switch-to-buffer includes a bunch of long disambiguating paths in the buffer names even though the buffer names aren't actually ambiguous in that command. Does that sound interesting? I, like you, usually use C-x b. But I think this feature would make C-x p b much nicer and competitive with C-x b. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-18 16:03 ` Spencer Baugh @ 2023-07-19 2:47 ` Dmitry Gutov 2023-07-19 6:56 ` Juri Linkov 0 siblings, 1 reply; 40+ messages in thread From: Dmitry Gutov @ 2023-07-19 2:47 UTC (permalink / raw) To: Spencer Baugh; +Cc: sbaugh, Eli Zaretskii, 62621 On 18/07/2023 19:03, Spencer Baugh wrote: >> Speaking of those, do you think it would be feasible to also offer >> these tweaks (as options, or for particular buffers): >> >> - Make the presence of the buffer name mandatory. As shown in the >> examples in bug#59502, it could be useful to always see in buffers >> like *eshell* produced by project-eshell. Or project-vc-dir, for >> example. > > (I assume you mean "make the presence of the project name mandatory") Ah yes, sorry. > I think there is a good solution to this which was not mentioned in > bug#59502 only add the project name (or dirname or whatever) to the > buffer when that's necessary to give the buffer a unique name.> That > reduces overhead when working only with one project, and neatly fits in > to how uniquify already works for file-visiting buffers. We never talked about such an option. It's a little less obvious, but might indeed fit in more smoothly for both project and non-project use cases (and I also often work on just one project). Something to consider, though: if I am in a project A, and a project B has an eshell buffer and project A does not, 'C-x b' won't tell me that that eshell is in project B. But ideally, it should, I suppose. This might have been the original reasoning to simply include the project name in those buffers' names. > To do this, I think we'd need to change commands to use a function other > than get-buffer-create when accessing e.g. *xref* or *eshell*, which > like create-file-buffer gets a chance to uniquify the buffer name. > > It's a bit tricky though: we want commands to access and reuse existing > a project-specific buffer if there is one, but commands doesn't know the > name of that buffer so can't find it that way. find-file has solved > this same problem ages ago, of reusing an existing buffer if we > find-file a buffer-file-name which is already open. I think we may need > something similar for non-file-visiting buffers. > > Maybe some kind of mechanism to find a buffer with basename "*eshell*" > whose default-directory contains our current default-directory? Kind of > a "locate-dominating-buffer"? Well... a straightforward way would be to have some public function in uniquify which, given a set of name components, would construct the supposed buffer name and see whether one exists. And/or return the newest one that matches (if there are several, sequentially enumerated). But I suppose uniquify doesn't have to be enabled in every session. So a higher-level function could be added to the core. It's hard to decouple this idea from using uniquify, though, so I'm not sure what we'd call it. Alternatively, we'd just check every time whether uniquify is on, and have two different code paths for yes and no. >> - Hide the parent directory from the uniquification logic (only >> keeping the project name). So that, for example, if I call 'M-x >> project-eshell' and then 'C-u M-x project-eshell', the generated >> buffer names would not try to use the parent segment to uniquify, >> and just stay as <project-name>/*eshell* and >> <project-name>/*eshell-2*. There is currently some bespoke logic for >> naming these particular buffers, but if we could move to uniquify >> (and obey its custom vars), that would probably be an improvement. > > Hm, so if two *eshell* buffers are in the same project, they should > first be uniquified from other *eshell* buffers by adding the project > name, and then uniquified from each other by adding numbers to the end > of the buffer name. I wonder how that's going to play with existing user expectations. Like, if there are no projects, then a regular parent directory name will be used, right? And currently eshell buffer names don't include that at all. But maybe they should?.. Anyway, if the new behavior is opt-in, there won't be a cause for complaint. > I think I can implement this pretty easily in uniquify.el: if a set of > conflicting buffers all have the same dirname, then resolve the conflict > by adding numbers to the end. Yes, I suppose if directory names are equal, it doesn't make sense to prepend further name components -- a number makes more sense. > (Actually I was a bit surprised to realize that uniquify wasn't doing > this already, but I guess it's because it previously has only worked for > file-visiting buffers, which as I mentioned above are kept unique by > buffer-file-name, so there can't be conflicts between two buffer names > if you include their entire buffer-file-name in the buffer name.) True enough. > Incidentally, another feature which I've been thinking about at the > intersection of project.el and uniquify.el: We could rerun uniquify on > project-buffers in a mode where it just outputs sufficiently unique > names without actually renaming the buffers, and then use that in > project-switch-to-buffer. So then when picking the buffer, you are > picking from buffer names which are unique *in that specific project*. > It's otherwise kind of annoying to me that project-switch-to-buffer > includes a bunch of long disambiguating paths in the buffer names even > though the buffer names aren't actually ambiguous in that command. > > Does that sound interesting? I, like you, usually use C-x b. But I > think this feature would make C-x p b much nicer and competitive with > C-x b. That does sound interesting! And actually, when initially reading a message from this thread, I thought it was about something like that. It could be implemented by altering the buffers' completion table, I suppose. But I'm not sure how much of uniquify's code could be reused there. Or the performance characteristics of re-running uniquification every time a buffer name is read. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-19 2:47 ` Dmitry Gutov @ 2023-07-19 6:56 ` Juri Linkov 0 siblings, 0 replies; 40+ messages in thread From: Juri Linkov @ 2023-07-19 6:56 UTC (permalink / raw) To: Dmitry Gutov; +Cc: Spencer Baugh, Eli Zaretskii, 62621, sbaugh >> Incidentally, another feature which I've been thinking about at the >> intersection of project.el and uniquify.el: We could rerun uniquify on >> project-buffers in a mode where it just outputs sufficiently unique >> names without actually renaming the buffers, and then use that in >> project-switch-to-buffer. So then when picking the buffer, you are >> picking from buffer names which are unique *in that specific project*. >> It's otherwise kind of annoying to me that project-switch-to-buffer >> includes a bunch of long disambiguating paths in the buffer names even >> though the buffer names aren't actually ambiguous in that command. >> Does that sound interesting? I, like you, usually use C-x b. But I >> think this feature would make C-x p b much nicer and competitive with >> C-x b. > > That does sound interesting! And actually, when initially reading a message > from this thread, I thought it was about something like that. > > It could be implemented by altering the buffers' completion table, > I suppose. But I'm not sure how much of uniquify's code could be reused > there. Or the performance characteristics of re-running uniquification > every time a buffer name is read. It could be implemented the same way as project--read-file-cpd-relative removes common-parent-directory from absolute filenames. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-18 1:37 ` Dmitry Gutov 2023-07-18 16:03 ` Spencer Baugh @ 2023-07-18 17:51 ` Juri Linkov 2023-07-19 2:24 ` Dmitry Gutov 1 sibling, 1 reply; 40+ messages in thread From: Juri Linkov @ 2023-07-18 17:51 UTC (permalink / raw) To: Dmitry Gutov; +Cc: Spencer Baugh, Eli Zaretskii, 62621, sbaugh > - Hide the parent directory from the uniquification logic (only keeping the > project name). So that, for example, if I call 'M-x project-eshell' and > then 'C-u M-x project-eshell', the generated buffer names would not try > to use the parent segment to uniquify, and just stay as > <project-name>/*eshell* and <project-name>/*eshell-2*. Often a project name in the buffer name is needed not for purposes of generating a unique buffer name, but for permanent indication which project a file/non-file buffer belongs to. In such cases indeed a parent directory makes no sense, but still uniquification is required for buffers inside the same project, e.g. <project-name>/*eshell*<1> <project-name>/*eshell*<2> So here are 2 styles combined: one for top-level project names produced by project.el, and another style for the same project by uniquify.el (in this case 'post-forward-angle-brackets'). ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-18 17:51 ` Juri Linkov @ 2023-07-19 2:24 ` Dmitry Gutov 0 siblings, 0 replies; 40+ messages in thread From: Dmitry Gutov @ 2023-07-19 2:24 UTC (permalink / raw) To: Juri Linkov; +Cc: Spencer Baugh, Eli Zaretskii, 62621, sbaugh On 18/07/2023 20:51, Juri Linkov wrote: >> - Hide the parent directory from the uniquification logic (only keeping the >> project name). So that, for example, if I call 'M-x project-eshell' and >> then 'C-u M-x project-eshell', the generated buffer names would not try >> to use the parent segment to uniquify, and just stay as >> <project-name>/*eshell* and <project-name>/*eshell-2*. > Often a project name in the buffer name is needed not for purposes > of generating a unique buffer name, but for permanent indication > which project a file/non-file buffer belongs to. That's what I was thinking of as well. I suppose, the question is, though, which place in the code should make that decision, and which one should be in change of formatting the buffer's name. > In such cases indeed a parent directory makes no sense, > but still uniquification is required for buffers inside > the same project, e.g. > > <project-name>/*eshell*<1> > <project-name>/*eshell*<2> > > So here are 2 styles combined: one for top-level project names > produced by project.el, and another style for the same project > by uniquify.el (in this case 'post-forward-angle-brackets'). ...which is a bit untidy at the moment. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 12:20 ` Spencer Baugh 2023-07-14 12:29 ` Eli Zaretskii @ 2023-07-14 16:31 ` Juri Linkov 1 sibling, 0 replies; 40+ messages in thread From: Juri Linkov @ 2023-07-14 16:31 UTC (permalink / raw) To: Spencer Baugh; +Cc: sbaugh, Eli Zaretskii, 62621 > The fact that uniquify doesn't use default-directory also means it's > unable to uniquify buffers which aren't visiting files, which can be > annoying. For example, if uniquify used default-directory then it could > uniquify *compilation* buffers for different projects, renaming them > based on the directory. But because it can't, every package has to come > up with their own special buffer-renaming scheme... include project.el. Why couldn't uniquify use default-directory? It would be nice to have such buffer names based on default-directory: *compilation*<project-1> *compilation*<project-2> ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-14 6:29 ` Eli Zaretskii 2023-07-14 11:28 ` sbaugh @ 2023-07-18 0:34 ` Dmitry Gutov 2023-07-18 11:07 ` Eli Zaretskii 1 sibling, 1 reply; 40+ messages in thread From: Dmitry Gutov @ 2023-07-18 0:34 UTC (permalink / raw) To: Eli Zaretskii, sbaugh; +Cc: sbaugh, 62621 On 14/07/2023 09:29, Eli Zaretskii wrote: > IOW, we should NOT immediately generalize to > functions only because such generalization could make sense in some > use cases. I agree with that statement. When only one or two behaviors can be needed or foreseen, there's no hard need to make the option open-ended (which it becomes when it can be set to a function). This case, however, looks more like an exception to my eye. Similar to save-some-buffers-default-predicate where extensibility makes sense. And if you also wanted to avoid a direct reference to project-* in uniquify.el, that's another argument in favor of extensibility. > Repeat after me: Use options whose values are functions > are hard on our users, because they require them to be Lisp > programmers. That doesn't have to be the case. If the defcustom's docstring mentions several functions that can be used, and the :type widget includes them as well, the user can decide to switch to any of them without writing any Lisp (or having to understand the implementations). Examples: the aforementioned save-some-buffers-default-predicate, or project-prompter, or xref-history-storage, and so on. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-18 0:34 ` Dmitry Gutov @ 2023-07-18 11:07 ` Eli Zaretskii 2023-07-19 2:22 ` Dmitry Gutov 0 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-18 11:07 UTC (permalink / raw) To: Dmitry Gutov; +Cc: sbaugh, 62621, sbaugh > Date: Tue, 18 Jul 2023 03:34:06 +0300 > Cc: sbaugh@janestreet.com, 62621@debbugs.gnu.org > From: Dmitry Gutov <dmitry@gutov.dev> > > > Repeat after me: Use options whose values are functions > > are hard on our users, because they require them to be Lisp > > programmers. > > That doesn't have to be the case. If the defcustom's docstring mentions > several functions that can be used, and the :type widget includes them > as well, the user can decide to switch to any of them without writing > any Lisp (or having to understand the implementations). But that was not so in this particular case. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-18 11:07 ` Eli Zaretskii @ 2023-07-19 2:22 ` Dmitry Gutov 2023-07-19 12:14 ` Eli Zaretskii 0 siblings, 1 reply; 40+ messages in thread From: Dmitry Gutov @ 2023-07-19 2:22 UTC (permalink / raw) To: Eli Zaretskii; +Cc: sbaugh, 62621, sbaugh On 18/07/2023 14:07, Eli Zaretskii wrote: >> Date: Tue, 18 Jul 2023 03:34:06 +0300 >> Cc:sbaugh@janestreet.com,62621@debbugs.gnu.org >> From: Dmitry Gutov<dmitry@gutov.dev> >> >>> Repeat after me: Use options whose values are functions >>> are hard on our users, because they require them to be Lisp >>> programmers. >> That doesn't have to be the case. If the defcustom's docstring mentions >> several functions that can be used, and the :type widget includes them >> as well, the user can decide to switch to any of them without writing >> any Lisp (or having to understand the implementations). > But that was not so in this particular case. That's easy to fix, as long as you don't have additional objections to that approach. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-19 2:22 ` Dmitry Gutov @ 2023-07-19 12:14 ` Eli Zaretskii 2023-07-19 12:31 ` Spencer Baugh 0 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-19 12:14 UTC (permalink / raw) To: Dmitry Gutov; +Cc: sbaugh, 62621, sbaugh > Date: Wed, 19 Jul 2023 05:22:56 +0300 > Cc: sbaugh@catern.com, sbaugh@janestreet.com, 62621@debbugs.gnu.org > From: Dmitry Gutov <dmitry@gutov.dev> > > On 18/07/2023 14:07, Eli Zaretskii wrote: > >> Date: Tue, 18 Jul 2023 03:34:06 +0300 > >> Cc:sbaugh@janestreet.com,62621@debbugs.gnu.org > >> From: Dmitry Gutov<dmitry@gutov.dev> > >> > >>> Repeat after me: Use options whose values are functions > >>> are hard on our users, because they require them to be Lisp > >>> programmers. > >> That doesn't have to be the case. If the defcustom's docstring mentions > >> several functions that can be used, and the :type widget includes them > >> as well, the user can decide to switch to any of them without writing > >> any Lisp (or having to understand the implementations). > > But that was not so in this particular case. > > That's easy to fix, as long as you don't have additional objections to > that approach. I'd need to see the fix first, because I don't think I have a clear idea of what you have in mind. (My objections, btw, where very minor and of pure usability nature. Frankly, I'm surprised such a simple and more-or-less agreed-upon comment got such a long thread of discussing various loosely-related issues.) ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-19 12:14 ` Eli Zaretskii @ 2023-07-19 12:31 ` Spencer Baugh 2023-07-19 13:25 ` Eli Zaretskii 0 siblings, 1 reply; 40+ messages in thread From: Spencer Baugh @ 2023-07-19 12:31 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Dmitry Gutov, 62621, sbaugh [-- Attachment #1: Type: text/plain, Size: 1315 bytes --] Eli Zaretskii <eliz@gnu.org> writes: >> Date: Wed, 19 Jul 2023 05:22:56 +0300 >> Cc: sbaugh@catern.com, sbaugh@janestreet.com, 62621@debbugs.gnu.org >> From: Dmitry Gutov <dmitry@gutov.dev> >> >> On 18/07/2023 14:07, Eli Zaretskii wrote: >> >> Date: Tue, 18 Jul 2023 03:34:06 +0300 >> >> Cc:sbaugh@janestreet.com,62621@debbugs.gnu.org >> >> From: Dmitry Gutov<dmitry@gutov.dev> >> >> >> >>> Repeat after me: Use options whose values are functions >> >>> are hard on our users, because they require them to be Lisp >> >>> programmers. >> >> That doesn't have to be the case. If the defcustom's docstring mentions >> >> several functions that can be used, and the :type widget includes them >> >> as well, the user can decide to switch to any of them without writing >> >> any Lisp (or having to understand the implementations). >> > But that was not so in this particular case. >> >> That's easy to fix, as long as you don't have additional objections to >> that approach. > > I'd need to see the fix first, because I don't think I have a clear > idea of what you have in mind. > > (My objections, btw, where very minor and of pure usability nature. > Frankly, I'm surprised such a simple and more-or-less agreed-upon > comment got such a long thread of discussing various loosely-related > issues.) Like this: [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Support-transforming-the-dirname-used-by-uniquify.patch --] [-- Type: text/x-patch, Size: 5843 bytes --] From 7fcbc7499809134104bb5dbde206094d85f48806 Mon Sep 17 00:00:00 2001 From: Spencer Baugh <sbaugh@catern.com> Date: Sun, 9 Jul 2023 22:21:03 -0400 Subject: [PATCH] Support transforming the dirname used by uniquify By transforming the dirname, we can add additional information to use during uniquifying. A basic one: uniquifying buffer names based on the project name. * lisp/progmodes/project.el (project-uniquify-dirname-transform): Add. * lisp/uniquify.el (uniquify-dirname-transform-default) (uniquify-dirname-transform): Add. (bug#62621) (uniquify-rationalize-file-buffer-names, uniquify-buffer-file-name): Use uniquify-dirname-transform. * test/lisp/uniquify-tests.el (uniquify-home, uniquify-project-transform): Add tests. --- lisp/progmodes/project.el | 12 ++++++++++++ lisp/uniquify.el | 25 ++++++++++++++++++++----- test/lisp/uniquify-tests.el | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index d482cc24d70..78f9fb410c1 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1835,5 +1835,17 @@ project-switch-project (let ((project-current-directory-override dir)) (call-interactively command)))) +;;;###autoload +(defun project-uniquify-dirname-transform (dirname) + "Include `project-name' in DIRNAME if in a project." + (if-let (proj (project-current nil dirname)) + (let ((root (project-root proj))) + (expand-file-name + (file-name-concat + (file-name-directory root) + (project-name proj) + (file-relative-name dirname root)))) + dirname)) + (provide 'project) ;;; project.el ends here diff --git a/lisp/uniquify.el b/lisp/uniquify.el index d1ca455b673..328f85bf32f 100644 --- a/lisp/uniquify.el +++ b/lisp/uniquify.el @@ -168,6 +168,19 @@ uniquify-list-buffers-directory-modes That means that when `buffer-file-name' is set to nil, `list-buffers-directory' contains the name of the directory which the buffer is visiting.") +(defcustom uniquify-dirname-transform #'identity + "Function to transform buffer's directory for uniquifying its name. + +It takes a single argument: the directory of the buffer. It +should return a string filename (which does not need to actually +exist in the filesystem) to use for uniquifying the buffer name." + :type '(choice (function-item :tag "Don't change the dirname" identity) + (function-item :tag "Include project name in dirname" + #'project-uniquify-dirname-transform) + function) + :version "30.1" + :group 'uniquify) + ;;; Utilities ;; uniquify-fix-list data structure @@ -209,7 +222,8 @@ uniquify-rationalize-file-buffer-names ;; this buffer. (with-current-buffer newbuf (setq uniquify-managed nil)) (when dirname - (setq dirname (expand-file-name (directory-file-name dirname))) + (setq dirname (funcall uniquify-dirname-transform + (expand-file-name (directory-file-name dirname)))) (let ((fix-list (list (uniquify-make-item base dirname newbuf nil))) items) @@ -268,10 +282,11 @@ uniquify-buffer-file-name (if (memq major-mode uniquify-list-buffers-directory-modes) list-buffers-directory)))) (when filename - (directory-file-name - (file-name-directory - (expand-file-name - (directory-file-name filename)))))))) + (funcall uniquify-dirname-transform + (directory-file-name + (file-name-directory + (expand-file-name + (directory-file-name filename))))))))) (defun uniquify-rerationalize-w/o-cb (fix-list) "Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'." diff --git a/test/lisp/uniquify-tests.el b/test/lisp/uniquify-tests.el index abd61fa3504..e533c4b644c 100644 --- a/test/lisp/uniquify-tests.el +++ b/test/lisp/uniquify-tests.el @@ -88,6 +88,21 @@ uniquify-dirs '("a/dir/" "b/dir/"))) (mapc #'kill-buffer bufs))))) +(ert-deftest uniquify-home () + "uniquify works, albeit confusingly, in the presence of directories named \"~\"" + (let (bufs) + (save-excursion + (push (find-file-noselect "~") bufs) + (push (find-file-noselect "./~") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("~<test>" "~<>"))) + (push (find-file-noselect "~/foo") bufs) + (push (find-file-noselect "./~/foo") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("foo<~>" "foo</nonexistent>" "~<test>" "~<>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (ert-deftest uniquify-rename-to-dir () "Giving a buffer a name which matches a directory doesn't rename the buffer" (let ((uniquify-buffer-name-style 'forward) @@ -125,5 +140,23 @@ uniquify-space-prefix (should (equal (buffer-name) "| foo")) (kill-buffer))) +(require 'project) +(ert-deftest uniquify-project-transform () + "`project-uniquify-dirname-transform' works" + (let ((uniquify-dirname-transform #'project-uniquify-dirname-transform) + (project-vc-name "foo1/bar") + bufs) + (save-excursion + (should (file-exists-p "../README")) + (push (find-file-noselect "../README") bufs) + (push (find-file-noselect "other/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<other>" "README<bar>"))) + (push (find-file-noselect "foo2/bar/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<foo2/bar>" "README<other>" "README<foo1/bar>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (provide 'uniquify-tests) ;;; uniquify-tests.el ends here -- 2.39.3 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-19 12:31 ` Spencer Baugh @ 2023-07-19 13:25 ` Eli Zaretskii 2023-07-21 13:34 ` Spencer Baugh 0 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-19 13:25 UTC (permalink / raw) To: Spencer Baugh; +Cc: dmitry, 62621, sbaugh > From: Spencer Baugh <sbaugh@janestreet.com> > Cc: Dmitry Gutov <dmitry@gutov.dev>, sbaugh@catern.com, 62621@debbugs.gnu.org > Date: Wed, 19 Jul 2023 08:31:00 -0400 > > >> >>> Repeat after me: Use options whose values are functions > >> >>> are hard on our users, because they require them to be Lisp > >> >>> programmers. > >> >> That doesn't have to be the case. If the defcustom's docstring mentions > >> >> several functions that can be used, and the :type widget includes them > >> >> as well, the user can decide to switch to any of them without writing > >> >> any Lisp (or having to understand the implementations). > >> > But that was not so in this particular case. > >> > >> That's easy to fix, as long as you don't have additional objections to > >> that approach. > > > > I'd need to see the fix first, because I don't think I have a clear > > idea of what you have in mind. > > > > (My objections, btw, where very minor and of pure usability nature. > > Frankly, I'm surprised such a simple and more-or-less agreed-upon > > comment got such a long thread of discussing various loosely-related > > issues.) > > Like this: Thanks, but it still falls short of what Dmitry described above: the doc string doesn't "mention several functions that can be used". > +(defcustom uniquify-dirname-transform #'identity > + "Function to transform buffer's directory for uniquifying its name. > + > +It takes a single argument: the directory of the buffer. It > +should return a string filename (which does not need to actually > +exist in the filesystem) to use for uniquifying the buffer name." Please read this carefully and try to put yourself in the shoes of a user who needs to make sense out of this description. The immediate question I had is what does "transforming a buffer's directory" have to do with "uniquifying the buffer name"? Uniquifying a buffer's name is not about its directory, at least not in general. IOW, the starting point of this description is too "inside" the implementation. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-19 13:25 ` Eli Zaretskii @ 2023-07-21 13:34 ` Spencer Baugh 2023-07-21 14:37 ` Eli Zaretskii 0 siblings, 1 reply; 40+ messages in thread From: Spencer Baugh @ 2023-07-21 13:34 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dmitry, 62621, sbaugh [-- Attachment #1: Type: text/plain, Size: 2131 bytes --] Eli Zaretskii <eliz@gnu.org> writes: >> From: Spencer Baugh <sbaugh@janestreet.com> >> Cc: Dmitry Gutov <dmitry@gutov.dev>, sbaugh@catern.com, 62621@debbugs.gnu.org >> Date: Wed, 19 Jul 2023 08:31:00 -0400 >> >> >> >>> Repeat after me: Use options whose values are functions >> >> >>> are hard on our users, because they require them to be Lisp >> >> >>> programmers. >> >> >> That doesn't have to be the case. If the defcustom's docstring mentions >> >> >> several functions that can be used, and the :type widget includes them >> >> >> as well, the user can decide to switch to any of them without writing >> >> >> any Lisp (or having to understand the implementations). >> >> > But that was not so in this particular case. >> >> >> >> That's easy to fix, as long as you don't have additional objections to >> >> that approach. >> > >> > I'd need to see the fix first, because I don't think I have a clear >> > idea of what you have in mind. >> > >> > (My objections, btw, where very minor and of pure usability nature. >> > Frankly, I'm surprised such a simple and more-or-less agreed-upon >> > comment got such a long thread of discussing various loosely-related >> > issues.) >> >> Like this: > > Thanks, but it still falls short of what Dmitry described above: the > doc string doesn't "mention several functions that can be used". > >> +(defcustom uniquify-dirname-transform #'identity >> + "Function to transform buffer's directory for uniquifying its name. >> + >> +It takes a single argument: the directory of the buffer. It >> +should return a string filename (which does not need to actually >> +exist in the filesystem) to use for uniquifying the buffer name." > > Please read this carefully and try to put yourself in the shoes of a > user who needs to make sense out of this description. The immediate > question I had is what does "transforming a buffer's directory" have > to do with "uniquifying the buffer name"? Uniquifying a buffer's name > is not about its directory, at least not in general. IOW, the > starting point of this description is too "inside" the implementation. OK, how about this? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Support-transforming-the-dirname-used-by-uniquify.patch --] [-- Type: text/x-patch, Size: 6460 bytes --] From d5d909040b04bd8d6265d5f19eb3610b6d3d87d8 Mon Sep 17 00:00:00 2001 From: Spencer Baugh <sbaugh@catern.com> Date: Sun, 9 Jul 2023 22:21:03 -0400 Subject: [PATCH] Support transforming the dirname used by uniquify By transforming the dirname, we can add additional information to use during uniquifying. A basic one: uniquifying buffer names based on the project name. * lisp/progmodes/project.el (project-uniquify-dirname-transform): Add. * lisp/uniquify.el (uniquify-dirname-transform-default) (uniquify-dirname-transform): Add. (bug#62621) (uniquify-rationalize-file-buffer-names, uniquify-buffer-file-name): Use uniquify-dirname-transform. * test/lisp/uniquify-tests.el (uniquify-home, uniquify-project-transform): Add tests. --- lisp/progmodes/project.el | 12 ++++++++++++ lisp/uniquify.el | 38 ++++++++++++++++++++++++++++++++----- test/lisp/uniquify-tests.el | 33 ++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index d482cc24d70..78f9fb410c1 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1835,5 +1835,17 @@ project-switch-project (let ((project-current-directory-override dir)) (call-interactively command)))) +;;;###autoload +(defun project-uniquify-dirname-transform (dirname) + "Include `project-name' in DIRNAME if in a project." + (if-let (proj (project-current nil dirname)) + (let ((root (project-root proj))) + (expand-file-name + (file-name-concat + (file-name-directory root) + (project-name proj) + (file-relative-name dirname root)))) + dirname)) + (provide 'project) ;;; project.el ends here diff --git a/lisp/uniquify.el b/lisp/uniquify.el index d1ca455b673..eec5aefc803 100644 --- a/lisp/uniquify.el +++ b/lisp/uniquify.el @@ -168,6 +168,32 @@ uniquify-list-buffers-directory-modes That means that when `buffer-file-name' is set to nil, `list-buffers-directory' contains the name of the directory which the buffer is visiting.") +(defcustom uniquify-dirname-transform #'identity + "Function to transform buffer's directory for uniquifying its name. + +When `uniquify-buffer-name-style' is non-nil, if a buffer's name +would be the same as some other buffer, then components from the +buffer's directory name are added to the buffer's name until the +buffer's name is unique. + +By default, uniquifying only adds components from the buffer's +directory name. If you set this variable to +`project-uniquify-dirname-transform', slash-separated components +from `project-name' will also be added to the buffer's name when +buffers from two different projects would otherwise have the same +name. + +To include your own custom details in the unique buffer name, set +this variable to a function taking a single argument, the +buffer's directory, and returning a file name (which does not +need to actually exist in the filesystem) to use components from." + :type '(choice (function-item :tag "Don't change the dirname" identity) + (function-item :tag "Include project name in dirname" + #'project-uniquify-dirname-transform) + function) + :version "30.1" + :group 'uniquify) + ;;; Utilities ;; uniquify-fix-list data structure @@ -209,7 +235,8 @@ uniquify-rationalize-file-buffer-names ;; this buffer. (with-current-buffer newbuf (setq uniquify-managed nil)) (when dirname - (setq dirname (expand-file-name (directory-file-name dirname))) + (setq dirname (funcall uniquify-dirname-transform + (expand-file-name (directory-file-name dirname)))) (let ((fix-list (list (uniquify-make-item base dirname newbuf nil))) items) @@ -268,10 +295,11 @@ uniquify-buffer-file-name (if (memq major-mode uniquify-list-buffers-directory-modes) list-buffers-directory)))) (when filename - (directory-file-name - (file-name-directory - (expand-file-name - (directory-file-name filename)))))))) + (funcall uniquify-dirname-transform + (directory-file-name + (file-name-directory + (expand-file-name + (directory-file-name filename))))))))) (defun uniquify-rerationalize-w/o-cb (fix-list) "Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'." diff --git a/test/lisp/uniquify-tests.el b/test/lisp/uniquify-tests.el index abd61fa3504..e533c4b644c 100644 --- a/test/lisp/uniquify-tests.el +++ b/test/lisp/uniquify-tests.el @@ -88,6 +88,21 @@ uniquify-dirs '("a/dir/" "b/dir/"))) (mapc #'kill-buffer bufs))))) +(ert-deftest uniquify-home () + "uniquify works, albeit confusingly, in the presence of directories named \"~\"" + (let (bufs) + (save-excursion + (push (find-file-noselect "~") bufs) + (push (find-file-noselect "./~") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("~<test>" "~<>"))) + (push (find-file-noselect "~/foo") bufs) + (push (find-file-noselect "./~/foo") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("foo<~>" "foo</nonexistent>" "~<test>" "~<>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (ert-deftest uniquify-rename-to-dir () "Giving a buffer a name which matches a directory doesn't rename the buffer" (let ((uniquify-buffer-name-style 'forward) @@ -125,5 +140,23 @@ uniquify-space-prefix (should (equal (buffer-name) "| foo")) (kill-buffer))) +(require 'project) +(ert-deftest uniquify-project-transform () + "`project-uniquify-dirname-transform' works" + (let ((uniquify-dirname-transform #'project-uniquify-dirname-transform) + (project-vc-name "foo1/bar") + bufs) + (save-excursion + (should (file-exists-p "../README")) + (push (find-file-noselect "../README") bufs) + (push (find-file-noselect "other/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<other>" "README<bar>"))) + (push (find-file-noselect "foo2/bar/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<foo2/bar>" "README<other>" "README<foo1/bar>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (provide 'uniquify-tests) ;;; uniquify-tests.el ends here -- 2.39.3 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-21 13:34 ` Spencer Baugh @ 2023-07-21 14:37 ` Eli Zaretskii 2023-07-22 18:00 ` Spencer Baugh 0 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-21 14:37 UTC (permalink / raw) To: Spencer Baugh; +Cc: dmitry, 62621, sbaugh > From: Spencer Baugh <sbaugh@janestreet.com> > Cc: dmitry@gutov.dev, 62621@debbugs.gnu.org, sbaugh@catern.com > Date: Fri, 21 Jul 2023 09:34:28 -0400 > > > Thanks, but it still falls short of what Dmitry described above: the > > doc string doesn't "mention several functions that can be used". > > > >> +(defcustom uniquify-dirname-transform #'identity > >> + "Function to transform buffer's directory for uniquifying its name. > >> + > >> +It takes a single argument: the directory of the buffer. It > >> +should return a string filename (which does not need to actually > >> +exist in the filesystem) to use for uniquifying the buffer name." > > > > Please read this carefully and try to put yourself in the shoes of a > > user who needs to make sense out of this description. The immediate > > question I had is what does "transforming a buffer's directory" have > > to do with "uniquifying the buffer name"? Uniquifying a buffer's name > > is not about its directory, at least not in general. IOW, the > > starting point of this description is too "inside" the implementation. > > OK, how about this? The explanation of what project-uniquify-dirname-transform does should in its doc string, not in the doc string of uniquify-dirname-transform (which should refer to the former, and that is enough). The doc string of uniquify-dirname-transform should mention at least 'identity' as the default (what you wrote does that, but without mentioning the function's name), otherwise this still falls short of what Dmitry described. And the last two paragraphs of the doc string of uniquify-dirname-transform should be more-or-less reversed: first describe the default, and that using some function other than 'identity' can affect the result, then describe project-uniquify-dirname-transform as one such non-default transform. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-21 14:37 ` Eli Zaretskii @ 2023-07-22 18:00 ` Spencer Baugh 2023-07-24 19:18 ` Spencer Baugh 0 siblings, 1 reply; 40+ messages in thread From: Spencer Baugh @ 2023-07-22 18:00 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dmitry, 62621, sbaugh [-- Attachment #1: Type: text/plain, Size: 1945 bytes --] Eli Zaretskii <eliz@gnu.org> writes: >> From: Spencer Baugh <sbaugh@janestreet.com> >> Cc: dmitry@gutov.dev, 62621@debbugs.gnu.org, sbaugh@catern.com >> Date: Fri, 21 Jul 2023 09:34:28 -0400 >> >> > Thanks, but it still falls short of what Dmitry described above: the >> > doc string doesn't "mention several functions that can be used". >> > >> >> +(defcustom uniquify-dirname-transform #'identity >> >> + "Function to transform buffer's directory for uniquifying its name. >> >> + >> >> +It takes a single argument: the directory of the buffer. It >> >> +should return a string filename (which does not need to actually >> >> +exist in the filesystem) to use for uniquifying the buffer name." >> > >> > Please read this carefully and try to put yourself in the shoes of a >> > user who needs to make sense out of this description. The immediate >> > question I had is what does "transforming a buffer's directory" have >> > to do with "uniquifying the buffer name"? Uniquifying a buffer's name >> > is not about its directory, at least not in general. IOW, the >> > starting point of this description is too "inside" the implementation. >> >> OK, how about this? > > The explanation of what project-uniquify-dirname-transform does should > in its doc string, not in the doc string of uniquify-dirname-transform > (which should refer to the former, and that is enough). > > The doc string of uniquify-dirname-transform should mention at least > 'identity' as the default (what you wrote does that, but without > mentioning the function's name), otherwise this still falls short of > what Dmitry described. > > And the last two paragraphs of the doc string of > uniquify-dirname-transform should be more-or-less reversed: first > describe the default, and that using some function other than > 'identity' can affect the result, then describe > project-uniquify-dirname-transform as one such non-default transform. OK, how about this? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Support-transforming-the-dirname-used-by-uniquify.patch --] [-- Type: text/x-patch, Size: 6426 bytes --] From 30b6cf1961b89f12e54adeae9035036696807a38 Mon Sep 17 00:00:00 2001 From: Spencer Baugh <sbaugh@catern.com> Date: Sun, 9 Jul 2023 22:21:03 -0400 Subject: [PATCH] Support transforming the dirname used by uniquify By transforming the dirname, we can add additional information to use during uniquifying. A basic one: uniquifying buffer names based on the project name. * lisp/progmodes/project.el (project-uniquify-dirname-transform): Add. * lisp/uniquify.el (uniquify-dirname-transform-default) (uniquify-dirname-transform): Add. (bug#62621) (uniquify-rationalize-file-buffer-names, uniquify-buffer-file-name): Use uniquify-dirname-transform. * test/lisp/uniquify-tests.el (uniquify-home, uniquify-project-transform): Add tests. --- lisp/progmodes/project.el | 12 ++++++++++++ lisp/uniquify.el | 37 ++++++++++++++++++++++++++++++++----- test/lisp/uniquify-tests.el | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index d482cc24d70..78f9fb410c1 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1835,5 +1835,17 @@ project-switch-project (let ((project-current-directory-override dir)) (call-interactively command)))) +;;;###autoload +(defun project-uniquify-dirname-transform (dirname) + "Include `project-name' in DIRNAME if in a project." + (if-let (proj (project-current nil dirname)) + (let ((root (project-root proj))) + (expand-file-name + (file-name-concat + (file-name-directory root) + (project-name proj) + (file-relative-name dirname root)))) + dirname)) + (provide 'project) ;;; project.el ends here diff --git a/lisp/uniquify.el b/lisp/uniquify.el index d1ca455b673..af00c95663d 100644 --- a/lisp/uniquify.el +++ b/lisp/uniquify.el @@ -168,6 +168,31 @@ uniquify-list-buffers-directory-modes That means that when `buffer-file-name' is set to nil, `list-buffers-directory' contains the name of the directory which the buffer is visiting.") +(defcustom uniquify-dirname-transform #'identity + "Function to transform buffer's directory for uniquifying its name. + +If `uniquify-buffer-name-style' is non-nil and a buffer's name +would be the same as some other buffer, then components from the +buffer's directory name are added to the buffer's name until the +buffer's name is unique. + +This function is used to transform the buffer's directory name +before the uniquifying process, allowing the unique buffer name +to include components from other sources. The default is +`identity', so only the buffer's directory name is used for +uniquifying. This function is called with the buffer's directory +name and should return a file name (which does not need to +actually exist in the filesystem) to use components from. + +To include components from `project-name', set this variable to +`project-uniquify-dirname-transform'." + :type '(choice (function-item :tag "Don't change the dirname" identity) + (function-item :tag "Include project name in dirname" + #'project-uniquify-dirname-transform) + function) + :version "30.1" + :group 'uniquify) + ;;; Utilities ;; uniquify-fix-list data structure @@ -209,7 +234,8 @@ uniquify-rationalize-file-buffer-names ;; this buffer. (with-current-buffer newbuf (setq uniquify-managed nil)) (when dirname - (setq dirname (expand-file-name (directory-file-name dirname))) + (setq dirname (funcall uniquify-dirname-transform + (expand-file-name (directory-file-name dirname)))) (let ((fix-list (list (uniquify-make-item base dirname newbuf nil))) items) @@ -268,10 +294,11 @@ uniquify-buffer-file-name (if (memq major-mode uniquify-list-buffers-directory-modes) list-buffers-directory)))) (when filename - (directory-file-name - (file-name-directory - (expand-file-name - (directory-file-name filename)))))))) + (funcall uniquify-dirname-transform + (directory-file-name + (file-name-directory + (expand-file-name + (directory-file-name filename))))))))) (defun uniquify-rerationalize-w/o-cb (fix-list) "Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'." diff --git a/test/lisp/uniquify-tests.el b/test/lisp/uniquify-tests.el index abd61fa3504..e533c4b644c 100644 --- a/test/lisp/uniquify-tests.el +++ b/test/lisp/uniquify-tests.el @@ -88,6 +88,21 @@ uniquify-dirs '("a/dir/" "b/dir/"))) (mapc #'kill-buffer bufs))))) +(ert-deftest uniquify-home () + "uniquify works, albeit confusingly, in the presence of directories named \"~\"" + (let (bufs) + (save-excursion + (push (find-file-noselect "~") bufs) + (push (find-file-noselect "./~") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("~<test>" "~<>"))) + (push (find-file-noselect "~/foo") bufs) + (push (find-file-noselect "./~/foo") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("foo<~>" "foo</nonexistent>" "~<test>" "~<>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (ert-deftest uniquify-rename-to-dir () "Giving a buffer a name which matches a directory doesn't rename the buffer" (let ((uniquify-buffer-name-style 'forward) @@ -125,5 +140,23 @@ uniquify-space-prefix (should (equal (buffer-name) "| foo")) (kill-buffer))) +(require 'project) +(ert-deftest uniquify-project-transform () + "`project-uniquify-dirname-transform' works" + (let ((uniquify-dirname-transform #'project-uniquify-dirname-transform) + (project-vc-name "foo1/bar") + bufs) + (save-excursion + (should (file-exists-p "../README")) + (push (find-file-noselect "../README") bufs) + (push (find-file-noselect "other/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<other>" "README<bar>"))) + (push (find-file-noselect "foo2/bar/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<foo2/bar>" "README<other>" "README<foo1/bar>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (provide 'uniquify-tests) ;;; uniquify-tests.el ends here -- 2.39.3 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-22 18:00 ` Spencer Baugh @ 2023-07-24 19:18 ` Spencer Baugh 2023-07-26 15:18 ` Eli Zaretskii 0 siblings, 1 reply; 40+ messages in thread From: Spencer Baugh @ 2023-07-24 19:18 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dmitry, 62621, sbaugh [-- Attachment #1: Type: text/plain, Size: 2144 bytes --] Spencer Baugh <sbaugh@janestreet.com> writes: > Eli Zaretskii <eliz@gnu.org> writes: >>> From: Spencer Baugh <sbaugh@janestreet.com> >>> Cc: dmitry@gutov.dev, 62621@debbugs.gnu.org, sbaugh@catern.com >>> Date: Fri, 21 Jul 2023 09:34:28 -0400 >>> >>> > Thanks, but it still falls short of what Dmitry described above: the >>> > doc string doesn't "mention several functions that can be used". >>> > >>> >> +(defcustom uniquify-dirname-transform #'identity >>> >> + "Function to transform buffer's directory for uniquifying its name. >>> >> + >>> >> +It takes a single argument: the directory of the buffer. It >>> >> +should return a string filename (which does not need to actually >>> >> +exist in the filesystem) to use for uniquifying the buffer name." >>> > >>> > Please read this carefully and try to put yourself in the shoes of a >>> > user who needs to make sense out of this description. The immediate >>> > question I had is what does "transforming a buffer's directory" have >>> > to do with "uniquifying the buffer name"? Uniquifying a buffer's name >>> > is not about its directory, at least not in general. IOW, the >>> > starting point of this description is too "inside" the implementation. >>> >>> OK, how about this? >> >> The explanation of what project-uniquify-dirname-transform does should >> in its doc string, not in the doc string of uniquify-dirname-transform >> (which should refer to the former, and that is enough). >> >> The doc string of uniquify-dirname-transform should mention at least >> 'identity' as the default (what you wrote does that, but without >> mentioning the function's name), otherwise this still falls short of >> what Dmitry described. >> >> And the last two paragraphs of the doc string of >> uniquify-dirname-transform should be more-or-less reversed: first >> describe the default, and that using some function other than >> 'identity' can affect the result, then describe >> project-uniquify-dirname-transform as one such non-default transform. > > OK, how about this? Oops, that one didn't include the updated project-uniquify-dirname-transform docstring. The right patch now: [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Support-transforming-the-dirname-used-by-uniquify.patch --] [-- Type: text/x-patch, Size: 6654 bytes --] From 39e508c96ddf6bc5361542aa030f199193329fe0 Mon Sep 17 00:00:00 2001 From: Spencer Baugh <sbaugh@catern.com> Date: Sun, 9 Jul 2023 22:21:03 -0400 Subject: [PATCH] Support transforming the dirname used by uniquify By transforming the dirname, we can add additional information to use during uniquifying. A basic one: uniquifying buffer names based on the project name. * lisp/progmodes/project.el (project-uniquify-dirname-transform): Add. * lisp/uniquify.el (uniquify-dirname-transform-default) (uniquify-dirname-transform): Add. (bug#62621) (uniquify-rationalize-file-buffer-names, uniquify-buffer-file-name): Use uniquify-dirname-transform. * test/lisp/uniquify-tests.el (uniquify-home, uniquify-project-transform): Add tests. --- lisp/progmodes/project.el | 17 +++++++++++++++++ lisp/uniquify.el | 37 ++++++++++++++++++++++++++++++++----- test/lisp/uniquify-tests.el | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index d482cc24d70..36c1005aef5 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1835,5 +1835,22 @@ project-switch-project (let ((project-current-directory-override dir)) (call-interactively command)))) +;;;###autoload +(defun project-uniquify-dirname-transform (dirname) + "Include `project-name' in DIRNAME if in a project. + +If you set `uniquify-dirname-transform' to this function, +slash-separated components from `project-name' will be added to +the buffer's name when buffers from two different projects would +otherwise have the same name." + (if-let (proj (project-current nil dirname)) + (let ((root (project-root proj))) + (expand-file-name + (file-name-concat + (file-name-directory root) + (project-name proj) + (file-relative-name dirname root)))) + dirname)) + (provide 'project) ;;; project.el ends here diff --git a/lisp/uniquify.el b/lisp/uniquify.el index d1ca455b673..af00c95663d 100644 --- a/lisp/uniquify.el +++ b/lisp/uniquify.el @@ -168,6 +168,31 @@ uniquify-list-buffers-directory-modes That means that when `buffer-file-name' is set to nil, `list-buffers-directory' contains the name of the directory which the buffer is visiting.") +(defcustom uniquify-dirname-transform #'identity + "Function to transform buffer's directory for uniquifying its name. + +If `uniquify-buffer-name-style' is non-nil and a buffer's name +would be the same as some other buffer, then components from the +buffer's directory name are added to the buffer's name until the +buffer's name is unique. + +This function is used to transform the buffer's directory name +before the uniquifying process, allowing the unique buffer name +to include components from other sources. The default is +`identity', so only the buffer's directory name is used for +uniquifying. This function is called with the buffer's directory +name and should return a file name (which does not need to +actually exist in the filesystem) to use components from. + +To include components from `project-name', set this variable to +`project-uniquify-dirname-transform'." + :type '(choice (function-item :tag "Don't change the dirname" identity) + (function-item :tag "Include project name in dirname" + #'project-uniquify-dirname-transform) + function) + :version "30.1" + :group 'uniquify) + ;;; Utilities ;; uniquify-fix-list data structure @@ -209,7 +234,8 @@ uniquify-rationalize-file-buffer-names ;; this buffer. (with-current-buffer newbuf (setq uniquify-managed nil)) (when dirname - (setq dirname (expand-file-name (directory-file-name dirname))) + (setq dirname (funcall uniquify-dirname-transform + (expand-file-name (directory-file-name dirname)))) (let ((fix-list (list (uniquify-make-item base dirname newbuf nil))) items) @@ -268,10 +294,11 @@ uniquify-buffer-file-name (if (memq major-mode uniquify-list-buffers-directory-modes) list-buffers-directory)))) (when filename - (directory-file-name - (file-name-directory - (expand-file-name - (directory-file-name filename)))))))) + (funcall uniquify-dirname-transform + (directory-file-name + (file-name-directory + (expand-file-name + (directory-file-name filename))))))))) (defun uniquify-rerationalize-w/o-cb (fix-list) "Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'." diff --git a/test/lisp/uniquify-tests.el b/test/lisp/uniquify-tests.el index abd61fa3504..e533c4b644c 100644 --- a/test/lisp/uniquify-tests.el +++ b/test/lisp/uniquify-tests.el @@ -88,6 +88,21 @@ uniquify-dirs '("a/dir/" "b/dir/"))) (mapc #'kill-buffer bufs))))) +(ert-deftest uniquify-home () + "uniquify works, albeit confusingly, in the presence of directories named \"~\"" + (let (bufs) + (save-excursion + (push (find-file-noselect "~") bufs) + (push (find-file-noselect "./~") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("~<test>" "~<>"))) + (push (find-file-noselect "~/foo") bufs) + (push (find-file-noselect "./~/foo") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("foo<~>" "foo</nonexistent>" "~<test>" "~<>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (ert-deftest uniquify-rename-to-dir () "Giving a buffer a name which matches a directory doesn't rename the buffer" (let ((uniquify-buffer-name-style 'forward) @@ -125,5 +140,23 @@ uniquify-space-prefix (should (equal (buffer-name) "| foo")) (kill-buffer))) +(require 'project) +(ert-deftest uniquify-project-transform () + "`project-uniquify-dirname-transform' works" + (let ((uniquify-dirname-transform #'project-uniquify-dirname-transform) + (project-vc-name "foo1/bar") + bufs) + (save-excursion + (should (file-exists-p "../README")) + (push (find-file-noselect "../README") bufs) + (push (find-file-noselect "other/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<other>" "README<bar>"))) + (push (find-file-noselect "foo2/bar/README") bufs) + (should (equal (mapcar #'buffer-name bufs) + '("README<foo2/bar>" "README<other>" "README<foo1/bar>"))) + (while bufs + (kill-buffer (pop bufs)))))) + (provide 'uniquify-tests) ;;; uniquify-tests.el ends here -- 2.39.3 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-24 19:18 ` Spencer Baugh @ 2023-07-26 15:18 ` Eli Zaretskii 2023-08-03 8:00 ` Eli Zaretskii 0 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-07-26 15:18 UTC (permalink / raw) To: Spencer Baugh; +Cc: dmitry, 62621, sbaugh > From: Spencer Baugh <sbaugh@janestreet.com> > Cc: dmitry@gutov.dev, 62621@debbugs.gnu.org, sbaugh@catern.com > Date: Mon, 24 Jul 2023 15:18:23 -0400 > > > OK, how about this? > > Oops, that one didn't include the updated > project-uniquify-dirname-transform docstring. The right patch now: Thanks, installed, with some minor changes as followup. The new test uniquify-home fails for me on MS-Windows: Test uniquify-home backtrace: signal(ert-test-failed (((should (equal (mapcar #'buffer-name bufs) ert-fail(((should (equal (mapcar #'buffer-name bufs) '("~<test>" "~< (if (unwind-protect (setq value-27 (apply fn-25 args-26)) (setq form (let (form-description-29) (if (unwind-protect (setq value-27 (apply (let ((value-27 'ert-form-evaluation-aborted-28)) (let (form-descrip (let* ((fn-25 #'equal) (args-26 (condition-case err (let ((signal-ho (save-excursion (setq bufs (cons (find-file-noselect "~") bufs)) (se (let (bufs) (save-excursion (setq bufs (cons (find-file-noselect "~" (closure (t) nil (let (bufs) (save-excursion (setq bufs (cons (find- ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test ert-run-test(#s(ert-test :name uniquify-home :documentation "uniquif ert-run-or-rerun-test(#s(ert--stats :selector (not ...) :tests [... ert-run-tests((not (or (tag :unstable) (tag :nativecomp))) #f(compil ert-run-tests-batch((not (or (tag :unstable) (tag :nativecomp)))) ert-run-tests-batch-and-exit((not (or (tag :unstable) (tag :nativeco eval((ert-run-tests-batch-and-exit '(not (or (tag :unstable) (tag :n command-line-1(("-L" ";." "-l" "ert" "-l" "lisp/uniquify-tests.el" " command-line() normal-top-level() Test uniquify-home condition: (ert-test-failed ((should (equal (mapcar ... bufs) '("~<test>" "~<>"))) :form (equal ("~" "nonexistent") ("~<test>" "~<>")) :value nil :explanation (list-elt 0 (arrays-of-different-length 1 7 "~" "~<test>" first-mismatch-at 1)))) The idea of the test is not clear to me, so I cannot tell what could be the reasons. Feel free to ask me to test changes or ask questions about what happens on this Windows system while running the test. ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-07-26 15:18 ` Eli Zaretskii @ 2023-08-03 8:00 ` Eli Zaretskii 2023-08-03 11:54 ` Spencer Baugh 0 siblings, 1 reply; 40+ messages in thread From: Eli Zaretskii @ 2023-08-03 8:00 UTC (permalink / raw) To: sbaugh; +Cc: dmitry, 62621, sbaugh Ping! Can this test failure be fixed, please? > Cc: dmitry@gutov.dev, 62621@debbugs.gnu.org, sbaugh@catern.com > Date: Wed, 26 Jul 2023 18:18:25 +0300 > From: Eli Zaretskii <eliz@gnu.org> > > > From: Spencer Baugh <sbaugh@janestreet.com> > > Cc: dmitry@gutov.dev, 62621@debbugs.gnu.org, sbaugh@catern.com > > Date: Mon, 24 Jul 2023 15:18:23 -0400 > > > > > OK, how about this? > > > > Oops, that one didn't include the updated > > project-uniquify-dirname-transform docstring. The right patch now: > > Thanks, installed, with some minor changes as followup. > > The new test uniquify-home fails for me on MS-Windows: > > Test uniquify-home backtrace: > signal(ert-test-failed (((should (equal (mapcar #'buffer-name bufs) > ert-fail(((should (equal (mapcar #'buffer-name bufs) '("~<test>" "~< > (if (unwind-protect (setq value-27 (apply fn-25 args-26)) (setq form > (let (form-description-29) (if (unwind-protect (setq value-27 (apply > (let ((value-27 'ert-form-evaluation-aborted-28)) (let (form-descrip > (let* ((fn-25 #'equal) (args-26 (condition-case err (let ((signal-ho > (save-excursion (setq bufs (cons (find-file-noselect "~") bufs)) (se > (let (bufs) (save-excursion (setq bufs (cons (find-file-noselect "~" > (closure (t) nil (let (bufs) (save-excursion (setq bufs (cons (find- > ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test > ert-run-test(#s(ert-test :name uniquify-home :documentation "uniquif > ert-run-or-rerun-test(#s(ert--stats :selector (not ...) :tests [... > ert-run-tests((not (or (tag :unstable) (tag :nativecomp))) #f(compil > ert-run-tests-batch((not (or (tag :unstable) (tag :nativecomp)))) > ert-run-tests-batch-and-exit((not (or (tag :unstable) (tag :nativeco > eval((ert-run-tests-batch-and-exit '(not (or (tag :unstable) (tag :n > command-line-1(("-L" ";." "-l" "ert" "-l" "lisp/uniquify-tests.el" " > command-line() > normal-top-level() > Test uniquify-home condition: > (ert-test-failed > ((should (equal (mapcar ... bufs) '("~<test>" "~<>"))) :form > (equal ("~" "nonexistent") ("~<test>" "~<>")) :value nil > :explanation > (list-elt 0 > (arrays-of-different-length 1 7 "~" "~<test>" > first-mismatch-at 1)))) > > The idea of the test is not clear to me, so I cannot tell what could > be the reasons. Feel free to ask me to test changes or ask questions > about what happens on this Windows system while running the test. > > > > ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-08-03 8:00 ` Eli Zaretskii @ 2023-08-03 11:54 ` Spencer Baugh 2023-08-03 14:05 ` Eli Zaretskii 0 siblings, 1 reply; 40+ messages in thread From: Spencer Baugh @ 2023-08-03 11:54 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Dmitry Gutov, 62621, Spencer Baugh [-- Attachment #1: Type: text/plain, Size: 2904 bytes --] On reflection that specific test case is of dubious value, and since it's failing on Windows it means the behavior isn't even consistent anyway. So just delete it. On Thu, Aug 3, 2023, 04:00 Eli Zaretskii <eliz@gnu.org> wrote: > Ping! Can this test failure be fixed, please? > > > Cc: dmitry@gutov.dev, 62621@debbugs.gnu.org, sbaugh@catern.com > > Date: Wed, 26 Jul 2023 18:18:25 +0300 > > From: Eli Zaretskii <eliz@gnu.org> > > > > > From: Spencer Baugh <sbaugh@janestreet.com> > > > Cc: dmitry@gutov.dev, 62621@debbugs.gnu.org, sbaugh@catern.com > > > Date: Mon, 24 Jul 2023 15:18:23 -0400 > > > > > > > OK, how about this? > > > > > > Oops, that one didn't include the updated > > > project-uniquify-dirname-transform docstring. The right patch now: > > > > Thanks, installed, with some minor changes as followup. > > > > The new test uniquify-home fails for me on MS-Windows: > > > > Test uniquify-home backtrace: > > signal(ert-test-failed (((should (equal (mapcar #'buffer-name bufs) > > ert-fail(((should (equal (mapcar #'buffer-name bufs) '("~<test>" "~< > > (if (unwind-protect (setq value-27 (apply fn-25 args-26)) (setq form > > (let (form-description-29) (if (unwind-protect (setq value-27 (apply > > (let ((value-27 'ert-form-evaluation-aborted-28)) (let (form-descrip > > (let* ((fn-25 #'equal) (args-26 (condition-case err (let ((signal-ho > > (save-excursion (setq bufs (cons (find-file-noselect "~") bufs)) (se > > (let (bufs) (save-excursion (setq bufs (cons (find-file-noselect "~" > > (closure (t) nil (let (bufs) (save-excursion (setq bufs (cons (find- > > ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test > > ert-run-test(#s(ert-test :name uniquify-home :documentation "uniquif > > ert-run-or-rerun-test(#s(ert--stats :selector (not ...) :tests [... > > ert-run-tests((not (or (tag :unstable) (tag :nativecomp))) #f(compil > > ert-run-tests-batch((not (or (tag :unstable) (tag :nativecomp)))) > > ert-run-tests-batch-and-exit((not (or (tag :unstable) (tag :nativeco > > eval((ert-run-tests-batch-and-exit '(not (or (tag :unstable) (tag :n > > command-line-1(("-L" ";." "-l" "ert" "-l" "lisp/uniquify-tests.el" " > > command-line() > > normal-top-level() > > Test uniquify-home condition: > > (ert-test-failed > > ((should (equal (mapcar ... bufs) '("~<test>" "~<>"))) :form > > (equal ("~" "nonexistent") ("~<test>" "~<>")) :value nil > > :explanation > > (list-elt 0 > > (arrays-of-different-length 1 7 "~" "~<test>" > > first-mismatch-at 1)))) > > > > The idea of the test is not clear to me, so I cannot tell what could > > be the reasons. Feel free to ask me to test changes or ask questions > > about what happens on this Windows system while running the test. > > > > > > > > > [-- Attachment #2: Type: text/html, Size: 4509 bytes --] ^ permalink raw reply [flat|nested] 40+ messages in thread
* bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename 2023-08-03 11:54 ` Spencer Baugh @ 2023-08-03 14:05 ` Eli Zaretskii 0 siblings, 0 replies; 40+ messages in thread From: Eli Zaretskii @ 2023-08-03 14:05 UTC (permalink / raw) To: Spencer Baugh; +Cc: dmitry, 62621-done, sbaugh > From: Spencer Baugh <sbaugh@janestreet.com> > Date: Thu, 3 Aug 2023 07:54:22 -0400 > Cc: Dmitry Gutov <dmitry@gutov.dev>, 62621@debbugs.gnu.org, > Spencer Baugh <sbaugh@catern.com> > > On reflection that specific test case is of dubious value, and since it's failing on Windows it means the > behavior isn't even consistent anyway. So just delete it. Done, and closing the bug. ^ permalink raw reply [flat|nested] 40+ messages in thread
end of thread, other threads:[~2023-08-03 14:05 UTC | newest] Thread overview: 40+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-04-02 17:37 bug#62621: 29.0.60; uniquify can't make buffers unique based on things other than filename Spencer Baugh 2023-04-02 17:57 ` Eli Zaretskii 2023-04-02 21:59 ` Drew Adams 2023-04-02 18:25 ` Juri Linkov 2023-04-14 16:08 ` Spencer Baugh 2023-07-13 22:51 ` sbaugh 2023-07-14 6:29 ` Eli Zaretskii 2023-07-14 11:28 ` sbaugh 2023-07-14 12:01 ` Eli Zaretskii 2023-07-14 12:20 ` Spencer Baugh 2023-07-14 12:29 ` Eli Zaretskii 2023-07-14 12:46 ` Spencer Baugh 2023-07-14 13:51 ` Eli Zaretskii 2023-07-14 14:14 ` Spencer Baugh 2023-07-14 19:10 ` Eli Zaretskii 2023-07-14 19:15 ` sbaugh 2023-07-15 5:42 ` Eli Zaretskii 2023-07-15 6:20 ` Eli Zaretskii 2023-07-18 0:19 ` Dmitry Gutov 2023-07-18 1:37 ` Dmitry Gutov 2023-07-18 16:03 ` Spencer Baugh 2023-07-19 2:47 ` Dmitry Gutov 2023-07-19 6:56 ` Juri Linkov 2023-07-18 17:51 ` Juri Linkov 2023-07-19 2:24 ` Dmitry Gutov 2023-07-14 16:31 ` Juri Linkov 2023-07-18 0:34 ` Dmitry Gutov 2023-07-18 11:07 ` Eli Zaretskii 2023-07-19 2:22 ` Dmitry Gutov 2023-07-19 12:14 ` Eli Zaretskii 2023-07-19 12:31 ` Spencer Baugh 2023-07-19 13:25 ` Eli Zaretskii 2023-07-21 13:34 ` Spencer Baugh 2023-07-21 14:37 ` Eli Zaretskii 2023-07-22 18:00 ` Spencer Baugh 2023-07-24 19:18 ` Spencer Baugh 2023-07-26 15:18 ` Eli Zaretskii 2023-08-03 8:00 ` Eli Zaretskii 2023-08-03 11:54 ` Spencer Baugh 2023-08-03 14:05 ` Eli Zaretskii
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.