From 1abc54ffe1674fecfb2bbef5109eb95c4c0da99d Mon Sep 17 00:00:00 2001 From: Drew Adams Date: Sat, 12 Jul 2025 17:17:36 +0000 Subject: [PATCH] Allow duplicate menu entries in Imenu * lisp/imenu.el (imenu-allow-duplicate-menu-items): New user option. (imenu--create-keymap): Allow duplicate imenu items if 'imenu-allow-duplicate-menu-items' is non-nil. * etc/NEWS: Announce the change. (Bug#78935) --- etc/NEWS | 9 +++++++++ lisp/imenu.el | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 0653ce74287..35ba75b9feb 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1665,6 +1665,15 @@ the 'grep' results editable. The edits will be reflected in the buffer visiting the originating file. Typing 'C-c C-c' will leave the Grep Edit mode. +** Imenu + +--- +*** New user option 'imenu-allow-duplicate-menu-items'. +This specifies whether Imenu can include duplicate menu items. +Duplicate items are now allowed by default (option value 't'), which +restores the behavior before Emacs 29. Customize this to nil to get the +behavior of Emacs 29 and Emacs 30. + ** Time Stamp --- diff --git a/lisp/imenu.el b/lisp/imenu.el index 0cf18447f62..41c4b5cee91 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -193,6 +193,18 @@ uses `imenu--generic-function')." :type 'number :version "28.1") +(defcustom imenu-allow-duplicate-menu-items t + "Non-nil means that Imenu can include duplicate menu items. +For example, if the buffer contains multiple definitions of function +`foo' then a menu item is included for each of them. +Otherwise, only the first such definition is accessible from the menu. + +This option applies only to an Imenu menu, not also to the use of +command `imenu', which uses `completing-read' to read a menu item. +The use of that command doesn't allow duplicate items." + :type 'boolean + :version "31.1") + ;;;###autoload (defvar-local imenu-generic-expression nil "List of definition matchers for creating an Imenu index. @@ -505,15 +517,26 @@ Non-nil arguments are in recursive calls." (defun imenu--create-keymap (title alist &optional cmd) `(keymap ,title ,@(mapcar - (lambda (item) - `(,(intern (car item)) ,(car item) - ,@(cond - ((imenu--subalist-p item) - (imenu--create-keymap (car item) (cdr item) cmd)) - (t - (lambda () (interactive) - (if cmd (funcall cmd item) item)))))) - (seq-filter #'identity alist)))) + (if imenu-allow-duplicate-menu-items + (lambda (item) + `(,(car item) + ,(car item) + ,@(cond + ((imenu--subalist-p item) + (imenu--create-keymap (car item) (cdr item) cmd)) + (t + (lambda () (interactive) + (if cmd (funcall cmd item) item)))))) + (lambda (item) + `(,(intern (car item)) + ,(car item) + ,@(cond + ((imenu--subalist-p item) + (imenu--create-keymap (car item) (cdr item) cmd)) + (t + (lambda () (interactive) + (if cmd (funcall cmd item) item))))))) + (remq nil alist)))) (defun imenu--in-alist (str alist) "Check whether the string STR is contained in multi-level ALIST."