GNU bug report logs -
#77312
[PATCH] Add uniquify-get-unique-names
Previous Next
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>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 77312 in the body.
You can then email your comments to 77312 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
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):
[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):
[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):
[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):
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):
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):
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):
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):
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):
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):
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):
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):
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.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Fri, 20 Jun 2025 03:09:01 GMT)
Full text and
rfc822 format available.
Message #46 received at 77312 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
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.
[uniquify-get-unique-buffers-with-textprop.diff (text/x-patch, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Fri, 20 Jun 2025 07:23:05 GMT)
Full text and
rfc822 format available.
Message #49 received at 77312 <at> debbugs.gnu.org (full text, mbox):
> Cc: 77312 <at> debbugs.gnu.org
> Date: Fri, 20 Jun 2025 06:08:12 +0300
> From: Dmitry Gutov <dmitry <at> gutov.dev>
>
> 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
If you decide to install this, please be sure to document this special
text property in the ELisp manual.
Thanks.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Fri, 20 Jun 2025 09:13:02 GMT)
Full text and
rfc822 format available.
Message #52 received at 77312 <at> debbugs.gnu.org (full text, mbox):
Dmitry Gutov <dmitry <at> gutov.dev> writes:
> 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).
Okay, maybe copying the string could be avoided by checking (equal
(buffer-name buf) uniquify--stateless-curname)?
I wonder why you called the property `uniquify-orig-buffer-name' instead
of `uniquify-orig-buffer', since it carries a buffer object?
Thanks!
Daniel
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Sat, 21 Jun 2025 02:28:04 GMT)
Full text and
rfc822 format available.
Message #55 received at 77312 <at> debbugs.gnu.org (full text, mbox):
On 20/06/2025 12:12, Daniel Mendler wrote:
> Okay, maybe copying the string could be avoided by checking (equal
Maybe you meant the 'eq' check.
> (buffer-name buf) uniquify--stateless-curname)?
Hmm, okay. Should we worry about different callers of this seeing
modified strings cached in the uniquify-managed variable?
Maybe not - hard to imagine actual problem scenarios.
> I wonder why you called the property `uniquify-orig-buffer-name' instead
> of `uniquify-orig-buffer', since it carries a buffer object?
Oh yeah, makes sense. I just used the name you originally suggested, but
shorter is better - and more correct too.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Sat, 21 Jun 2025 02:31:03 GMT)
Full text and
rfc822 format available.
Message #58 received at 77312 <at> debbugs.gnu.org (full text, mbox):
On 20/06/2025 10:22, Eli Zaretskii wrote:
> If you decide to install this, please be sure to document this special
> text property in the ELisp manual.
Do you have a particular section in mind?
I mean, it's not like a text property affecting display, for example.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Sat, 21 Jun 2025 07:25:02 GMT)
Full text and
rfc822 format available.
Message #61 received at 77312 <at> debbugs.gnu.org (full text, mbox):
> Date: Sat, 21 Jun 2025 05:29:46 +0300
> Cc: sbaugh <at> janestreet.com, mail <at> daniel-mendler.de, 77312 <at> debbugs.gnu.org
> From: Dmitry Gutov <dmitry <at> gutov.dev>
>
> On 20/06/2025 10:22, Eli Zaretskii wrote:
> > If you decide to install this, please be sure to document this special
> > text property in the ELisp manual.
>
> Do you have a particular section in mind?
We have a special sub-section for that: "Special Properties".
> I mean, it's not like a text property affecting display, for example.
Text properties in Emacs affect many things, not just the display.
See that section for a good demonstration.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Mon, 23 Jun 2025 01:55:06 GMT)
Full text and
rfc822 format available.
Message #64 received at 77312 <at> debbugs.gnu.org (full text, mbox):
On 21/06/2025 10:20, Eli Zaretskii wrote:
>> Do you have a particular section in mind?
> We have a special sub-section for that: "Special Properties".
>
>> I mean, it's not like a text property affecting display, for example.
> Text properties in Emacs affect many things, not just the display.
> See that section for a good demonstration.
Okay. Still, all properties in that section seem to have some effect
when used somewhere inside a buffer text, either to control its display,
or some other behaviors of that buffer.
We're talking about a property which would never be set on a buffer's
text. Still should be in the same sub-section?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Mon, 23 Jun 2025 11:28:02 GMT)
Full text and
rfc822 format available.
Message #67 received at 77312 <at> debbugs.gnu.org (full text, mbox):
> Date: Mon, 23 Jun 2025 04:53:55 +0300
> Cc: sbaugh <at> janestreet.com, mail <at> daniel-mendler.de, 77312 <at> debbugs.gnu.org
> From: Dmitry Gutov <dmitry <at> gutov.dev>
>
> On 21/06/2025 10:20, Eli Zaretskii wrote:
> >> Do you have a particular section in mind?
> > We have a special sub-section for that: "Special Properties".
> >
> >> I mean, it's not like a text property affecting display, for example.
> > Text properties in Emacs affect many things, not just the display.
> > See that section for a good demonstration.
>
> Okay. Still, all properties in that section seem to have some effect
> when used somewhere inside a buffer text, either to control its display,
> or some other behaviors of that buffer.
>
> We're talking about a property which would never be set on a buffer's
> text. Still should be in the same sub-section?
Text properties are set on strings as well, not only on buffer text.
A notable example is the strings used to construct the mode line. So
I don't see a problem here.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Mon, 23 Jun 2025 15:38:02 GMT)
Full text and
rfc822 format available.
Message #70 received at 77312 <at> debbugs.gnu.org (full text, mbox):
On 23/06/2025 14:27, Eli Zaretskii wrote:
> Text properties are set on strings as well, not only on buffer text.
> A notable example is the strings used to construct the mode line. So
> I don't see a problem here.
But either way they are described from the pov of how they affect a
buffer and some behavior in it.
So I wonder how you would want it introduced.
Maybe instead we would instead have a note somewhere near where
'completing-read-function', saying something to the effect that the
completion strings might have a certain text property that would point
to related object. Which the completion UI might use to provide some
extra functionality.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Mon, 23 Jun 2025 16:10:03 GMT)
Full text and
rfc822 format available.
Message #73 received at 77312 <at> debbugs.gnu.org (full text, mbox):
> Date: Mon, 23 Jun 2025 18:37:13 +0300
> Cc: sbaugh <at> janestreet.com, mail <at> daniel-mendler.de, 77312 <at> debbugs.gnu.org
> From: Dmitry Gutov <dmitry <at> gutov.dev>
>
> On 23/06/2025 14:27, Eli Zaretskii wrote:
> > Text properties are set on strings as well, not only on buffer text.
> > A notable example is the strings used to construct the mode line. So
> > I don't see a problem here.
>
> But either way they are described from the pov of how they affect a
> buffer and some behavior in it.
>
> So I wonder how you would want it introduced.
Just describe what this face is used for and what is its effect.
> Maybe instead we would instead have a note somewhere near where
> 'completing-read-function', saying something to the effect that the
> completion strings might have a certain text property that would point
> to related object. Which the completion UI might use to provide some
> extra functionality.
We should do both.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77312
; Package
emacs
.
(Fri, 27 Jun 2025 02:06:02 GMT)
Full text and
rfc822 format available.
Message #76 received at 77312 <at> debbugs.gnu.org (full text, mbox):
On 23/06/2025 19:09, Eli Zaretskii wrote:
>> But either way they are described from the pov of how they affect a
>> buffer and some behavior in it.
>>
>> So I wonder how you would want it introduced.
> Just describe what this face is used for and what is its effect.
>
>> Maybe instead we would instead have a note somewhere near where
>> 'completing-read-function', saying something to the effect that the
>> completion strings might have a certain text property that would point
>> to related object. Which the completion UI might use to provide some
>> extra functionality.
> We should do both.
Here's what I have come up with, so far. In the practical sense, it
seems adequate, though it might seem to elevate this particular text
property too much (mentioning it in a very general context).
A more general approach might be better, one which would allow
transforming the string names just when the selection is being made.
Similar to what Spencer described, though I'm not sure if the predicate
is the place to do transformation.
Anyway, doc proposal for the current functionality below. WDYT?
(Need code change too, will be included in the final patch.)
diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index b34f73feb5b..fc994496db0 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -1239,7 +1239,10 @@ Minibuffer Completion
@code{completing-read} to actually do its work. It should accept the
same arguments as @code{completing-read}. This can be bound to a
different function to completely override the normal behavior of
-@code{completing-read}.
+@code{completing-read}. The function is free to use the string values,
+or text properties on them when available such as
+@code{uniquify-orig-buffer}, to offer additional UI which would act on
+those entities.
@end defvar
@findex completing-read-multiple
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index a23033f2ab0..f7fe0b0180e 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -4020,6 +4020,12 @@ Special Properties
Custom, display-line-numbers,, emacs, The GNU Emacs Manual}) for the
text which has this property.
+@kindex uniquify-orig-buffer @r{(text property)}
+@item uniquify-orig-buffer
+This text property might be attached to some strings when reading a
+buffer name, to reference the original buffer object the string relates
+to. Such strings are returned by @code{uniquify-get-unique-names}.
+
@end table
@defvar inhibit-point-motion-hooks
bug archived.
Request was from
Debbugs Internal Request <help-debbugs <at> gnu.org>
to
internal_control <at> debbugs.gnu.org
.
(Fri, 25 Jul 2025 11:24:06 GMT)
Full text and
rfc822 format available.
This bug report was last modified 6 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.