Subject: Re: bug#70846: Imenu flatten

From: Juri Linkov <[email-masked]>
Date: Tue, 28 May 2024 20:53:18 +0300

>> +(defcustom imenu-flatten nil
>> +  "If non-nil, popup the completion buffer with a flattened menu.
>> +The string from `imenu-level-separator' is used to separate names of
>> +nested levels while flattening nested indexes with name concatenation."
>> +  :type 'boolean
>
> Here is another useful value for `imenu-flatten' that
> will show section names as a suffix instead of a prefix:

Here is the final patch that adds an option to group Imenu completions.

diff --git a/lisp/imenu.el b/lisp/imenu.el
index 93d84106ec1..3aec32fa708 100644
--- a/lisp/imenu.el
+++ b/lisp/imenu.el
@@ -151,15 +151,18 @@ imenu-level-separator
 (defcustom imenu-flatten nil
   "Whether to flatten the list of sections in an imenu or show it nested.
 If nil, use nested indexes.
-If t, pop up the completion buffer with a flattened menu.
+If `prefix', pop up the completion buffer with a flattened menu
+where section names are used as a prefix.
 If `annotation', use completion annotation as a suffix
 to append section names after the index names.
+If `group', split completions into groups.
 
 The string from `imenu-level-separator' is used to separate names of
 nested levels while flattening nested indexes with name concatenation."
   :type '(choice (const :tag "Nested" nil)
-                 (const :tag "By prefix" t)
-                 (const :tag "By suffix" annotation))
+                 (const :tag "By prefix" prefix)
+                 (const :tag "By annotation" annotation)
+                 (const :tag "By group" group))
   :version "30.1")
 
 (defcustom imenu-generic-skip-comments-and-strings t
@@ -758,7 +761,13 @@ imenu--completion-buffer
                          ,@(when (eq imenu-flatten 'annotation)
                              `(:annotation-function
                                ,(lambda (s) (get-text-property
-                                             0 'imenu-section s))))))
+                                             0 'imenu-section s))))
+                         ,@(when (eq imenu-flatten 'group)
+                             `(: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
@@ -801,15 +810,20 @@ imenu--flatten-index-alist
 	    (new-prefix (and concat-names
 			     (if prefix
 				 (concat prefix imenu-level-separator name)
-			       (if (eq imenu-flatten 'annotation)
-                                   (propertize name 'imenu-choice item)
-                                 name)))))
+			       name))))
        (cond
 	((not (imenu--subalist-p item))
-	 (list (cons (if (and (eq imenu-flatten 'annotation) prefix)
-			 (propertize name 'imenu-section
-				     (format " (%s)" prefix))
-		       new-prefix)
+	 (list (cons (pcase imenu-flatten
+                       ('annotation
+                        (if prefix
+                            (propertize name
+                                        'imenu-section (format " (%s)" prefix)
+                                        'imenu-choice item)
+                          (propertize new-prefix 'imenu-choice item)))
+                       ('group (propertize name
+                                           'imenu-section (or prefix "*")
+                                           'imenu-choice item))
+                       (_ new-prefix))
 		     pos)))
 	(t
 	 (imenu--flatten-index-alist pos concat-names new-prefix)))))