GNU bug report logs - #77312
[PATCH] Add uniquify-get-unique-names

Previous Next

Package: emacs;

Reported by: Spencer Baugh <sbaugh <at> janestreet.com>

Date: Thu, 27 Mar 2025 15:04:03 UTC

Severity: normal

Tags: patch

Done: Dmitry Gutov <dmitry <at> gutov.dev>

To reply to this bug, email your comments to 77312 AT debbugs.gnu.org.
There is no need to reopen the bug first.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to dmitry <at> gutov.dev, bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Thu, 27 Mar 2025 15:04:03 GMT) Full text and rfc822 format available.

Acknowledgement sent to Spencer Baugh <sbaugh <at> janestreet.com>:
New bug report received and forwarded. Copy sent to dmitry <at> gutov.dev, bug-gnu-emacs <at> gnu.org. (Thu, 27 Mar 2025 15:04:03 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: bug-gnu-emacs <at> gnu.org
Subject: [PATCH] Add uniquify-get-unique-names
Date: Thu, 27 Mar 2025 11:03:17 -0400
[Message part 1 (text/plain, inline)]
Tags: patch


This new function provides an interface to uniquify.el which doesn't
change the actual names of the buffers.  This is useful for any commands
which deal with a subset of all buffers; for example, project.el.

* lisp/uniquify.el (uniquify-rationalize--generic): Add.
(uniquify-rationalize, uniquify-rationalize-a-list)
(uniquify-rationalize-conflicting-sublist): Explicitly pass
RENAME-BUFFER-FN and GET-BUFFER-FN.
(uniquify--stateless-curname, uniquify-get-unique-names): Add.

In GNU Emacs 30.1.50 (build 1, x86_64-pc-linux-gnu, X toolkit, cairo
 version 1.15.12, Xaw scroll bars) of 2025-03-11 built on
 igm-qws-u22796a
Repository revision: 516d1e6463a9659951f7567e038efc5ee2a19bbf
Windowing system distributor 'The X.Org Foundation', version 11.0.12011000
System Description: Rocky Linux 8.10 (Green Obsidian)

Configured using:
 'configure --config-cache --with-x-toolkit=lucid --without-gpm
 --without-gconf --without-selinux --without-imagemagick --with-modules
 --with-gif=no --with-cairo --with-rsvg --without-compress-install
 --with-tree-sitter --with-native-compilation=aot
 --prefix=/usr/local/home/garnish/raw-emacs/30-20250311_131404'

[0001-Add-uniquify-get-unique-names.patch (text/patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Fri, 28 Mar 2025 18:52:02 GMT) Full text and rfc822 format available.

Message #8 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: 77312 <at> debbugs.gnu.org
Cc: dmitry <at> gutov.dev
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Fri, 28 Mar 2025 14:50:59 -0400
[Message part 1 (text/plain, inline)]
After some use, it seems better to return an alist rather than a hash
table from this function; that alist is in the same order as the buffer
list that was passed in, which is nice for completion.  So here's a
version which does that.

[0001-Add-uniquify-get-unique-names.patch (text/x-patch, inline)]
From 62ff7104ff2cc0ab5a258c2cd83d1278bc804961 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh <at> janestreet.com>
Date: Thu, 27 Mar 2025 09:32:47 -0400
Subject: [PATCH] Add uniquify-get-unique-names

This new function provides an interface to uniquify.el which doesn't
change the actual names of the buffers.  This is useful for any commands
which deal with a subset of all buffers; for example, project.el.

* lisp/uniquify.el (uniquify-rationalize--generic): Add.
(uniquify-rationalize, uniquify-rationalize-a-list)
(uniquify-rationalize-conflicting-sublist): Explicitly pass
RENAME-BUFFER-FN and GET-BUFFER-FN.
(uniquify--stateless-curname, uniquify-get-unique-names): Add.
---
 lisp/uniquify.el | 66 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 55 insertions(+), 11 deletions(-)

diff --git a/lisp/uniquify.el b/lisp/uniquify.el
index 358ae6af651..ac60228d9d8 100644
--- a/lisp/uniquify.el
+++ b/lisp/uniquify.el
@@ -320,14 +320,19 @@ uniquify-rerationalize-w/o-cb
 (defun uniquify-rationalize (fix-list)
   ;; Set up uniquify to re-rationalize after killing/renaming
   ;; if there is a conflict.
+  (dolist (item fix-list)
+    (with-current-buffer (uniquify-item-buffer item)
+      (setq uniquify-managed fix-list)))
+  (uniquify-rationalize--generic fix-list #'uniquify-rename-buffer #'get-buffer))
+
+(defun uniquify-rationalize--generic (fix-list rename-buffer-fn get-buffer-fn)
   (dolist (item fix-list)
     (with-current-buffer (uniquify-item-buffer item)
       ;; Refresh the dirnames and proposed names.
       (setf (uniquify-item-proposed item)
 	    (uniquify-get-proposed-name (uniquify-item-base item)
 					(uniquify-item-dirname item)
-                                        nil))
-      (setq uniquify-managed fix-list)))
+                                        nil))))
   ;; Strip any shared last directory names of the dirname.
   (when (and (cdr fix-list) uniquify-strip-common-suffix)
     (let ((strip t))
@@ -353,13 +358,13 @@ uniquify-rationalize
 		fix-list)))))
   ;; If uniquify-min-dir-content is 0, this will end up just
   ;; passing fix-list to uniquify-rationalize-conflicting-sublist.
-  (uniquify-rationalize-a-list fix-list))
+  (uniquify-rationalize-a-list fix-list nil rename-buffer-fn get-buffer-fn))
 
 (defun uniquify-item-greaterp (item1 item2)
   (string-lessp (uniquify-item-proposed item2)
 		(uniquify-item-proposed item1)))
 
-(defun uniquify-rationalize-a-list (fix-list &optional depth)
+(defun uniquify-rationalize-a-list (fix-list depth rename-buffer-fn get-buffer-fn)
   (unless depth (setq depth uniquify-min-dir-content))
   (let (conflicting-sublist	; all elements have the same proposed name
 	(old-proposed "")
@@ -370,12 +375,14 @@ uniquify-rationalize-a-list
       (setq proposed (uniquify-item-proposed item))
       (unless (equal proposed old-proposed)
 	(uniquify-rationalize-conflicting-sublist conflicting-sublist
-						  old-proposed depth)
+						  old-proposed depth
+                                                  rename-buffer-fn get-buffer-fn)
 	(setq conflicting-sublist nil))
       (push item conflicting-sublist)
       (setq old-proposed proposed))
     (uniquify-rationalize-conflicting-sublist conflicting-sublist
-					      old-proposed depth)))
+					      old-proposed depth
+                                              rename-buffer-fn get-buffer-fn)))
 
 (defun uniquify-get-proposed-name (base dirname &optional depth)
   (unless depth (setq depth uniquify-min-dir-content))
@@ -427,12 +434,12 @@ uniquify-get-proposed-name
 
 ;; Deal with conflicting-sublist, all of whose elements have identical
 ;; "base" components.
-(defun uniquify-rationalize-conflicting-sublist (conf-list old-name depth)
+(defun uniquify-rationalize-conflicting-sublist (conf-list old-name depth rename-buffer-fn get-buffer-fn)
   (when conf-list
     (if (or (cdr conf-list)
 	    ;; Check that the proposed name doesn't conflict with some
 	    ;; existing buffer.
-	    (let ((buf (get-buffer old-name)))
+	    (let ((buf (funcall get-buffer-fn old-name)))
 	      (and buf (not (eq buf (uniquify-item-buffer (car conf-list)))))))
 	(when uniquify-possibly-resolvable
 	  (setq uniquify-possibly-resolvable nil
@@ -443,10 +450,9 @@ uniquify-rationalize-conflicting-sublist
 		   (uniquify-item-base item)
 		   (uniquify-item-dirname item)
 		   depth)))
-	  (uniquify-rationalize-a-list conf-list depth))
+	  (uniquify-rationalize-a-list conf-list depth rename-buffer-fn get-buffer-fn))
       (unless (string= old-name "")
-	(uniquify-rename-buffer (car conf-list) old-name)))))
-
+	(funcall rename-buffer-fn (car conf-list) old-name)))))
 
 (defun uniquify-rename-buffer (item newname)
   (let ((buffer (uniquify-item-buffer item)))
@@ -456,6 +462,44 @@ uniquify-rename-buffer
 	  ;; Pass the `unique' arg, so the advice doesn't mark it as unmanaged.
 	  (rename-buffer newname t))))))
 
+(defvar-local uniquify--stateless-curname nil
+  "The current unique name of this buffer in `uniquify-get-unique-names'.")
+
+(defun uniquify-get-unique-names (buffers)
+  "Return an alist with a unique name for each buffer in BUFFERS.
+
+The names are unique only among BUFFERS, and may conflict with other
+buffers not in that list.
+
+This does not rename the buffers or change any state; the unique name is
+only present in the returned alist."
+  (let ((buffer-names (make-hash-table :size (length buffers) :test 'equal))
+        fix-lists-by-base)
+    (dolist (buf buffers)
+      (with-current-buffer buf
+        (setq uniquify--stateless-curname (buffer-name buf))
+        (puthash (buffer-name buf) buf buffer-names)
+        (when uniquify-managed
+          (let ((base (uniquify-item-base (car uniquify-managed))))
+            (push
+             (uniquify-make-item base (uniquify-buffer-file-name buf) buf nil)
+             (alist-get base fix-lists-by-base nil nil #'equal))))))
+    (dolist (pair fix-lists-by-base)
+      (uniquify-rationalize--generic
+       (cdr pair)
+       (lambda (item name)              ; rename-buffer
+         (with-current-buffer (uniquify-item-buffer item)
+           (remhash uniquify--stateless-curname buffer-names)
+           (setq uniquify--stateless-curname name)
+           (puthash name (current-buffer) buffer-names)))
+       (lambda (name)                   ; get-buffer
+         (gethash name buffer-names)))))
+  (mapcar (lambda (buf)
+            (with-current-buffer buf
+              (prog1 (cons uniquify--stateless-curname buf)
+                (kill-local-variable 'uniquify--stateless-curname))))
+          buffers))
+
 ;;; Hooks from the rest of Emacs
 
 (defun uniquify-maybe-rerationalize-w/o-cb ()
-- 
2.39.3


Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Mon, 31 Mar 2025 19:59:02 GMT) Full text and rfc822 format available.

Message #11 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dmitry <at> gutov.dev>
To: Spencer Baugh <sbaugh <at> janestreet.com>, 77312 <at> debbugs.gnu.org
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Mon, 31 Mar 2025 22:58:19 +0300
[Message part 1 (text/plain, inline)]
Hi all,

On 28/03/2025 20:50, Spencer Baugh wrote:
> After some use, it seems better to return an alist rather than a hash
> table from this function; that alist is in the same order as the buffer
> list that was passed in, which is nice for completion.  So here's a
> version which does that.

Here's the corresponding patch to project.el to use the new function.

The use of new logic is predicated on the non-nil value of 
uniquify-buffer-name-style. The latter doesn't necessarily imply that 
the user wants the former, but seems a safe enough bet.
[project--read-project-buffer-reuniquify.diff (text/x-patch, attachment)]

Reply sent to Dmitry Gutov <dmitry <at> gutov.dev>:
You have taken responsibility. (Fri, 06 Jun 2025 02:46:02 GMT) Full text and rfc822 format available.

Notification sent to Spencer Baugh <sbaugh <at> janestreet.com>:
bug acknowledged by developer. (Fri, 06 Jun 2025 02:46:02 GMT) Full text and rfc822 format available.

Message #16 received at 77312-done <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dmitry <at> gutov.dev>
To: Spencer Baugh <sbaugh <at> janestreet.com>, 77312-done <at> debbugs.gnu.org
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Fri, 6 Jun 2025 05:45:22 +0300
On 31/03/2025 22:58, Dmitry Gutov wrote:
> Here's the corresponding patch to project.el to use the new function.
> 
> The use of new logic is predicated on the non-nil value of uniquify- 
> buffer-name-style. The latter doesn't necessarily imply that the user 
> wants the former, but seems a safe enough bet.

No further comments from anybody, so I've pushed the two patches and am 
closing the bug.

If anybody dislikes the change in project-switch-to-buffer's behavior, 
let me know.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Sat, 07 Jun 2025 08:12:01 GMT) Full text and rfc822 format available.

Message #19 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Daniel Mendler <mail <at> daniel-mendler.de>
To: 77312 <at> debbugs.gnu.org
Cc: dmitry <at> gutov.dev, sbaugh <at> janestreet.com
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Sat, 07 Jun 2025 10:11:42 +0200
Hello Dmitry!

Dmitry Gutov <dmitry <at> gutov.dev> writes:
> On 31/03/2025 22:58, Dmitry Gutov wrote:
>> Here's the corresponding patch to project.el to use the new function.
>> The use of new logic is predicated on the non-nil value of uniquify-
>> buffer-name-style. The latter doesn't necessarily imply that the user wants
>> the former, but seems a safe enough bet.
>
> No further comments from anybody, so I've pushed the two patches and am closing
> the bug.
>
> If anybody dislikes the change in project-switch-to-buffer's behavior, let me
> know.

Would it be possible to attach the buffer object or the original buffer
name to the completion candidate string as text property? This would
make it possible to attach annotations via Marginalia or to execute
buffer actions via Embark. Otherwise I don't see a possibility to access
the original buffer, since they are only present in the `unique-names`
alist local variable.

Daniel




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Sun, 08 Jun 2025 02:07:02 GMT) Full text and rfc822 format available.

Message #22 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dmitry <at> gutov.dev>
To: Daniel Mendler <mail <at> daniel-mendler.de>, 77312 <at> debbugs.gnu.org
Cc: sbaugh <at> janestreet.com
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Sun, 8 Jun 2025 05:06:36 +0300
Hey Daniel!

On 07/06/2025 11:11, Daniel Mendler wrote:
> Would it be possible to attach the buffer object or the original buffer
> name to the completion candidate string as text property? This would
> make it possible to attach annotations via Marginalia or to execute
> buffer actions via Embark. Otherwise I don't see a possibility to access
> the original buffer, since they are only present in the `unique-names`
> alist local variable.

That makes sense. Just call the property 'buffer'?

I wonder if it would make sense to alter the calling convention for 
uniquify-get-unique-names itself to return a list of propertized strings 
instead. project--read-project-buffer can do the conversion (copy each 
string and attach the property), but it's just extra consing.

Unless some more new callers are going to prefer the current convention.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Sun, 08 Jun 2025 05:42:01 GMT) Full text and rfc822 format available.

Message #25 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Daniel Mendler <mail <at> daniel-mendler.de>
To: Dmitry Gutov <dmitry <at> gutov.dev>
Cc: sbaugh <at> janestreet.com, 77312 <at> debbugs.gnu.org
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Sun, 08 Jun 2025 07:41:19 +0200
Dmitry Gutov <dmitry <at> gutov.dev> writes:

> Hey Daniel!
>
> On 07/06/2025 11:11, Daniel Mendler wrote:
>> Would it be possible to attach the buffer object or the original buffer
>> name to the completion candidate string as text property? This would
>> make it possible to attach annotations via Marginalia or to execute
>> buffer actions via Embark. Otherwise I don't see a possibility to access
>> the original buffer, since they are only present in the `unique-names`
>> alist local variable.
>
> That makes sense. Just call the property 'buffer'?

That would work. I prefer a more specific property name to ease
grepping/debugging. Also see below regarding the consing.

> I wonder if it would make sense to alter the calling convention for
> uniquify-get-unique-names itself to return a list of propertized strings
> instead. project--read-project-buffer can do the conversion (copy each string
> and attach the property), but it's just extra consing.

I haven't checked if the current function is already working hard to
avoid unnecessary allocations. If yes, it would be wasteful to add extra
string allocations.

In order to avoid them, we could only attach the property if the buffer
name has really changed, such that no strings have to be copied. The
property could be called `uniquify-orig-buffer-name`. If the property is
present, it holds the original buffer name, if it is not present the
string itself is the original buffer name.

> Unless some more new callers are going to prefer the current convention.

Both would be fine for me. Generally I think it is nice to push
functionality to the lower level API, as long as the functionality is
generic enough.

Btw, would you be interested in having `uniquify-get-unique-names' in
Compat, such that you avoid the fboundp check? project.el would have to
depend on Compat for that, but that's essentially free on Emacs 30 and
newer.

Daniel




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Tue, 10 Jun 2025 02:52:04 GMT) Full text and rfc822 format available.

Message #28 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dmitry <at> gutov.dev>
To: Daniel Mendler <mail <at> daniel-mendler.de>
Cc: sbaugh <at> janestreet.com, 77312 <at> debbugs.gnu.org
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Tue, 10 Jun 2025 05:51:29 +0300
On 08/06/2025 08:41, Daniel Mendler wrote:

>> On 07/06/2025 11:11, Daniel Mendler wrote:
>>> Would it be possible to attach the buffer object or the original buffer
>>> name to the completion candidate string as text property? This would
>>> make it possible to attach annotations via Marginalia or to execute
>>> buffer actions via Embark. Otherwise I don't see a possibility to access
>>> the original buffer, since they are only present in the `unique-names`
>>> alist local variable.
>>
>> That makes sense. Just call the property 'buffer'?
> 
> That would work. I prefer a more specific property name to ease
> grepping/debugging. Also see below regarding the consing.

All right.

>> I wonder if it would make sense to alter the calling convention for
>> uniquify-get-unique-names itself to return a list of propertized strings
>> instead. project--read-project-buffer can do the conversion (copy each string
>> and attach the property), but it's just extra consing.
> 
> I haven't checked if the current function is already working hard to
> avoid unnecessary allocations. If yes, it would be wasteful to add extra
> string allocations.

Also when you provide the same information via different ways, over time 
they tend to get out of sync. The simpler the better.

> In order to avoid them, we could only attach the property if the buffer
> name has really changed, such that no strings have to be copied. The
> property could be called `uniquify-orig-buffer-name`. If the property is
> present, it holds the original buffer name, if it is not present the
> string itself is the original buffer name.

Yeah, that's a good idea.

> Btw, would you be interested in having `uniquify-get-unique-names' in
> Compat, such that you avoid the fboundp check? project.el would have to
> depend on Compat for that, but that's essentially free on Emacs 30 and
> newer.

I usually try to avoid extra deps, but this can make sense, at least for 
users of Emacs>30. Especially if it leads to simplification in multiple 
places.

Can you see other compatibility checks we could forgo this way? Offhand, 
I see another fboundp in 'project-ignores' (default definition) and a 
version< inside 'project-list-buffers-buffer-menu'.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Tue, 10 Jun 2025 03:15:05 GMT) Full text and rfc822 format available.

Message #31 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Daniel Mendler <mail <at> daniel-mendler.de>
To: Dmitry Gutov <dmitry <at> gutov.dev>
Cc: sbaugh <at> janestreet.com, 77312 <at> debbugs.gnu.org
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Tue, 10 Jun 2025 05:14:28 +0200
Dmitry Gutov <dmitry <at> gutov.dev> writes:

>> Btw, would you be interested in having `uniquify-get-unique-names' in
>> Compat, such that you avoid the fboundp check? project.el would have to
>> depend on Compat for that, but that's essentially free on Emacs 30 and
>> newer.
>
> I usually try to avoid extra deps, but this can make sense, at least for users
> of Emacs>30. Especially if it leads to simplification in multiple places.

I also find it good to avoid extra deps, in particular if they introduce
their own idioms. Compat doesn't invent functionality, it just provides
some APIs from the latest stable Emacs versions, so it will help keeping
your code up to date. Compat is made such that the dependency cost is
minimized, since it is not installed if Emacs is sufficiently new.

> Can you see other compatibility checks we could forgo this way? Offhand, I see
> another fboundp in 'project-ignores' (default definition) and a version< inside
> 'project-list-buffers-buffer-menu'.

I think these checks cannot be avoided. But you could start using some
new functions or macros like `defvar-keymap'. See the Compat manual for
a list of backported functionality.

Daniel




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Tue, 10 Jun 2025 15:06:03 GMT) Full text and rfc822 format available.

Message #34 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: Daniel Mendler <mail <at> daniel-mendler.de>
Cc: Dmitry Gutov <dmitry <at> gutov.dev>, 77312 <at> debbugs.gnu.org
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Tue, 10 Jun 2025 11:05:06 -0400
Daniel Mendler <mail <at> daniel-mendler.de> writes:

> Dmitry Gutov <dmitry <at> gutov.dev> writes:
>
>> Hey Daniel!
>>
>> On 07/06/2025 11:11, Daniel Mendler wrote:
>>> Would it be possible to attach the buffer object or the original buffer
>>> name to the completion candidate string as text property? This would
>>> make it possible to attach annotations via Marginalia or to execute
>>> buffer actions via Embark. Otherwise I don't see a possibility to access
>>> the original buffer, since they are only present in the `unique-names`
>>> alist local variable.
>>
>> That makes sense. Just call the property 'buffer'?
>
> That would work. I prefer a more specific property name to ease
> grepping/debugging. Also see below regarding the consing.
>
>> I wonder if it would make sense to alter the calling convention for
>> uniquify-get-unique-names itself to return a list of propertized strings
>> instead. project--read-project-buffer can do the conversion (copy each string
>> and attach the property), but it's just extra consing.
>
> I haven't checked if the current function is already working hard to
> avoid unnecessary allocations. If yes, it would be wasteful to add extra
> string allocations.
>
> In order to avoid them, we could only attach the property if the buffer
> name has really changed, such that no strings have to be copied. The
> property could be called `uniquify-orig-buffer-name`. If the property is
> present, it holds the original buffer name, if it is not present the
> string itself is the original buffer name.

All else being equal, I think changing uniquify-get-unique-names to
return a list of strings which have the original buffer names as a
property is a reasonable and easy thing to do.  uniquify.el is generally
pretty allocation heavy, so I wouldn't worry about the excess
allocations, just stick the property on all the returned strings.

Also, some future work I was considering, which I hope we can
accomodate: making this be internal functionality of read-buffer.  That
is, when read-buffer is passed a predicate, it could:
- use the predicate to filter the buffers
- then use uniquify-get-unique-names to get less-verbose buffer names
- then call completing-read with those buffer names
I think the text property approach would indeed work with this, but just
mentioning it.

Some unnecessary speculation about alternatives to the text property
approach follows:

One alternative to the text property approach is to have the alist
returned by uniquify-get-unique-names be let-bound in some special
variable around the call to completing-read.  Then Embark/Marginalia
could look up strings in that alist to figure out the underlying buffer
that a string is referring to.

Or, we could have a completion table action (ACTION='get-buffer or
something) which ignores PRED and returns the buffer corresponding to
the passed in STRING.  No new special variables at all.

I am reminded of the perennial discussions about how completing-read is
an API for "read string with completion", not "select a value by its
string name from a set of possible values", maybe this would be useful
for that...)

>> Unless some more new callers are going to prefer the current convention.
>
> Both would be fine for me. Generally I think it is nice to push
> functionality to the lower level API, as long as the functionality is
> generic enough.
>
> Btw, would you be interested in having `uniquify-get-unique-names' in
> Compat, such that you avoid the fboundp check? project.el would have to
> depend on Compat for that, but that's essentially free on Emacs 30 and
> newer.

I think adding uniquify-get-unique-names to compat might be difficult
because it depends on non-trivial changes to the rest of the code in
uniquify.el.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Tue, 10 Jun 2025 16:55:03 GMT) Full text and rfc822 format available.

Message #37 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Daniel Mendler <mail <at> daniel-mendler.de>
To: Spencer Baugh via "Bug reports for GNU Emacs, the Swiss army knife of
 text editors" <bug-gnu-emacs <at> gnu.org>
Cc: Spencer Baugh <sbaugh <at> janestreet.com>, 77312 <at> debbugs.gnu.org,
 Dmitry Gutov <dmitry <at> gutov.dev>
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Tue, 10 Jun 2025 18:54:12 +0200
Spencer Baugh via "Bug reports for GNU Emacs, the Swiss army knife of
text editors" <bug-gnu-emacs <at> gnu.org> writes:

> Daniel Mendler <mail <at> daniel-mendler.de> writes:
>
>> Dmitry Gutov <dmitry <at> gutov.dev> writes:
>>
>>> Hey Daniel!
>>>
>>> On 07/06/2025 11:11, Daniel Mendler wrote:
>>>> Would it be possible to attach the buffer object or the original buffer
>>>> name to the completion candidate string as text property? This would
>>>> make it possible to attach annotations via Marginalia or to execute
>>>> buffer actions via Embark. Otherwise I don't see a possibility to access
>>>> the original buffer, since they are only present in the `unique-names`
>>>> alist local variable.
>>>
>>> That makes sense. Just call the property 'buffer'?
>>
>> That would work. I prefer a more specific property name to ease
>> grepping/debugging. Also see below regarding the consing.
>>
>>> I wonder if it would make sense to alter the calling convention for
>>> uniquify-get-unique-names itself to return a list of propertized strings
>>> instead. project--read-project-buffer can do the conversion (copy each string
>>> and attach the property), but it's just extra consing.
>>
>> I haven't checked if the current function is already working hard to
>> avoid unnecessary allocations. If yes, it would be wasteful to add extra
>> string allocations.
>>
>> In order to avoid them, we could only attach the property if the buffer
>> name has really changed, such that no strings have to be copied. The
>> property could be called `uniquify-orig-buffer-name`. If the property is
>> present, it holds the original buffer name, if it is not present the
>> string itself is the original buffer name.
>
> All else being equal, I think changing uniquify-get-unique-names to
> return a list of strings which have the original buffer names as a
> property is a reasonable and easy thing to do.  uniquify.el is generally
> pretty allocation heavy, so I wouldn't worry about the excess
> allocations, just stick the property on all the returned strings.

Okay.

> Some unnecessary speculation about alternatives to the text property
> approach follows:
>
> One alternative to the text property approach is to have the alist
> returned by uniquify-get-unique-names be let-bound in some special
> variable around the call to completing-read.  Then Embark/Marginalia
> could look up strings in that alist to figure out the underlying buffer
> that a string is referring to.

Yes, this would work too. Or more ideally set a local variable in the
minibuffer setup hook, since then buffer unification can be detected by
checking if the variable is non-nil.

>>> Unless some more new callers are going to prefer the current convention.
>>
>> Both would be fine for me. Generally I think it is nice to push
>> functionality to the lower level API, as long as the functionality is
>> generic enough.
>>
>> Btw, would you be interested in having `uniquify-get-unique-names' in
>> Compat, such that you avoid the fboundp check? project.el would have to
>> depend on Compat for that, but that's essentially free on Emacs 30 and
>> newer.
>
> I think adding uniquify-get-unique-names to compat might be difficult
> because it depends on non-trivial changes to the rest of the code in
> uniquify.el.

That's unfortunate. I have not looked in detail at it, but if the effort
is disproportionate, and half of uniquify.el would need to be
replicated, then we cannot port it back as part of Compat.

Daniel




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Tue, 10 Jun 2025 16:55:04 GMT) Full text and rfc822 format available.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77312; Package emacs. (Tue, 10 Jun 2025 17:05:02 GMT) Full text and rfc822 format available.

Message #43 received at 77312 <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: Daniel Mendler <mail <at> daniel-mendler.de>
Cc: dmitry <at> gutov.dev, 77312 <at> debbugs.gnu.org
Subject: Re: bug#77312: [PATCH] Add uniquify-get-unique-names
Date: Tue, 10 Jun 2025 13:03:53 -0400
Daniel Mendler <mail <at> daniel-mendler.de> writes:
> Spencer Baugh via "Bug reports for GNU Emacs, the Swiss army knife of
> text editors" <bug-gnu-emacs <at> gnu.org> writes:
>
>> Daniel Mendler <mail <at> daniel-mendler.de> writes:
>>
>>> Dmitry Gutov <dmitry <at> gutov.dev> writes:
>>>
>>>> Hey Daniel!
>>>>
>>>> On 07/06/2025 11:11, Daniel Mendler wrote:
>>>>> Would it be possible to attach the buffer object or the original buffer
>>>>> name to the completion candidate string as text property? This would
>>>>> make it possible to attach annotations via Marginalia or to execute
>>>>> buffer actions via Embark. Otherwise I don't see a possibility to access
>>>>> the original buffer, since they are only present in the `unique-names`
>>>>> alist local variable.
>>>>
>>>> That makes sense. Just call the property 'buffer'?
>>>
>>> That would work. I prefer a more specific property name to ease
>>> grepping/debugging. Also see below regarding the consing.
>>>
>>>> I wonder if it would make sense to alter the calling convention for
>>>> uniquify-get-unique-names itself to return a list of propertized strings
>>>> instead. project--read-project-buffer can do the conversion (copy each string
>>>> and attach the property), but it's just extra consing.
>>>
>>> I haven't checked if the current function is already working hard to
>>> avoid unnecessary allocations. If yes, it would be wasteful to add extra
>>> string allocations.
>>>
>>> In order to avoid them, we could only attach the property if the buffer
>>> name has really changed, such that no strings have to be copied. The
>>> property could be called `uniquify-orig-buffer-name`. If the property is
>>> present, it holds the original buffer name, if it is not present the
>>> string itself is the original buffer name.
>>
>> All else being equal, I think changing uniquify-get-unique-names to
>> return a list of strings which have the original buffer names as a
>> property is a reasonable and easy thing to do.  uniquify.el is generally
>> pretty allocation heavy, so I wouldn't worry about the excess
>> allocations, just stick the property on all the returned strings.
>
> Okay.

Er, sorry, crucial typo/miscommunication here: I think
uniquify-get-unique-names should return a list of strings, each of which
has a text property containing the original *buffer*.  Not the original
buffer name - the buffer itself.  That would just be slightly more
efficient.

>
>> Some unnecessary speculation about alternatives to the text property
>> approach follows:
>>
>> One alternative to the text property approach is to have the alist
>> returned by uniquify-get-unique-names be let-bound in some special
>> variable around the call to completing-read.  Then Embark/Marginalia
>> could look up strings in that alist to figure out the underlying buffer
>> that a string is referring to.
>
> Yes, this would work too. Or more ideally set a local variable in the
> minibuffer setup hook, since then buffer unification can be detected by
> checking if the variable is non-nil.

Ah right, because otherwise a recursive edit could cause problems... so
a local variable set in the minibuffer setup hook would indeed be
bettter.

>>>> Unless some more new callers are going to prefer the current convention.
>>>
>>> Both would be fine for me. Generally I think it is nice to push
>>> functionality to the lower level API, as long as the functionality is
>>> generic enough.
>>>
>>> Btw, would you be interested in having `uniquify-get-unique-names' in
>>> Compat, such that you avoid the fboundp check? project.el would have to
>>> depend on Compat for that, but that's essentially free on Emacs 30 and
>>> newer.
>>
>> I think adding uniquify-get-unique-names to compat might be difficult
>> because it depends on non-trivial changes to the rest of the code in
>> uniquify.el.
>
> That's unfortunate. I have not looked in detail at it, but if the effort
> is disproportionate, and half of uniquify.el would need to be
> replicated, then we cannot port it back as part of Compat.

Yep.  Maybe about 120 lines would need to be replicated.




This bug report was last modified 4 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.