* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) [not found] ` <20240513065931.0D83AC12C31@vcs2.savannah.gnu.org> @ 2024-05-13 9:22 ` Eshel Yaron 2024-05-13 16:30 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Eshel Yaron @ 2024-05-13 9:22 UTC (permalink / raw) To: emacs-devel; +Cc: Juri Linkov Hi Juri, Juri Linkov <juri@jurta.org> writes: > branch: master > commit 431f8ff1e38ca4367637c6b9fbc25d13d6f760a7 > Author: Juri Linkov <juri@linkov.net> > Commit: Juri Linkov <juri@linkov.net> > > * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) > > (imenu-flatten): Change type boolean to choice > of more values for prefix/suffix section names. > (imenu--completion-buffer): Add :annotation-function if > 'imenu-flatten' is 'annotation'. This is a nice option to have, unfortunately it doesn't play well with the limitations of completing-read --- if we have two or more tree branches that end with the same leaf (string), imenu-flatten=annotation produces the same completion candidate string for multiple imenu items, and choosing any of them loses information about the prefix and always jumps to the first one. For example, setting imenu-flatten to annotation seems to make it impossible to jump to the second "Foo" heading in an Org buffer with the following contents: --8<---------------cut here---------------start------------->8--- * Bar ** Foo * Baz ** Foo --8<---------------cut here---------------end--------------->8--- What do you think about disambiguating just the duplicates in such cases by adding some part of the prefix to the completion candidate string? Best, Eshel ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-13 9:22 ` master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) Eshel Yaron @ 2024-05-13 16:30 ` Juri Linkov 2024-05-14 6:08 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-05-13 16:30 UTC (permalink / raw) To: Eshel Yaron; +Cc: emacs-devel > This is a nice option to have, unfortunately it doesn't play well with > the limitations of completing-read --- if we have two or more tree > branches that end with the same leaf (string), imenu-flatten=annotation > produces the same completion candidate string for multiple imenu items, > and choosing any of them loses information about the prefix and always > jumps to the first one. > > For example, setting imenu-flatten to annotation seems to make it > impossible to jump to the second "Foo" heading in an Org buffer with the > following contents: > > * Bar > ** Foo > * Baz > ** Foo > > What do you think about disambiguating just the duplicates in such cases > by adding some part of the prefix to the completion candidate string? I'm aware of this limitation, I tested it on function/variable ambiguity. One way to disambiguate them is to use text properties on the completion candidate strings. But unfortunately read-from-minibuffer doesn't obey a non-nil value of minibuffer-allow-text-properties, because choose-completion unconditionally discards all properties by substring-no-properties. Maybe choose-completion should use substring instead of substring-no-properties when minibuffer-allow-text-properties is non-nil? ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-13 16:30 ` Juri Linkov @ 2024-05-14 6:08 ` Juri Linkov 2024-05-14 6:38 ` Eli Zaretskii 2024-05-14 15:26 ` [External] : " Drew Adams 0 siblings, 2 replies; 36+ messages in thread From: Juri Linkov @ 2024-05-14 6:08 UTC (permalink / raw) To: Eshel Yaron; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 578 bytes --] > One way to disambiguate them is to use text properties > on the completion candidate strings. > > But unfortunately read-from-minibuffer doesn't obey > a non-nil value of minibuffer-allow-text-properties, > because choose-completion unconditionally discards all properties > by substring-no-properties. > > Maybe choose-completion should use substring instead of > substring-no-properties when minibuffer-allow-text-properties > is non-nil? Here is a new variable that helps to disambiguate completions with the same name but different annotations by using text properties: [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: completion-allow-text-properties.patch --] [-- Type: text/x-diff, Size: 3289 bytes --] diff --git a/lisp/imenu.el b/lisp/imenu.el index 93a544ff550..af344e5e250 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -729,6 +732,8 @@ imenu--completion-buffer ;; Create a list for this buffer only when needed. (let ((name (thing-at-point 'symbol)) choice + (minibuffer-allow-text-properties t) + (completion-allow-text-properties t) (prepared-index-alist (if (not imenu-space-replacement) index-alist (mapcar @@ -762,10 +768,12 @@ imenu--completion-buffer nil t nil 'imenu--history-list name))) (when (stringp name) - (setq choice (assoc name prepared-index-alist)) - (if (imenu--subalist-p choice) - (imenu--completion-buffer (cdr choice) prompt) - choice)))) + (or (get-text-property 0 'imenu-choice name) + (progn + (setq choice (assoc name prepared-index-alist)) + (if (imenu--subalist-p choice) + (imenu--completion-buffer (cdr choice) prompt) + choice)))))) (defun imenu--mouse-menu (index-alist event &optional title) "Let the user select from a buffer index from a mouse menu. @@ -800,7 +808,8 @@ imenu--flatten-index-alist ((not (imenu--subalist-p item)) (list (cons (if (and (eq imenu-flatten 'annotation) prefix) (propertize name 'imenu-section - (format " (%s)" prefix)) + (format " (%s)" prefix) + 'imenu-choice item) new-prefix) pos))) (t diff --git a/lisp/simple.el b/lisp/simple.el index deab52c4201..fa180323963 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10102,6 +10102,14 @@ choose-completion-deselect-if-after This makes `completions--deselect' effective.") +(defcustom completion-allow-text-properties nil + "Non-nil means `choose-completion' should not discard text properties. +This also affects `completing-read' and any of the functions that do +minibuffer input with completion." + :type 'boolean + :version "30.1" + :group 'completion) + (defun choose-completion (&optional event no-exit no-quit) "Choose the completion at point. If EVENT, use EVENT's position to determine the starting position. @@ -10123,7 +10131,9 @@ choose-completion (choice (if choose-completion-deselect-if-after (if-let ((str (get-text-property (posn-point (event-start event)) 'completion--string))) - (substring-no-properties str) + (if completion-allow-text-properties + (substring str) + (substring-no-properties str)) (error "No completion here")) (save-excursion (goto-char (posn-point (event-start event))) @@ -10139,8 +10149,11 @@ choose-completion (setq beg (or (previous-single-property-change beg 'completion--string) beg)) - (substring-no-properties - (get-text-property beg 'completion--string))))))) + (if completion-allow-text-properties + (substring + (get-text-property beg 'completion--string)) + (substring-no-properties + (get-text-property beg 'completion--string)))))))) (unless (buffer-live-p buffer) (error "Destination buffer is dead")) ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-14 6:08 ` Juri Linkov @ 2024-05-14 6:38 ` Eli Zaretskii 2024-05-14 13:10 ` Stefan Monnier 2024-05-15 16:51 ` Juri Linkov 2024-05-14 15:26 ` [External] : " Drew Adams 1 sibling, 2 replies; 36+ messages in thread From: Eli Zaretskii @ 2024-05-14 6:38 UTC (permalink / raw) To: Juri Linkov, Stefan Monnier; +Cc: me, emacs-devel > From: Juri Linkov <juri@linkov.net> > Cc: emacs-devel@gnu.org > Date: Tue, 14 May 2024 09:08:01 +0300 > > +(defcustom completion-allow-text-properties nil > + "Non-nil means `choose-completion' should not discard text properties. > +This also affects `completing-read' and any of the functions that do > +minibuffer input with completion." This new user option should be announced in NEWS. I also wonder whether it should be a user option, i.e. is it reasonable that a user would like all of his/her completions to preserve text properties? Stefan, WDYT? ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-14 6:38 ` Eli Zaretskii @ 2024-05-14 13:10 ` Stefan Monnier 2024-05-14 16:46 ` Juri Linkov 2024-05-14 20:58 ` Daniel Mendler via Emacs development discussions. 2024-05-15 16:51 ` Juri Linkov 1 sibling, 2 replies; 36+ messages in thread From: Stefan Monnier @ 2024-05-14 13:10 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Juri Linkov, me, emacs-devel >> +(defcustom completion-allow-text-properties nil >> + "Non-nil means `choose-completion' should not discard text properties. >> +This also affects `completing-read' and any of the functions that do >> +minibuffer input with completion." > > This new user option should be announced in NEWS. > > I also wonder whether it should be a user option, i.e. is it > reasonable that a user would like all of his/her completions to > preserve text properties? Stefan, WDYT? I can't see how it can make sense as a user-option, no. AFAICT it's a hack for specific front-ends or specific backends (or combinations thereof) to work around limitations in the completion API (or maybe rather to allow abusing the completion API as a selection API 🙂). Stefan ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-14 13:10 ` Stefan Monnier @ 2024-05-14 16:46 ` Juri Linkov 2024-05-14 20:58 ` Daniel Mendler via Emacs development discussions. 1 sibling, 0 replies; 36+ messages in thread From: Juri Linkov @ 2024-05-14 16:46 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, me, emacs-devel >>> +(defcustom completion-allow-text-properties nil >>> + "Non-nil means `choose-completion' should not discard text properties. >>> +This also affects `completing-read' and any of the functions that do >>> +minibuffer input with completion." >> >> This new user option should be announced in NEWS. >> >> I also wonder whether it should be a user option, i.e. is it >> reasonable that a user would like all of his/her completions to >> preserve text properties? Stefan, WDYT? > > I can't see how it can make sense as a user-option, no. AFAICT it's > a hack for specific front-ends or specific backends (or combinations > thereof) to work around limitations in the completion API (or maybe Sorry, it was a mistake, it was intended as a counterpart of minibuffer-allow-text-properties that is not a user option. > rather to allow abusing the completion API as a selection API 🙂). Indeed, this value of imenu-flatten can be unambiguous only in case of the Selection API. So completion-allow-text-properties would be useful for users who prefer Selection API to select a candidate with annotation. And for the Completion API another value of imenu-flatten could be added that will add a suffix, so the annotation will be part of the completion candidate string. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-14 13:10 ` Stefan Monnier 2024-05-14 16:46 ` Juri Linkov @ 2024-05-14 20:58 ` Daniel Mendler via Emacs development discussions. 2024-05-14 23:26 ` FW: [External] : " Drew Adams 1 sibling, 1 reply; 36+ messages in thread From: Daniel Mendler via Emacs development discussions. @ 2024-05-14 20:58 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, Juri Linkov, me, emacs-devel, Dmitry Gutov Stefan Monnier <monnier@iro.umontreal.ca> writes: >>> +(defcustom completion-allow-text-properties nil >>> + "Non-nil means `choose-completion' should not discard text properties. >>> +This also affects `completing-read' and any of the functions that do >>> +minibuffer input with completion." >> >> This new user option should be announced in NEWS. >> >> I also wonder whether it should be a user option, i.e. is it >> reasonable that a user would like all of his/her completions to >> preserve text properties? Stefan, WDYT? > > I can't see how it can make sense as a user-option, no. AFAICT it's > a hack for specific front-ends or specific backends (or combinations > thereof) to work around limitations in the completion API (or maybe > rather to allow abusing the completion API as a selection API 🙂). As far as I can tell, both Corfu and Company preserve the text properties if a candidate is selected explicitly. The same could work for default completion when operating in "selection mode", i.e., when the user explicitly selects a candidate explicitly in the *Completions* buffer. However in the regular mode of operation, where the user step-wise builds up input in the minibuffer, text properties wouldn't and shouldn't be preserved. Preserving text properties during selection can be useful when distinguishing equal candidates, even if regular completion will continue to work as is. For example Eglot provides both snippet and identifier candidates (which may be equal). Then the user can explicitly select among them. Similarly, Eglot may return equal candidates for overloaded methods with argument list expansion like in Java. However I am not sure if my proposal would help with the Imenu duplicate candidate issue you are discussing here. When completing, the first equal candidate would win, but the user could perhaps opt-in to select another one explicitly. Daniel ^ permalink raw reply [flat|nested] 36+ messages in thread
* FW: [External] : Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-14 20:58 ` Daniel Mendler via Emacs development discussions. @ 2024-05-14 23:26 ` Drew Adams 0 siblings, 0 replies; 36+ messages in thread From: Drew Adams @ 2024-05-14 23:26 UTC (permalink / raw) To: emacs-devel@gnu.org Sending again. For some reason, "Reply All" didn't include emacs-devel@gnu.org. -----Original Message----- From: Drew Adams Sent: Tuesday, May 14, 2024 4:16 PM To: 'Daniel Mendler'; Stefan Monnier Cc: Eli Zaretskii; Juri Linkov; me@eshelyaron.com; Dmitry Gutov > However in the regular mode of operation, where the user > step-wise builds up input in the minibuffer, text properties wouldn't > and shouldn't be preserved. Why shouldn't they? Maybe I don't understand the case you describe, but isn't the caller of completing-read or whatever completion function ultimately getting a completion candidate returned from that completion function? If so, and if the completions are propertized strings, why "shouldn't" that be returned as the result? What does it matter how or whether thematching input was "stepwise built up in the minibuffer"? It's OK if some particular completion apparatus _can't_ return a propertized string for some reason. But why should such a limitation be elevated to a proscription that completion in general "shouldn't" return a propertized string? > Preserving text properties during selection can be useful when > distinguishing equal candidates, even if regular completion will > continue to work as is. Yes, of course. That's a main use case for propertizing candidates. E.g., a property that holds a buffer position or that holds the complete alist-element value (a string candidate that holds all the info of the entire "real" candidate). (Icicles has been exploiting this "gimmick" for 16 years now.) ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-14 6:38 ` Eli Zaretskii 2024-05-14 13:10 ` Stefan Monnier @ 2024-05-15 16:51 ` Juri Linkov 2024-05-15 18:03 ` Eli Zaretskii 2024-05-15 18:30 ` Eshel Yaron 1 sibling, 2 replies; 36+ messages in thread From: Juri Linkov @ 2024-05-15 16:51 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Stefan Monnier, me, emacs-devel [-- Attachment #1: Type: text/plain, Size: 473 bytes --] >> +(defcustom completion-allow-text-properties nil >> + "Non-nil means `choose-completion' should not discard text properties. >> +This also affects `completing-read' and any of the functions that do >> +minibuffer input with completion." > > This new user option should be announced in NEWS. > > I also wonder whether it should be a user option So here it's a variable, that will later help to select Imenu completion candidates with same names from different groups. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: completion-allow-text-properties.patch --] [-- Type: text/x-diff, Size: 4075 bytes --] diff --git a/etc/NEWS b/etc/NEWS index 34052764f5f..0db85410ebe 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1784,6 +1784,13 @@ A major mode based on the tree-sitter library for editing Lua files. ** Minibuffer and Completions +*** New variable 'completion-allow-text-properties'. +Like non-nil 'minibuffer-allow-text-properties' that doesn't discard +text properties, it does the same by keeping text properties +on the selected completion candidate. So when these two variables +both are non-nil then 'completing-read' returns a selected completion +with the initial text properties kept intact. + +++ *** New global minor mode 'minibuffer-regexp-mode'. This is a minor mode for editing regular expressions in the minibuffer. diff --git a/lisp/simple.el b/lisp/simple.el index cdbbd876e3b..8793e590733 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10102,6 +10102,11 @@ choose-completion-deselect-if-after This makes `completions--deselect' effective.") +(defvar completion-allow-text-properties nil + "Non-nil means `choose-completion' should not discard text properties. +This affects `completing-read' and any of the functions that do +minibuffer input with completion.") + (defun choose-completion (&optional event no-exit no-quit) "Choose the completion at point. If EVENT, use EVENT's position to determine the starting position. @@ -10122,8 +10127,10 @@ choose-completion (completion-no-auto-exit (if no-exit t completion-no-auto-exit)) (choice (if choose-completion-deselect-if-after - (if-let ((str (get-text-property (posn-point (event-start event)) 'completion--string))) - (substring-no-properties str) + (if-let ((str (get-text-property (posn-point (event-start event)) + 'completion--string))) + (if completion-allow-text-properties str + (substring-no-properties str)) (error "No completion here")) (save-excursion (goto-char (posn-point (event-start event))) @@ -10139,8 +10146,9 @@ choose-completion (setq beg (or (previous-single-property-change beg 'completion--string) beg)) - (substring-no-properties - (get-text-property beg 'completion--string))))))) + (let ((str (get-text-property beg 'completion--string))) + (if completion-allow-text-properties str + (substring-no-properties str)))))))) (unless (buffer-live-p buffer) (error "Destination buffer is dead")) diff --git a/lisp/imenu.el b/lisp/imenu.el index ea097f5da3a..952c3dc8969 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -732,6 +732,8 @@ imenu--completion-buffer ;; Create a list for this buffer only when needed. (let ((name (thing-at-point 'symbol)) choice + (minibuffer-allow-text-properties t) + (completion-allow-text-properties t) (prepared-index-alist (if (not imenu-space-replacement) index-alist (mapcar @@ -765,10 +767,12 @@ imenu--completion-buffer nil t nil 'imenu--history-list name))) (when (stringp name) - (setq choice (assoc name prepared-index-alist)) - (if (imenu--subalist-p choice) - (imenu--completion-buffer (cdr choice) prompt) - choice)))) + (or (get-text-property 0 'imenu-choice name) + (progn + (setq choice (assoc name prepared-index-alist)) + (if (imenu--subalist-p choice) + (imenu--completion-buffer (cdr choice) prompt) + choice)))))) (defun imenu--mouse-menu (index-alist event &optional title) "Let the user select from a buffer index from a mouse menu. @@ -803,7 +807,8 @@ imenu--flatten-index-alist ((not (imenu--subalist-p item)) (list (cons (if (and (eq imenu-flatten 'annotation) prefix) (propertize name 'imenu-section - (format " (%s)" prefix)) + (format " (%s)" prefix) + 'imenu-choice item) new-prefix) pos))) (t ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-15 16:51 ` Juri Linkov @ 2024-05-15 18:03 ` Eli Zaretskii 2024-05-15 18:30 ` Eshel Yaron 1 sibling, 0 replies; 36+ messages in thread From: Eli Zaretskii @ 2024-05-15 18:03 UTC (permalink / raw) To: Juri Linkov; +Cc: monnier, me, emacs-devel > From: Juri Linkov <juri@linkov.net> > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, me@eshelyaron.com, > emacs-devel@gnu.org > Date: Wed, 15 May 2024 19:51:25 +0300 > > > I also wonder whether it should be a user option > > So here it's a variable, that will later help to select Imenu > completion candidates with same names from different groups. Thanks, LGTM. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-15 16:51 ` Juri Linkov 2024-05-15 18:03 ` Eli Zaretskii @ 2024-05-15 18:30 ` Eshel Yaron 2024-05-16 6:08 ` Juri Linkov 1 sibling, 1 reply; 36+ messages in thread From: Eshel Yaron @ 2024-05-15 18:30 UTC (permalink / raw) To: Juri Linkov; +Cc: Eli Zaretskii, Stefan Monnier, emacs-devel Hi Juri, Juri Linkov <juri@linkov.net> writes: >>> +(defcustom completion-allow-text-properties nil >>> + "Non-nil means `choose-completion' should not discard text properties. >>> +This also affects `completing-read' and any of the functions that do >>> +minibuffer input with completion." >> >> This new user option should be announced in NEWS. >> >> I also wonder whether it should be a user option > > So here it's a variable, that will later help to select Imenu > completion candidates with same names from different groups. > > diff --git a/etc/NEWS b/etc/NEWS > index 34052764f5f..0db85410ebe 100644 > --- a/etc/NEWS > +++ b/etc/NEWS > @@ -1784,6 +1784,13 @@ A major mode based on the tree-sitter library for editing Lua files. > > ** Minibuffer and Completions > > +*** New variable 'completion-allow-text-properties'. > +Like non-nil 'minibuffer-allow-text-properties' that doesn't discard > +text properties, it does the same by keeping text properties > +on the selected completion candidate. So when these two variables > +both are non-nil then 'completing-read' returns a selected completion > +with the initial text properties kept intact. Note that when minibuffer-allow-text-properties is non-nil, you can already get the same original text properties from completing-read if you "select" your candidate by cycling, since that doesn't go through choose-completion which strips text properties. It feels a bit surprising to have this separate variable that affects one kind of selection ("choosing") and not other kinds ("cycling", "expanding"). IMO, it'd be better, if possible, to just cease stripping text properties in choose-completion altogether. Note that choose-completion calls completion--replace to do the actual insertion, and that function already respects minibuffer-allow-text-properties. > --- a/lisp/imenu.el > +++ b/lisp/imenu.el > @@ -732,6 +732,8 @@ imenu--completion-buffer > ;; Create a list for this buffer only when needed. > (let ((name (thing-at-point 'symbol)) > choice > + (minibuffer-allow-text-properties t) > + (completion-allow-text-properties t) IIUC, these let-bindings around completing-read will affect all recursive minibuffers too, and even completion-at-point completions if you start editing another buffer before exiting the minibuffer. Perhaps we can use buffer-local bindings in the minibuffer and propagate them to the completions list buffer when populating it instead of let-binding? Best, Eshel ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-15 18:30 ` Eshel Yaron @ 2024-05-16 6:08 ` Juri Linkov 2024-05-16 9:51 ` Eli Zaretskii 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-05-16 6:08 UTC (permalink / raw) To: Eshel Yaron; +Cc: Eli Zaretskii, Stefan Monnier, emacs-devel >> +*** New variable 'completion-allow-text-properties'. >> +Like non-nil 'minibuffer-allow-text-properties' that doesn't discard >> +text properties, it does the same by keeping text properties >> +on the selected completion candidate. So when these two variables >> +both are non-nil then 'completing-read' returns a selected completion >> +with the initial text properties kept intact. > > Note that when minibuffer-allow-text-properties is non-nil, you can > already get the same original text properties from completing-read if > you "select" your candidate by cycling, since that doesn't go through > choose-completion which strips text properties. It feels a bit > surprising to have this separate variable that affects one kind of > selection ("choosing") and not other kinds ("cycling", "expanding"). > IMO, it'd be better, if possible, to just cease stripping text > properties in choose-completion altogether. Note that choose-completion > calls completion--replace to do the actual insertion, and that function > already respects minibuffer-allow-text-properties. I agree that a new variable is unnecessary, so it would be better just to preserve text properties in choose-completion unconditionally. Unless there are objections this looks like the right thing to do. >> (let ((name (thing-at-point 'symbol)) >> choice >> + (minibuffer-allow-text-properties t) >> + (completion-allow-text-properties t) > > IIUC, these let-bindings around completing-read will affect all > recursive minibuffers too, and even completion-at-point completions if > you start editing another buffer before exiting the minibuffer. Perhaps > we can use buffer-local bindings in the minibuffer and propagate them to > the completions list buffer when populating it instead of let-binding? This problem could be solved much easier if we avoid adding a new variable completion-allow-text-properties. Then we can set only the existing variable minibuffer-allow-text-properties in the minibuffer. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-16 6:08 ` Juri Linkov @ 2024-05-16 9:51 ` Eli Zaretskii 2024-05-17 6:48 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Eli Zaretskii @ 2024-05-16 9:51 UTC (permalink / raw) To: Juri Linkov; +Cc: me, monnier, emacs-devel > From: Juri Linkov <juri@linkov.net> > Cc: Eli Zaretskii <eliz@gnu.org>, Stefan Monnier > <monnier@iro.umontreal.ca>, emacs-devel@gnu.org > Date: Thu, 16 May 2024 09:08:21 +0300 > > >> +*** New variable 'completion-allow-text-properties'. > >> +Like non-nil 'minibuffer-allow-text-properties' that doesn't discard > >> +text properties, it does the same by keeping text properties > >> +on the selected completion candidate. So when these two variables > >> +both are non-nil then 'completing-read' returns a selected completion > >> +with the initial text properties kept intact. > > > > Note that when minibuffer-allow-text-properties is non-nil, you can > > already get the same original text properties from completing-read if > > you "select" your candidate by cycling, since that doesn't go through > > choose-completion which strips text properties. It feels a bit > > surprising to have this separate variable that affects one kind of > > selection ("choosing") and not other kinds ("cycling", "expanding"). > > IMO, it'd be better, if possible, to just cease stripping text > > properties in choose-completion altogether. Note that choose-completion > > calls completion--replace to do the actual insertion, and that function > > already respects minibuffer-allow-text-properties. > > I agree that a new variable is unnecessary, so it would be better just > to preserve text properties in choose-completion unconditionally. > Unless there are objections this looks like the right thing to do. Does that mean completion candidates will always appear with their original text properties? If so, I don't think it's TRT in all cases. Whether it's TRT depends on the use case, so a variable definitely seems like the way to go. However, AFAIU Eshel didn't mean to say we should always preserve text properties, he said we already have a variable to indicate whether properties are to be preserved. So the issue, AFAIU, is whether we need _another_ variable, or should use a single one in both cases. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-16 9:51 ` Eli Zaretskii @ 2024-05-17 6:48 ` Juri Linkov 2024-05-17 15:36 ` Stefan Monnier 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-05-17 6:48 UTC (permalink / raw) To: Eli Zaretskii; +Cc: me, monnier, emacs-devel >> > Note that when minibuffer-allow-text-properties is non-nil, you can >> > already get the same original text properties from completing-read if >> > you "select" your candidate by cycling, since that doesn't go through >> > choose-completion which strips text properties. It feels a bit >> > surprising to have this separate variable that affects one kind of >> > selection ("choosing") and not other kinds ("cycling", "expanding"). >> > IMO, it'd be better, if possible, to just cease stripping text >> > properties in choose-completion altogether. Note that choose-completion >> > calls completion--replace to do the actual insertion, and that function >> > already respects minibuffer-allow-text-properties. >> >> I agree that a new variable is unnecessary, so it would be better just >> to preserve text properties in choose-completion unconditionally. >> Unless there are objections this looks like the right thing to do. > > Does that mean completion candidates will always appear with their > original text properties? If so, I don't think it's TRT in all cases. > Whether it's TRT depends on the use case, so a variable definitely > seems like the way to go. Like Eshel noted, the text properties are already discarded from the completion candidate by default since the default value of minibuffer-allow-text-properties is nil. > However, AFAIU Eshel didn't mean to say we should always preserve text > properties, he said we already have a variable to indicate whether > properties are to be preserved. So the issue, AFAIU, is whether we > need _another_ variable, or should use a single one in both cases. Indeed, the existing variable minibuffer-allow-text-properties can be used for both cases. So when choose-completion will preserve text properties, then completion--replace will decide whether to discard them based on the value of minibuffer-allow-text-properties. But there is another separate problem: Eshel asked to replace let-bindings around completing-read with the minibuffer-local value of minibuffer-allow-text-properties. However, this is impossible to do because read-from-minibuffer called from completing-read can't use a minibuffer-local value of minibuffer-allow-text-properties. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-17 6:48 ` Juri Linkov @ 2024-05-17 15:36 ` Stefan Monnier 2024-05-17 16:43 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Stefan Monnier @ 2024-05-17 15:36 UTC (permalink / raw) To: Juri Linkov; +Cc: Eli Zaretskii, me, emacs-devel > But there is another separate problem: Eshel asked to replace > let-bindings around completing-read with the minibuffer-local value > of minibuffer-allow-text-properties. However, this is impossible to do > because read-from-minibuffer called from completing-read can't use > a minibuffer-local value of minibuffer-allow-text-properties. It could use something like `minibuffer-with-setup-hook`, no? This might be a good opportunity to allow the INIT argument to be a function (run within the fresh new minibuffer). Stefan ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-17 15:36 ` Stefan Monnier @ 2024-05-17 16:43 ` Juri Linkov 2024-05-18 15:12 ` Stefan Monnier 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-05-17 16:43 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, me, emacs-devel >> But there is another separate problem: Eshel asked to replace >> let-bindings around completing-read with the minibuffer-local value >> of minibuffer-allow-text-properties. However, this is impossible to do >> because read-from-minibuffer called from completing-read can't use >> a minibuffer-local value of minibuffer-allow-text-properties. > > It could use something like `minibuffer-with-setup-hook`, no? > This might be a good opportunity to allow the INIT argument to be > a function (run within the fresh new minibuffer). I see no way of doing that, this doesn't work: (minibuffer-with-setup-hook (lambda () (setq-local minibuffer-allow-text-properties t)) (completing-read "Prompt: " (list (propertize "foo1" 'prop t) (propertize "foo2" 'prop t)))) because when `completing-read-default` calls `read-from-minibuffer`, it uses the value of `minibuffer-allow-text-properties` from the original buffer: val = read_minibuf (keymap, initial_contents, prompt, !NILP (read), histvar, histpos, default_value, minibuffer_allow_text_properties, !NILP (inherit_input_method)); Then `read_minibuf` uses its argument `allow_props`: if (allow_props) val = Fminibuffer_contents (); else val = Fminibuffer_contents_no_properties (); Maybe it could use `minibuffer-allow-text-properties` directly here? ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-17 16:43 ` Juri Linkov @ 2024-05-18 15:12 ` Stefan Monnier 2024-05-20 6:46 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Stefan Monnier @ 2024-05-18 15:12 UTC (permalink / raw) To: Juri Linkov; +Cc: Eli Zaretskii, me, emacs-devel > because when `completing-read-default` calls `read-from-minibuffer`, > it uses the value of `minibuffer-allow-text-properties` from > the original buffer: > > val = read_minibuf (keymap, initial_contents, prompt, > !NILP (read), > histvar, histpos, default_value, > minibuffer_allow_text_properties, > !NILP (inherit_input_method)); Damn! This is too bad: a buffer-local setting of `minibuffer_allow_text_properties` can basically never be used then, because it's read from the wrong buffer. > Then `read_minibuf` uses its argument `allow_props`: > > if (allow_props) > val = Fminibuffer_contents (); > else > val = Fminibuffer_contents_no_properties (); > > Maybe it could use `minibuffer-allow-text-properties` directly here? Indeed: since a buffer-local setting can't work, we know that all callers must use a plain let-binding so the binding will be active during the whole minibuffer session, so we may as well read it at the end (in the minibuffer) rather than at the beginning (in the `minibuffer--original-buffer`). Stefan PS: Git shows that `minibuffer-allow-text-properties` was introduced eons ago (and basically never touched since then, even the docstring is mostly unchanged). And Grep shows it's not used very often (and several of those uses are around `completing-read`). Funnily enough, one of the few uses in our tree binds it to nil, I wonder why that was needed. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-18 15:12 ` Stefan Monnier @ 2024-05-20 6:46 ` Juri Linkov 2024-05-27 18:18 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-05-20 6:46 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, me, emacs-devel [-- Attachment #1: Type: text/plain, Size: 1880 bytes --] >> because when `completing-read-default` calls `read-from-minibuffer`, >> it uses the value of `minibuffer-allow-text-properties` from >> the original buffer: >> >> val = read_minibuf (keymap, initial_contents, prompt, >> !NILP (read), >> histvar, histpos, default_value, >> minibuffer_allow_text_properties, >> !NILP (inherit_input_method)); > > Damn! This is too bad: a buffer-local setting of > `minibuffer_allow_text_properties` can basically never be used then, > because it's read from the wrong buffer. > >> Then `read_minibuf` uses its argument `allow_props`: >> >> if (allow_props) >> val = Fminibuffer_contents (); >> else >> val = Fminibuffer_contents_no_properties (); >> >> Maybe it could use `minibuffer-allow-text-properties` directly here? > > Indeed: since a buffer-local setting can't work, we know that all > callers must use a plain let-binding so the binding will be active > during the whole minibuffer session, so we may as well read it at the > end (in the minibuffer) rather than at the beginning (in the > `minibuffer--original-buffer`). Ok, then here is a complete patch with documentation updates where many documentation changes are fixing the documentation to describe the current behavior existed even before applying these code changes. > PS: Git shows that `minibuffer-allow-text-properties` was introduced > eons ago (and basically never touched since then, even the docstring is > mostly unchanged). And Grep shows it's not used very often (and > several of those uses are around `completing-read`). > Funnily enough, one of the few uses in our tree binds it to nil, > I wonder why that was needed. Probably the nil let-binding was intended to negate the effect of a non-nil let-binding higher in the stack of recursive minibuffers. So this is another reason to prefer buffer-local settings. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: minibuffer_allow_text_properties.patch --] [-- Type: text/x-diff, Size: 8774 bytes --] diff --git a/etc/NEWS b/etc/NEWS index 4e52d4dccb2..cefbc0eb938 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2033,6 +2033,17 @@ UTF-8 byte sequence, and the optional parameter MULTIBYTE of 'dbus-string-to-byte-array' should be a regular Lisp string, not a unibyte string. ++++ +** 'minibuffer-allow-text-properties' now can be set buffer-local. +'read-from-minibuffer' and functions that use it can take the +buffer-local value from the minibuffer. + ++++ +** 'minibuffer-allow-text-properties' also affects completions. +When it has a non-nil value, then completion functions like +'completing-read' don't discard text properties from the returned +completion candidate. + \f * Lisp Changes in Emacs 30.1 diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi index 8f2d0d702f9..af5552851e2 100644 --- a/doc/lispref/minibuf.texi +++ b/doc/lispref/minibuf.texi @@ -185,7 +185,8 @@ Text from Minibuffer History}. If the variable @code{minibuffer-allow-text-properties} is -non-@code{nil}, then the string that is returned includes whatever text +non-@code{nil}, either let-bound or buffer-local in the minibuffer, +then the string that is returned includes whatever text properties were present in the minibuffer. Otherwise all the text properties are stripped when the value is returned. (By default this variable is @code{nil}.) @@ -352,28 +353,27 @@ Text from Minibuffer @defvar minibuffer-allow-text-properties If this variable is @code{nil}, the default, then -@code{read-from-minibuffer} and @code{read-string} strip all text +@code{read-from-minibuffer}, @code{read-string}, and all +functions that do minibuffer input with completion strip all text properties from the minibuffer input before returning it. However, -@code{read-no-blanks-input} (see below), as well as @code{read-minibuffer} and related functions (@pxref{Object from -Minibuffer,, Reading Lisp Objects With the Minibuffer}), and all -functions that do minibuffer input with completion, remove the +Minibuffer,, Reading Lisp Objects With the Minibuffer}), remove the @code{face} property unconditionally, regardless of the value of this variable. -If this variable is non-@code{nil}, most text properties on strings -from the completion table are preserved---but only on the part of the -strings that were completed. +If this variable is non-@code{nil}, either let-bound or buffer-local in +the minibuffer, most text properties on strings from the completion +table are preserved---but only on the part of the strings that were +completed. @lisp (let ((minibuffer-allow-text-properties t)) (completing-read "String: " (list (propertize "foobar" 'data 'zot)))) -=> #("foobar" 3 6 (data zot)) +=> #("foobar" 0 6 (data zot)) @end lisp In this example, the user typed @samp{foo} and then hit the @kbd{TAB} -key, so the text properties are only preserved on the last three -characters. +key, so the text properties are preserved on all characters. @end defvar @vindex minibuffer-mode-map @@ -433,18 +433,6 @@ Text from Minibuffer keymap as the @var{keymap} argument for that function. Since the keymap @code{minibuffer-local-ns-map} does not rebind @kbd{C-q}, it @emph{is} possible to put a space into the string, by quoting it. - -This function discards text properties, regardless of the value of -@code{minibuffer-allow-text-properties}. - -@smallexample -@group -(read-no-blanks-input @var{prompt} @var{initial}) -@equiv{} -(let (minibuffer-allow-text-properties) - (read-from-minibuffer @var{prompt} @var{initial} minibuffer-local-ns-map)) -@end group -@end smallexample @end defun @c Slightly unfortunate name, suggesting it might be related to the diff --git a/src/minibuf.c b/src/minibuf.c index 9c1c86680d4..f2a76086361 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -563,7 +563,8 @@ DEFUN ("minibuffer-contents-no-properties", Fminibuffer_contents_no_properties, DEFALT specifies the default value for the sake of history commands. - If ALLOW_PROPS, do not throw away text properties. + If ALLOW_PROPS or `minibuffer-allow-text-properties' is non-nil, + do not throw away text properties. if INHERIT_INPUT_METHOD, the minibuffer inherits the current input method. */ @@ -928,7 +929,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, /* Make minibuffer contents into a string. */ Fset_buffer (minibuffer); - if (allow_props) + if (allow_props || minibuffer_allow_text_properties) val = Fminibuffer_contents (); else val = Fminibuffer_contents_no_properties (); @@ -1321,7 +1322,8 @@ DEFUN ("read-from-minibuffer", Fread_from_minibuffer, Seventh arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits the current input method and the setting of `enable-multibyte-characters'. -If the variable `minibuffer-allow-text-properties' is non-nil, +If the variable `minibuffer-allow-text-properties' is non-nil + (either let-bound or buffer-local in the minibuffer), then the string which is returned includes whatever text properties were present in the minibuffer. Otherwise the value has no text properties. @@ -2464,9 +2466,10 @@ syms_of_minibuf (void) DEFVAR_BOOL ("minibuffer-allow-text-properties", minibuffer_allow_text_properties, doc: /* Non-nil means `read-from-minibuffer' should not discard text properties. -This also affects `read-string', but it does not affect `read-minibuffer', -`read-no-blanks-input', or any of the functions that do minibuffer input -with completion; they always discard text properties. */); +The value could be let-bound or buffer-local in the minibuffer. +This also affects `read-string', or any of the functions that do +minibuffer input with completion, but it does not affect `read-minibuffer' +that always discards text properties. */); minibuffer_allow_text_properties = 0; DEFVAR_LISP ("minibuffer-prompt-properties", Vminibuffer_prompt_properties, diff --git a/lisp/simple.el b/lisp/simple.el index bcd26da13ed..8fbfa683e97 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10127,9 +10127,9 @@ choose-completion (completion-no-auto-exit (if no-exit t completion-no-auto-exit)) (choice (if choose-completion-deselect-if-after - (if-let ((str (get-text-property (posn-point (event-start event)) 'completion--string))) - (substring-no-properties str) - (error "No completion here")) + (or (get-text-property (posn-point (event-start event)) + 'completion--string) + (error "No completion here")) (save-excursion (goto-char (posn-point (event-start event))) (let (beg) @@ -10144,8 +10144,7 @@ choose-completion (setq beg (or (previous-single-property-change beg 'completion--string) beg)) - (substring-no-properties - (get-text-property beg 'completion--string))))))) + (get-text-property beg 'completion--string)))))) (unless (buffer-live-p buffer) (error "Destination buffer is dead")) diff --git a/lisp/imenu.el b/lisp/imenu.el index ea097f5da3a..93d84106ec1 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -752,6 +752,7 @@ imenu--completion-buffer ;; Display the completion buffer. (minibuffer-with-setup-hook (lambda () + (setq-local minibuffer-allow-text-properties t) (setq-local completion-extra-properties `( :category imenu ,@(when (eq imenu-flatten 'annotation) @@ -765,10 +766,12 @@ imenu--completion-buffer nil t nil 'imenu--history-list name))) (when (stringp name) - (setq choice (assoc name prepared-index-alist)) - (if (imenu--subalist-p choice) - (imenu--completion-buffer (cdr choice) prompt) - choice)))) + (or (get-text-property 0 'imenu-choice name) + (progn + (setq choice (assoc name prepared-index-alist)) + (if (imenu--subalist-p choice) + (imenu--completion-buffer (cdr choice) prompt) + choice)))))) (defun imenu--mouse-menu (index-alist event &optional title) "Let the user select from a buffer index from a mouse menu. @@ -798,7 +801,9 @@ imenu--flatten-index-alist (new-prefix (and concat-names (if prefix (concat prefix imenu-level-separator name) - name)))) + (if (eq imenu-flatten 'annotation) + (propertize name 'imenu-choice item) + name))))) (cond ((not (imenu--subalist-p item)) (list (cons (if (and (eq imenu-flatten 'annotation) prefix) ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-20 6:46 ` Juri Linkov @ 2024-05-27 18:18 ` Juri Linkov 2024-07-14 6:28 ` Eshel Yaron 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-05-27 18:18 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, me, emacs-devel >>> Maybe it could use `minibuffer-allow-text-properties` directly here? >> >> Indeed: since a buffer-local setting can't work, we know that all >> callers must use a plain let-binding so the binding will be active >> during the whole minibuffer session, so we may as well read it at the >> end (in the minibuffer) rather than at the beginning (in the >> `minibuffer--original-buffer`). > > Ok, then here is a complete patch with documentation updates > where many documentation changes are fixing the documentation > to describe the current behavior existed even before applying > these code changes. So this patch is pushed now. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-27 18:18 ` Juri Linkov @ 2024-07-14 6:28 ` Eshel Yaron 2024-07-14 6:53 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Eshel Yaron @ 2024-07-14 6:28 UTC (permalink / raw) To: Juri Linkov; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel Hi Juri, Juri Linkov <juri@linkov.net> writes: >> Ok, then here is a complete patch with documentation updates >> where many documentation changes are fixing the documentation >> to describe the current behavior existed even before applying >> these code changes. > > So this patch is pushed now. I'm afraid imenu-flatten=annotation has one more hurdle to overcome. Consider: 1. emacs -Q 2. (setq imenu-flatten 'annotation) 2. C-x C-f .../lisp/imenu.el 3. M-g i 4. M-<down> M-<down> M-<down> M-<down> ... 5. Now the selected candidate in *Completions* is e.g. imenu--cleanup, this is also the minibuffer contents, so far so good. 6. Type M-RET to jump to this candidate. 7. Land on imenu instead of imenu--cleanup. No matter how far down you go with M-<down>, if you go through the entry for imenu, that's where you'll land when you hit M-RET. This is because imenu-flatten=annotation tries to identify candidates by their text properties, but completion--replace retains common parts while replacing minibuffer text, along with the text properties of these common parts. This affects imenu-flatten=group too. It might be possible to resolve this by setting a different completion-list-insert-choice-function that circumvents replaces the whole minibuffer contents, unlike completion--replace, which tries hard to preserve markers etc. Best, Eshel ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-07-14 6:28 ` Eshel Yaron @ 2024-07-14 6:53 ` Juri Linkov 2024-07-14 10:55 ` Eshel Yaron 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-07-14 6:53 UTC (permalink / raw) To: Eshel Yaron; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel > I'm afraid imenu-flatten=annotation has one more hurdle to overcome. > Consider: > > 1. emacs -Q > 2. (setq imenu-flatten 'annotation) > 2. C-x C-f .../lisp/imenu.el > 3. M-g i > 4. M-<down> M-<down> M-<down> M-<down> ... > 5. Now the selected candidate in *Completions* is e.g. imenu--cleanup, > this is also the minibuffer contents, so far so good. > 6. Type M-RET to jump to this candidate. > 7. Land on imenu instead of imenu--cleanup. > > No matter how far down you go with M-<down>, if you go through the entry > for imenu, that's where you'll land when you hit M-RET. This is because > imenu-flatten=annotation tries to identify candidates by their text > properties, but completion--replace retains common parts while replacing > minibuffer text, along with the text properties of these common parts. > > This affects imenu-flatten=group too. > > It might be possible to resolve this by setting a different > completion-list-insert-choice-function that circumvents replaces the > whole minibuffer contents, unlike completion--replace, which tries hard > to preserve markers etc. Maybe then imenu--completion-buffer should try to get the text property from the end of completion? Provided that completion--replace will keep some properties at the end instead of using insert-and-inherit. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-07-14 6:53 ` Juri Linkov @ 2024-07-14 10:55 ` Eshel Yaron 2024-07-14 17:00 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Eshel Yaron @ 2024-07-14 10:55 UTC (permalink / raw) To: Juri Linkov; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel Juri Linkov <juri@linkov.net> writes: >> I'm afraid imenu-flatten=annotation has one more hurdle to overcome. >> Consider: >> >> 1. emacs -Q >> 2. (setq imenu-flatten 'annotation) >> 2. C-x C-f .../lisp/imenu.el >> 3. M-g i >> 4. M-<down> M-<down> M-<down> M-<down> ... >> 5. Now the selected candidate in *Completions* is e.g. imenu--cleanup, >> this is also the minibuffer contents, so far so good. >> 6. Type M-RET to jump to this candidate. >> 7. Land on imenu instead of imenu--cleanup. >> >> No matter how far down you go with M-<down>, if you go through the entry >> for imenu, that's where you'll land when you hit M-RET. This is because >> imenu-flatten=annotation tries to identify candidates by their text >> properties, but completion--replace retains common parts while replacing >> minibuffer text, along with the text properties of these common parts. >> >> This affects imenu-flatten=group too. >> >> It might be possible to resolve this by setting a different >> completion-list-insert-choice-function that circumvents replaces the >> whole minibuffer contents, unlike completion--replace, which tries hard >> to preserve markers etc. > > Maybe then imenu--completion-buffer should try to get the text property > from the end of completion? Provided that completion--replace will keep > some properties at the end instead of using insert-and-inherit. I'm not sure, I think that might work in some cases, but since completion--replace also keeps the common suffix it may still suffer from the same issue when going from candidate "foo-baz" to "bar-baz". Then there's the problem of what happens when you simply type the candidate you want to jump to, without completion. For example M-g i imenu RET goes to the imenu function when imenu-flatten=nil, but if imenu-flatten=annotation then it goes to the defgroup. What I would suggest is to ensure completion candidates are unambiguous as strings rather than relying on text properties. Namely: - Restore imenu-flatten to a boolean option: either flat or nested. - If imenu-flatten is non-nil, prepend the full prefix to each candidate, like imenu-flatten=prefix does currently. This takes care of disambiguating the candidate strings. - If completions-group is also non-nil, then group candidates according to their prefix and trim the prefix in the group-function when transforming candidates for display. Best, Eshel ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-07-14 10:55 ` Eshel Yaron @ 2024-07-14 17:00 ` Juri Linkov 2024-07-16 6:57 ` Eshel Yaron 2024-08-14 1:41 ` master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) Stefan Monnier 0 siblings, 2 replies; 36+ messages in thread From: Juri Linkov @ 2024-07-14 17:00 UTC (permalink / raw) To: Eshel Yaron; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel >>> I'm afraid imenu-flatten=annotation has one more hurdle to overcome. >>> Consider: >>> >>> 1. emacs -Q >>> 2. (setq imenu-flatten 'annotation) >>> 2. C-x C-f .../lisp/imenu.el >>> 3. M-g i >>> 4. M-<down> M-<down> M-<down> M-<down> ... >>> 5. Now the selected candidate in *Completions* is e.g. imenu--cleanup, >>> this is also the minibuffer contents, so far so good. >>> 6. Type M-RET to jump to this candidate. >>> 7. Land on imenu instead of imenu--cleanup. >>> >>> No matter how far down you go with M-<down>, if you go through the entry >>> for imenu, that's where you'll land when you hit M-RET. This is because >>> imenu-flatten=annotation tries to identify candidates by their text >>> properties, but completion--replace retains common parts while replacing >>> minibuffer text, along with the text properties of these common parts. >>> >>> This affects imenu-flatten=group too. >>> >>> It might be possible to resolve this by setting a different >>> completion-list-insert-choice-function that circumvents replaces the >>> whole minibuffer contents, unlike completion--replace, which tries hard >>> to preserve markers etc. >> >> Maybe then imenu--completion-buffer should try to get the text property >> from the end of completion? Provided that completion--replace will keep >> some properties at the end instead of using insert-and-inherit. > > I'm not sure, I think that might work in some cases, but since > completion--replace also keeps the common suffix it may still suffer > from the same issue when going from candidate "foo-baz" to "bar-baz". > > Then there's the problem of what happens when you simply type the > candidate you want to jump to, without completion. For example > M-g i imenu RET goes to the imenu function when imenu-flatten=nil, > but if imenu-flatten=annotation then it goes to the defgroup. > > What I would suggest is to ensure completion candidates are unambiguous > as strings rather than relying on text properties. Namely: Unfortunately, that'd be a step back. Maybe at least we could document limitations that annotations work only by selection. > - Restore imenu-flatten to a boolean option: either flat or nested. > - If imenu-flatten is non-nil, prepend the full prefix to each candidate, > like imenu-flatten=prefix does currently. This takes care of > disambiguating the candidate strings. It can't be boolean, because a more reliable replacement for annotations would be appending the suffix, i.e. by the new value 'suffix'. > - If completions-group is also non-nil, then group candidates according > to their prefix and trim the prefix in the group-function when > transforming candidates for display. The disadvantage of completions-group is its too wide coverage. We should strive for more specific options where possible. Or better: let's enable groups by category. I don't know why we have such a glaring omission that groups still can't be enabled by category. This should be simple to implement: diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index d8df001159f..f26a49a019f 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -1809,7 +1809,8 @@ completion-all-sorted-completions minibuffer-completion-table minibuffer-completion-predicate)) (sort-fun (completion-metadata-get all-md 'cycle-sort-function)) - (group-fun (completion-metadata-get all-md 'group-function))) + (group-fun (completion-metadata-get all-md 'group-function)) + (group (completion-metadata-get all-md 'group))) (when last (setcdr last nil) @@ -1821,7 +1822,7 @@ completion-all-sorted-completions (cond (sort-fun (setq all (funcall sort-fun all))) - ((and completions-group group-fun) + ((and (or completions-group group) group-fun) ;; TODO: experiment with re-grouping here. Might be slow ;; if the group-fun (given by the table and out of our ;; control) is slow and/or allocates too much. ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-07-14 17:00 ` Juri Linkov @ 2024-07-16 6:57 ` Eshel Yaron 2024-08-07 6:51 ` Juri Linkov 2024-08-07 6:56 ` Completions group metadata [was: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846)] Juri Linkov 2024-08-14 1:41 ` master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) Stefan Monnier 1 sibling, 2 replies; 36+ messages in thread From: Eshel Yaron @ 2024-07-16 6:57 UTC (permalink / raw) To: Juri Linkov; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel Hi Juri, Juri Linkov <juri@linkov.net> writes: >>> Maybe then imenu--completion-buffer should try to get the text property >>> from the end of completion? Provided that completion--replace will keep >>> some properties at the end instead of using insert-and-inherit. >> >> I'm not sure, I think that might work in some cases, but since >> completion--replace also keeps the common suffix it may still suffer >> from the same issue when going from candidate "foo-baz" to "bar-baz". >> >> Then there's the problem of what happens when you simply type the >> candidate you want to jump to, without completion. For example >> M-g i imenu RET goes to the imenu function when imenu-flatten=nil, >> but if imenu-flatten=annotation then it goes to the defgroup. I forgot to mention that this also affects using previous minibuffer inputs with M-p: the text properties aren't recorded in the history list, so you get an ambiguous input that doesn't always take you to where you went when you previously used that input. >> What I would suggest is to ensure completion candidates are unambiguous >> as strings rather than relying on text properties. Namely: > > Unfortunately, that'd be a step back. Maybe at least we could document > limitations that annotations work only by selection. Indeed my suggestion was to take a step back of sorts. If it's too late for that, I agree it's a good idea to document the known issues. > >> - Restore imenu-flatten to a boolean option: either flat or nested. >> - If imenu-flatten is non-nil, prepend the full prefix to each candidate, >> like imenu-flatten=prefix does currently. This takes care of >> disambiguating the candidate strings. > > It can't be boolean, because a more reliable replacement for annotations > would be appending the suffix, i.e. by the new value 'suffix'. That makes sense. >> - If completions-group is also non-nil, then group candidates according >> to their prefix and trim the prefix in the group-function when >> transforming candidates for display. > > The disadvantage of completions-group is its too wide coverage. > We should strive for more specific options where possible. Right. The advantage, on the other hand, is that you can toggle completions-group on the fly in the minibuffer, either with toggle-option or with a dedicated command. The wide coverage of completions-group means there's just one variable to toggle, always. > Or better: let's enable groups by category. I don't know why we have > such a glaring omission that groups still can't be enabled by > category. This should be simple to implement: Doesn't the group-function metadata entry give enough control already? If a category or a specific completion table wants to disable grouping, it can simply avoid providing a group-function. If it wants to enable grouping, then it does provide a group-function, and now it's up to the user's preferences which they express by setting completions-group. Maybe your suggestion yields more flexibility in some cases? Best, Eshel ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-07-16 6:57 ` Eshel Yaron @ 2024-08-07 6:51 ` Juri Linkov 2024-08-07 8:33 ` Eshel Yaron 2024-08-07 6:56 ` Completions group metadata [was: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846)] Juri Linkov 1 sibling, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-08-07 6:51 UTC (permalink / raw) To: Eshel Yaron; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel > I forgot to mention that this also affects using previous minibuffer > inputs with M-p: the text properties aren't recorded in the history > list, so you get an ambiguous input that doesn't always take you to > where you went when you previously used that input. Do you mean that text properties are not saved between sessions? Because in the same session text properties are preserved in the history. (This assumes that you select candidates by completion selection UI.) >> Unfortunately, that'd be a step back. Maybe at least we could document >> limitations that annotations work only by selection. > > Indeed my suggestion was to take a step back of sorts. If it's too late > for that, I agree it's a good idea to document the known issues. Ok, so here is a patch for emacs-30: diff --git a/lisp/imenu.el b/lisp/imenu.el index 708a39a0f71..ae030e0104a 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -158,6 +158,9 @@ imenu-flatten with a suffix that is the section name to which it belongs. If the value is `group', split completion candidates into groups according to the sections. +Since the values `annotation' and `group' rely on text properties, +you can use them only by selecting candidates from the completions +buffer, not by typing in the minibuffer. Any other value is treated as `prefix'. >> It can't be boolean, because a more reliable replacement for annotations >> would be appending the suffix, i.e. by the new value 'suffix'. > > That makes sense. Ok, here is the implementation for emacs-30 where documentation could be added later to not cause merge conflicts with the documentation changes above: diff --git a/lisp/imenu.el b/lisp/imenu.el index 708a39a0f71..31937d3f333 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -827,6 +830,9 @@ imenu--flatten-index-alist ('group (propertize name 'imenu-section (or prefix "*") 'imenu-choice item)) + ('suffix (if prefix + (concat name imenu-level-separator prefix) + name)) (_ new-prefix)) pos))) ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-08-07 6:51 ` Juri Linkov @ 2024-08-07 8:33 ` Eshel Yaron 2024-08-07 16:46 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Eshel Yaron @ 2024-08-07 8:33 UTC (permalink / raw) To: Juri Linkov; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel Hi Juri, Juri Linkov <juri@linkov.net> writes: >> I forgot to mention that this also affects using previous minibuffer >> inputs with M-p: the text properties aren't recorded in the history >> list, so you get an ambiguous input that doesn't always take you to >> where you went when you previously used that input. > > Do you mean that text properties are not saved between sessions? > Because in the same session text properties are preserved in the history. > (This assumes that you select candidates by completion selection UI.) Hmm right, I probably didn't select the candidate from the completions UI when I tested this scenario. >>> Unfortunately, that'd be a step back. Maybe at least we could document >>> limitations that annotations work only by selection. >> >> Indeed my suggestion was to take a step back of sorts. If it's too late >> for that, I agree it's a good idea to document the known issues. > > Ok, so here is a patch for emacs-30: > > diff --git a/lisp/imenu.el b/lisp/imenu.el > index 708a39a0f71..ae030e0104a 100644 > --- a/lisp/imenu.el > +++ b/lisp/imenu.el > @@ -158,6 +158,9 @@ imenu-flatten > with a suffix that is the section name to which it belongs. > If the value is `group', split completion candidates into groups > according to the sections. > +Since the values `annotation' and `group' rely on text properties, > +you can use them only by selecting candidates from the completions > +buffer, not by typing in the minibuffer. > Any other value is treated as `prefix'. > >>> It can't be boolean, because a more reliable replacement for annotations >>> would be appending the suffix, i.e. by the new value 'suffix'. >> >> That makes sense. > > Ok, here is the implementation for emacs-30 where documentation could be > added later to not cause merge conflicts with the documentation changes above: > > diff --git a/lisp/imenu.el b/lisp/imenu.el > index 708a39a0f71..31937d3f333 100644 > --- a/lisp/imenu.el > +++ b/lisp/imenu.el > @@ -827,6 +830,9 @@ imenu--flatten-index-alist > ('group (propertize name > 'imenu-section (or prefix "*") > 'imenu-choice item)) > + ('suffix (if prefix > + (concat name imenu-level-separator prefix) > + name)) > (_ new-prefix)) > pos))) Both of these changes look like nice improvements to me :) Cheers, Eshel ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-08-07 8:33 ` Eshel Yaron @ 2024-08-07 16:46 ` Juri Linkov 2024-08-09 6:59 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-08-07 16:46 UTC (permalink / raw) To: Eshel Yaron; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel >> @@ -827,6 +830,9 @@ imenu--flatten-index-alist >> ('group (propertize name >> 'imenu-section (or prefix "*") >> 'imenu-choice item)) >> + ('suffix (if prefix >> + (concat name imenu-level-separator prefix) >> + name)) >> (_ new-prefix)) >> pos))) > > Both of these changes look like nice improvements to me :) Now the documentation change is pushed to emacs-30, but implementation of the 'suffix' value is problematic since I remembered it's ambiguous: https://lists.gnu.org/archive/html/emacs-devel/2024-05/msg01224.html So probably need two separate suffix values. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-08-07 16:46 ` Juri Linkov @ 2024-08-09 6:59 ` Juri Linkov 2024-08-09 7:11 ` Eli Zaretskii 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-08-09 6:59 UTC (permalink / raw) To: Eshel Yaron; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel >> Both of these changes look like nice improvements to me :) > > Now the documentation change is pushed to emacs-30, > but implementation of the 'suffix' value is problematic > since I remembered it's ambiguous: > https://lists.gnu.org/archive/html/emacs-devel/2024-05/msg01224.html > So probably need two separate suffix values. Ok, here are two new suffix values for both variants: "<IDENT> <SUB-CATEGORY-TOP> <SUB-CATEGORY-BOTTOM>" and "<IDENT> <SUB-CATEGORY-BOTTOM> <SUB-CATEGORY-TOP>" diff --git a/lisp/imenu.el b/lisp/imenu.el index 8f1b1f22a67..99d9d4a5582 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -154,6 +154,10 @@ imenu-flatten If the value is `prefix', pop up the completion buffer with a flattened menu where section names are prepended to completion candidates as prefixes. +If the value is `suffix', use section names appended to completion +candidates as suffixes. +The value `suffix-reverse' is like `suffix', but the section names +are in reverse order. If the value is `annotation', annotate each completion candidate with a suffix that is the section name to which it belongs. If the value is `group', split completion candidates into groups @@ -168,6 +172,8 @@ imenu-flatten names of completion candidates." :type '(choice (const :tag "Show nested list" nil) (const :tag "Flat list with sections as prefix" prefix) + (const :tag "Flat list with sections as suffix" suffix) + (const :tag "Flat list with reverse sections as suffix" suffix-reverse) (const :tag "Flat list annotated with sections" annotation) (const :tag "Flat list grouped by sections" group)) :version "30.1") @@ -816,7 +822,9 @@ imenu--flatten-index-alist (pos (cdr item)) (new-prefix (and concat-names (if prefix - (concat prefix imenu-level-separator name) + (if (eq imenu-flatten 'suffix-reverse) + (concat name imenu-level-separator prefix) + (concat prefix imenu-level-separator name)) name)))) (cond ((not (imenu--subalist-p item)) @@ -830,6 +838,9 @@ imenu--flatten-index-alist ('group (propertize name 'imenu-section (or prefix "*") 'imenu-choice item)) + ('suffix (if prefix + (concat name imenu-level-separator prefix) + name)) (_ new-prefix)) pos))) (t ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-08-09 6:59 ` Juri Linkov @ 2024-08-09 7:11 ` Eli Zaretskii 2024-08-09 16:10 ` Juri Linkov 0 siblings, 1 reply; 36+ messages in thread From: Eli Zaretskii @ 2024-08-09 7:11 UTC (permalink / raw) To: Juri Linkov; +Cc: me, monnier, emacs-devel > From: Juri Linkov <juri@linkov.net> > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, Eli Zaretskii > <eliz@gnu.org>, emacs-devel@gnu.org > Date: Fri, 09 Aug 2024 09:59:40 +0300 > > :type '(choice (const :tag "Show nested list" nil) > (const :tag "Flat list with sections as prefix" prefix) > + (const :tag "Flat list with sections as suffix" suffix) > + (const :tag "Flat list with reverse sections as suffix" suffix-reverse) "Reverse sections"? Can we make this tag text more clear? ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-08-09 7:11 ` Eli Zaretskii @ 2024-08-09 16:10 ` Juri Linkov 2024-08-09 17:43 ` Eli Zaretskii 0 siblings, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-08-09 16:10 UTC (permalink / raw) To: Eli Zaretskii; +Cc: me, monnier, emacs-devel >> :type '(choice (const :tag "Show nested list" nil) >> (const :tag "Flat list with sections as prefix" prefix) >> + (const :tag "Flat list with sections as suffix" suffix) >> + (const :tag "Flat list with reverse sections as suffix" suffix-reverse) > > "Reverse sections"? Can we make this tag text more clear? I have no idea. Another problem is that the tag is too long. This will make it shorter: "Flat list with reverse suffix". An unclear tag is not a problem since it's explained in the docstring. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-08-09 16:10 ` Juri Linkov @ 2024-08-09 17:43 ` Eli Zaretskii 0 siblings, 0 replies; 36+ messages in thread From: Eli Zaretskii @ 2024-08-09 17:43 UTC (permalink / raw) To: Juri Linkov; +Cc: me, monnier, emacs-devel > From: Juri Linkov <juri@linkov.net> > Cc: me@eshelyaron.com, monnier@iro.umontreal.ca, emacs-devel@gnu.org > Date: Fri, 09 Aug 2024 19:10:09 +0300 > > >> :type '(choice (const :tag "Show nested list" nil) > >> (const :tag "Flat list with sections as prefix" prefix) > >> + (const :tag "Flat list with sections as suffix" suffix) > >> + (const :tag "Flat list with reverse sections as suffix" suffix-reverse) > > > > "Reverse sections"? Can we make this tag text more clear? > > I have no idea. How about "Flat list, sections as suffix, in reverse order of sections." > Another problem is that the tag is too long. That usually means the option is over-engineered. > This will make it shorter: "Flat list with reverse suffix". I don't understand what us "reverse suffix". AFAIU, the "reverse" part refers to order, not to the suffixes. > An unclear tag is not a problem since it's explained in the docstring. I disagree. If an unclear tag would not be a problem, we could just make the tag be the name of the corresponding symbol. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Completions group metadata [was: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846)] 2024-07-16 6:57 ` Eshel Yaron 2024-08-07 6:51 ` Juri Linkov @ 2024-08-07 6:56 ` Juri Linkov 2024-08-09 16:16 ` Completions group metadata [ Juri Linkov 1 sibling, 1 reply; 36+ messages in thread From: Juri Linkov @ 2024-08-07 6:56 UTC (permalink / raw) To: Eshel Yaron; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel >>> - If completions-group is also non-nil, then group candidates according >>> to their prefix and trim the prefix in the group-function when >>> transforming candidates for display. >> >> The disadvantage of completions-group is its too wide coverage. >> We should strive for more specific options where possible. > > Right. The advantage, on the other hand, is that you can toggle > completions-group on the fly in the minibuffer, either with > toggle-option or with a dedicated command. The wide coverage of > completions-group means there's just one variable to toggle, always. Interesting. Then this requires such precedence (from high to low): buffer-local value of completions-group -> metadata -> default-value of completions-group >> Or better: let's enable groups by category. I don't know why we have >> such a glaring omission that groups still can't be enabled by >> category. This should be simple to implement: > > Doesn't the group-function metadata entry give enough control already? It's not easy for users to customize group-function metadata by writing own group function. Whereas with a boolean its easy to toggle it in the Customization UI for completion-category-overrides. > If a category or a specific completion table wants to disable grouping, > it can simply avoid providing a group-function. If it wants to enable > grouping, then it does provide a group-function, and now it's up to the > user's preferences which they express by setting completions-group. > Maybe your suggestion yields more flexibility in some cases? It makes sense to provide a group-function disabled by default to help users just to enable it in completion-category-overrides instead of writing it from scratch. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Completions group metadata [ 2024-08-07 6:56 ` Completions group metadata [was: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846)] Juri Linkov @ 2024-08-09 16:16 ` Juri Linkov 0 siblings, 0 replies; 36+ messages in thread From: Juri Linkov @ 2024-08-09 16:16 UTC (permalink / raw) To: Eshel Yaron; +Cc: Stefan Monnier, Eli Zaretskii, emacs-devel [-- Attachment #1: Type: text/plain, Size: 2464 bytes --] >>>> - If completions-group is also non-nil, then group candidates according >>>> to their prefix and trim the prefix in the group-function when >>>> transforming candidates for display. >>> >>> The disadvantage of completions-group is its too wide coverage. >>> We should strive for more specific options where possible. >> >> Right. The advantage, on the other hand, is that you can toggle >> completions-group on the fly in the minibuffer, either with >> toggle-option or with a dedicated command. The wide coverage of >> completions-group means there's just one variable to toggle, always. > > Interesting. Then this requires such precedence (from high to low): > > buffer-local value of completions-group -> metadata -> default-value > of completions-group The patch below doesn't yet implement this precedence since I can't find a dedicated command that toggles completions-group on the fly. Such a command doesn't exist even in your branch 'feature/minibuffer-completion-enhancements'. And anyway this should be improved at the same time with introducing a support for toggling the sorting order, layout, etc. >>> Or better: let's enable groups by category. I don't know why we have >>> such a glaring omission that groups still can't be enabled by >>> category. This should be simple to implement: >> >> Doesn't the group-function metadata entry give enough control already? > > It's not easy for users to customize group-function metadata > by writing own group function. Whereas with a boolean its easy > to toggle it in the Customization UI for completion-category-overrides. Regarding the value 'group' of imenu-flatten, it can't be removed since it's used in imenu--flatten-index-alist, so the patch hard-codes ':group-p t' for the value 'group'. >> If a category or a specific completion table wants to disable grouping, >> it can simply avoid providing a group-function. If it wants to enable >> grouping, then it does provide a group-function, and now it's up to the >> user's preferences which they express by setting completions-group. >> Maybe your suggestion yields more flexibility in some cases? > > It makes sense to provide a group-function disabled by default > to help users just to enable it in completion-category-overrides > instead of writing it from scratch. Here is the patch that supports (setopt completion-category-overrides '((unicode-name (group-p . t)))) without enabling the global 'completions-group'. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: completions-group-p.patch --] [-- Type: text/x-diff, Size: 4671 bytes --] diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el index 7d784ef3b1b..e0c282a54e5 100644 --- a/lisp/international/mule-cmds.el +++ b/lisp/international/mule-cmds.el @@ -3260,8 +3260,7 @@ read-char-by-name (affixation-function . ,#'mule--ucs-names-affixation) (group-function - . ,(when completions-group - #'mule--ucs-names-group)) + . ,#'mule--ucs-names-group) (category . unicode-name)) (complete-with-action action (ucs-names) string pred))))) (char diff --git a/lisp/imenu.el b/lisp/imenu.el index 8f1b1f22a67..6efa2d55966 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -770,11 +776,12 @@ imenu--completion-buffer ,(lambda (s) (get-text-property 0 'imenu-section s)))) ,@(when (eq imenu-flatten 'group) - `(:group-function - ,(lambda (s transform) - (if transform s - (get-text-property - 0 'imenu-section s))))))) + `( :group-p t + :group-function + ,(lambda (s transform) + (if transform s + (get-text-property + 0 'imenu-section s))))))) (unless imenu-eager-completion-buffer (minibuffer-completion-help))) (setq name (completing-read prompt diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index e8e0f169197..1269bab0d40 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -1231,6 +1231,10 @@ completion-category-overrides (const :tag "Historical sorting" minibuffer-sort-by-history) (function :tag "Custom function"))) + (cons :tag "Use Groups" + (const :tag "Enable groups." + group-p) + (boolean)) (cons :tag "Completion Groups" (const :tag "Select one value from the menu." group-function) @@ -1809,7 +1813,8 @@ completion-all-sorted-completions minibuffer-completion-table minibuffer-completion-predicate)) (sort-fun (completion-metadata-get all-md 'cycle-sort-function)) - (group-fun (completion-metadata-get all-md 'group-function))) + (group-fun (completion-metadata-get all-md 'group-function)) + (group-p (completion-metadata-get all-md 'group-p))) (when last (setcdr last nil) @@ -1821,7 +1826,7 @@ completion-all-sorted-completions (cond (sort-fun (setq all (funcall sort-fun all))) - ((and completions-group group-fun) + ((and (or completions-group group-p) group-fun) ;; TODO: experiment with re-grouping here. Might be slow ;; if the group-fun (given by the table and out of our ;; control) is slow and/or allocates too much. @@ -2610,7 +2615,9 @@ minibuffer-completion-help (ann-fun (completion-metadata-get all-md 'annotation-function)) (aff-fun (completion-metadata-get all-md 'affixation-function)) (sort-fun (completion-metadata-get all-md 'display-sort-function)) - (group-fun (completion-metadata-get all-md 'group-function)) + (group-p (completion-metadata-get all-md 'group-p)) + (group-fun (when (or completions-group group-p) + (completion-metadata-get all-md 'group-function))) (mainbuf (current-buffer)) ;; If the *Completions* buffer is shown in a new ;; window, mark it as softly-dedicated, so bury-buffer in diff --git a/lisp/icomplete.el b/lisp/icomplete.el index 2ea5e36fa88..07b8ec83cf9 100644 --- a/lisp/icomplete.el +++ b/lisp/icomplete.el @@ -791,8 +791,7 @@ icomplete--augment by `group-function''s second \"transformation\" protocol." (let* ((aff-fun (completion-metadata-get md 'affixation-function)) (ann-fun (completion-metadata-get md 'annotation-function)) - (grp-fun (and completions-group - (completion-metadata-get md 'group-function))) + (grp-fun (completion-metadata-get md 'group-function)) (annotated (cond (aff-fun (funcall aff-fun prospects)) ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-07-14 17:00 ` Juri Linkov 2024-07-16 6:57 ` Eshel Yaron @ 2024-08-14 1:41 ` Stefan Monnier 2024-08-20 17:51 ` Juri Linkov 1 sibling, 1 reply; 36+ messages in thread From: Stefan Monnier @ 2024-08-14 1:41 UTC (permalink / raw) To: Juri Linkov; +Cc: Eshel Yaron, Eli Zaretskii, emacs-devel >> What I would suggest is to ensure completion candidates are unambiguous >> as strings rather than relying on text properties. Namely: > Unfortunately, that'd be a step back. Maybe at least we could document > limitations that annotations work only by selection. How about we make them unambiguous by adding text *at the end* (and only if there's ambiguity)? The completion code assumes in all kinds of places that the same text means the same thing, so using the same text to mean different completion choices will get you in trouble in all kinds of corner (and not so corner) cases. Stefan ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-08-14 1:41 ` master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) Stefan Monnier @ 2024-08-20 17:51 ` Juri Linkov 0 siblings, 0 replies; 36+ messages in thread From: Juri Linkov @ 2024-08-20 17:51 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eshel Yaron, Eli Zaretskii, emacs-devel >>> What I would suggest is to ensure completion candidates are unambiguous >>> as strings rather than relying on text properties. Namely: >> Unfortunately, that'd be a step back. Maybe at least we could document >> limitations that annotations work only by selection. > > How about we make them unambiguous by adding text *at the end* (and > only if there's ambiguity)? > > The completion code assumes in all kinds of places that the same text > means the same thing, so using the same text to mean different > completion choices will get you in trouble in all kinds of corner (and > not so corner) cases. Ok, this patch adds the suffix only to ambiguous items. At least it helps to get the right item for the case when not selecting candidates from the completions list. OTOH, it still doesn't solve the original issue of using `M-<down> M-<down> M-RET` where `completion--replace` keeps properties of previous completion strings by using `insert-and-inherit`. ``` diff --git a/lisp/imenu.el b/lisp/imenu.el index 8f1b1f22a67..e151a685ce5 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -740,6 +740,24 @@ imenu--completion-buffer Return one of the entries in index-alist or nil." ;; Create a list for this buffer only when needed. + (when (eq imenu-flatten 'annotation) + (let ((hash (make-hash-table :test 'equal))) + (dolist (item index-alist) + (puthash (car item) (1+ (gethash (car item) hash 0)) hash)) + (setq index-alist + (mapcar (lambda (item) + (if (> (gethash (car item) hash) 1) + (cons (let ((ann (get-text-property + 0 'imenu-section (car item)))) + (if ann + (concat (propertize (car item) + 'imenu-section nil) + imenu-level-separator + (substring ann 1)) + (car item))) + (cdr item)) + item)) + index-alist)))) (let ((name (thing-at-point 'symbol)) choice (prepared-index-alist ``` ^ permalink raw reply related [flat|nested] 36+ messages in thread
* RE: [External] : Re: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) 2024-05-14 6:08 ` Juri Linkov 2024-05-14 6:38 ` Eli Zaretskii @ 2024-05-14 15:26 ` Drew Adams 1 sibling, 0 replies; 36+ messages in thread From: Drew Adams @ 2024-05-14 15:26 UTC (permalink / raw) To: Juri Linkov, Eshel Yaron; +Cc: emacs-devel@gnu.org > Here is a new variable that helps to disambiguate completions with > the same name but different annotations by using text properties: > (defcustom completion-allow-text-properties nil > "Non-nil means `choose-completion' should not > discard text properties. > This also affects `completing-read' and any of the > functions that do > minibuffer input with completion." > :type 'boolean :version "30.1" :group 'completion) ___ FWIW, since 2008 Icicles has had this feature. I tried several times, unsuccessfully, to persuade vanilla Emacs to add it, i.e., to allow the result of completion to keep text properties, unless a user option says to strip them. IOW, the default behavior in Icicles is to _keep_, not to remove, text properties. Emacs should do the same, in order to, as you say, let code "disambiguate completions with the same name". Hard to believe this hasn't even been possible till now, let alone been done by default. ___ `icicle-unpropertize-completion-result-flag' is a variable defined in `icicles-opt.el'. Its value is nil Documentation: Non-nil means strip text properties from the completion result. Set or bind this option to non-nil only if you need to ensure, for some other library, that the string returned by `completing-read' and `read-file-name' has no text properties. Typically, you will not use a non-nil value. Internal text properties added by Icicles are always removed anyway. A non-nil value lets you also remove properties such as `face'. ___ As for whether a user option is appropriate: yes. But I don't take the view that no code should ever bind a user option. ^ permalink raw reply [flat|nested] 36+ messages in thread
end of thread, other threads:[~2024-08-20 17:51 UTC | newest] Thread overview: 36+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <171558357066.26019.9766615061719600757@vcs2.savannah.gnu.org> [not found] ` <20240513065931.0D83AC12C31@vcs2.savannah.gnu.org> 2024-05-13 9:22 ` master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) Eshel Yaron 2024-05-13 16:30 ` Juri Linkov 2024-05-14 6:08 ` Juri Linkov 2024-05-14 6:38 ` Eli Zaretskii 2024-05-14 13:10 ` Stefan Monnier 2024-05-14 16:46 ` Juri Linkov 2024-05-14 20:58 ` Daniel Mendler via Emacs development discussions. 2024-05-14 23:26 ` FW: [External] : " Drew Adams 2024-05-15 16:51 ` Juri Linkov 2024-05-15 18:03 ` Eli Zaretskii 2024-05-15 18:30 ` Eshel Yaron 2024-05-16 6:08 ` Juri Linkov 2024-05-16 9:51 ` Eli Zaretskii 2024-05-17 6:48 ` Juri Linkov 2024-05-17 15:36 ` Stefan Monnier 2024-05-17 16:43 ` Juri Linkov 2024-05-18 15:12 ` Stefan Monnier 2024-05-20 6:46 ` Juri Linkov 2024-05-27 18:18 ` Juri Linkov 2024-07-14 6:28 ` Eshel Yaron 2024-07-14 6:53 ` Juri Linkov 2024-07-14 10:55 ` Eshel Yaron 2024-07-14 17:00 ` Juri Linkov 2024-07-16 6:57 ` Eshel Yaron 2024-08-07 6:51 ` Juri Linkov 2024-08-07 8:33 ` Eshel Yaron 2024-08-07 16:46 ` Juri Linkov 2024-08-09 6:59 ` Juri Linkov 2024-08-09 7:11 ` Eli Zaretskii 2024-08-09 16:10 ` Juri Linkov 2024-08-09 17:43 ` Eli Zaretskii 2024-08-07 6:56 ` Completions group metadata [was: master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846)] Juri Linkov 2024-08-09 16:16 ` Completions group metadata [ Juri Linkov 2024-08-14 1:41 ` master 431f8ff1e38: * lisp/imenu.el: Support more values for imenu-flatten (bug#70846) Stefan Monnier 2024-08-20 17:51 ` Juri Linkov 2024-05-14 15:26 ` [External] : " Drew Adams
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.