Subject: bug#77312: [PATCH] Add uniquify-get-unique-names

From: Dmitry Gutov <[email-masked]>
Date: Fri, 20 Jun 2025 06:08:12 +0300

On 10/06/2025 18:05, Spencer Baugh wrote:
>> 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.

Here's how the change can look.

It actually increases consing a bit further, though like mentioned it 
probably doesn't matter:

- Added copy-sequence because I'm not sure if 
'uniquify--stateless-curname' always returns a new string (and never the 
original buffer name string object).
- project--read-project-buffer converts the list to alist anyway, to 
avoid having two different bindings for PREDICATE.

diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 5cf9a68a294..0471daa55b7 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1580,7 +1580,14 @@ project--read-project-buffer
                    uniquify-buffer-name-style)
               ;; Forgo the use of `buffer-read-function' (often nil) in
               ;; favor of uniquifying the buffers better.
-              (let* ((unique-names (uniquify-get-unique-names buffers))
+              (let* ((unique-names
+                      (mapcar
+                       (lambda (name)
+                         (cons name
+                               (and name
+                                    (get-text-property 0 'uniquify-orig-buffer-name
+                                                       name))))
+                       (uniquify-get-unique-names buffers)))
                      (other-name (when (funcall predicate (cons other-name other-buffer))
                                    (car (rassoc other-buffer unique-names))))
                      (result (completing-read
diff --git a/lisp/uniquify.el b/lisp/uniquify.el
index 6e25323bf5a..67cf346d204 100644
--- a/lisp/uniquify.el
+++ b/lisp/uniquify.el
@@ -517,10 +517,11 @@ uniquify--stateless-curname
   "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.
+  "Return a list with unique names for buffers in BUFFERS.
 
 The names are unique only among BUFFERS, and may conflict with other
-buffers not in that list.
+buffers not in that list.  Each string has a text property
+`uniquify-orig-buffer-name' that stores the corresponding buffer.
 
 This does not rename the buffers or change any state; the unique name is
 only present in the returned alist."
@@ -547,8 +548,11 @@ uniquify-get-unique-names
          (gethash name buffer-names)))))
   (mapcar (lambda (buf)
             (with-current-buffer buf
-              (prog1 (cons uniquify--stateless-curname buf)
-                (kill-local-variable 'uniquify--stateless-curname))))
+              (let ((name (copy-sequence uniquify--stateless-curname)))
+                (when name
+                  (put-text-property 0 1 'uniquify-orig-buffer-name buf name))
+                (kill-local-variable 'uniquify--stateless-curname)
+                name)))
           buffers))
 
 ;;; Hooks from the rest of Emacs