This patch to Emacs 22's Imenu avoids finding positions inside comments
and strings and adds the command `imenu-all' which flattens the Imenu
structure so that you can do completion against all the names, regardless
of whether, for instance, they are functions or variables.

2005-10-07  Dave Love  <fx@gnu.org>

	* imenu.el: Doc fixes.
	(imenu--flat-index-alist, imenu--last-index)
	(imenu--flatten-alist, imenu-all): New.
	(imenu--make-index-alist): Set imenu--flat-index-alist.
	(imenu-default-create-index-function): Check position is outside
	comment/string.
	(imenu): Set imenu--last-index.

Index: imenu.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/imenu.el,v
retrieving revision 1.114
diff -u -p -u -r1.114 imenu.el
--- imenu.el	6 Aug 2005 22:13:43 -0000	1.114
+++ imenu.el	7 Oct 2005 16:54:31 -0000
@@ -270,6 +270,7 @@ The function in this variable is called 
 
 
 (defun imenu--subalist-p (item)
+  "Return non-nil if ITEM represents a sub-menu."
   (and (consp (cdr item)) (listp (cadr item))
        (not (eq (car (cadr item)) 'lambda))))
 
@@ -323,8 +324,8 @@ Don't move point."
 ;;;
 
 (defun imenu-example--lisp-extract-index-name ()
-  ;; Example of a candidate for `imenu-extract-index-name-function'.
-  ;; This will generate a flat index of definitions in a lisp file.
+  "Example of a candidate for `imenu-extract-index-name-function'.
+This will generate a flat index of definitions in a Lisp file."
   (save-match-data
     (and (looking-at "(def")
 	 (condition-case nil
@@ -337,8 +338,8 @@ Don't move point."
 	   (error nil)))))
 
 (defun imenu-example--create-lisp-index ()
-  ;; Example of a candidate for `imenu-create-index-function'.
-  ;; It will generate a nested index of definitions.
+  "Example of a candidate for `imenu-create-index-function'.
+It will generate a nested index of definitions."
   (let ((index-alist '())
 	(index-var-alist '())
 	(index-type-alist '())
@@ -425,8 +426,8 @@ Don't move point."
 ;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;; The item to use in the index for rescanning the buffer.
-(defconst imenu--rescan-item '("*Rescan*" . -99))
+(defconst imenu--rescan-item '("*Rescan*" . -99)
+  "The item to use in the index for rescanning the buffer.")
 
 ;; The latest buffer index.
 ;; Buffer local.
@@ -438,14 +439,24 @@ A nested sub-alist element looks like (I
 
 (make-variable-buffer-local 'imenu--index-alist)
 
+(defvar imenu--flat-index-alist nil
+  "A flattened form of `imenu--index-alist'.
+Made by operating on it with `imenu--flatten-alist'.")
+
+(make-variable-buffer-local 'imenu--flat-index-alist)
+
 (defvar imenu--last-menubar-index-alist nil
   "The latest buffer index used to update the menu bar menu.")
 
 (make-variable-buffer-local 'imenu--last-menubar-index-alist)
 
-;; History list for 'jump-to-function-in-buffer'.
+(defvar imenu--last-index nil
+  "The last index item used.")
+(make-variable-buffer-local 'imenu--last-index)
+
 ;; Making this buffer local caused it not to work!
-(defvar imenu--history-list nil)
+(defvar imenu--history-list nil
+  "History list for `jump-to-function-in-buffer'.")
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
@@ -465,9 +476,9 @@ A nested sub-alist element looks like (I
   (< (cdr item1) (cdr item2)))
 
 (defun imenu--relative-position (&optional reverse)
-  ;; Support function to calculate relative position in buffer
-  ;; Beginning of buffer is 0 and end of buffer is 100
-  ;; If REVERSE is non-nil then the beginning is 100 and the end is 0.
+  "Support function to calculate relative position in buffer.
+Beginning of buffer is 0 and end of buffer is 100.
+If REVERSE is non-nil then the beginning is 100 and the end is 0."
   (let ((pos (point))
 	(total (buffer-size)))
     (and reverse (setq pos (- total pos)))
@@ -476,9 +487,9 @@ A nested sub-alist element looks like (I
 	(/ (1- pos) (max (/ total 100) 1))
       (/ (* 100 (1- pos)) (max total 1)))))
 
-;; Split LIST into sublists of max length N.
-;; Example (imenu--split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8))
 (defun imenu--split (list n)
+  "Split LIST into sublists of max length N.
+Example (imenu--split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8))"
   (let ((remain list)
 	(result '())
 	(sublist '())
@@ -497,9 +508,9 @@ A nested sub-alist element looks like (I
 	 (push (nreverse sublist) result))
     (nreverse result)))
 
-;;; Split the alist MENULIST into a nested alist, if it is long enough.
-;;; In any case, add TITLE to the front of the alist.
 (defun imenu--split-menu (menulist title)
+  "Split the alist MENULIST into a nested alist, if it is long enough.
+In any case, add TITLE to the front of the alist."
   (let (keep-at-top tail)
     (if (memq imenu--rescan-item menulist)
 	(setq keep-at-top (cons imenu--rescan-item nil)
@@ -520,9 +531,8 @@ A nested sub-alist element looks like (I
     (cons title
 	  (nconc (nreverse keep-at-top) menulist))))
 
-;;; Split up each long alist that are nested within ALIST
-;;; into nested alists.
 (defun imenu--split-submenus (alist)
+  "Split up each long alist that are nested within ALIST into nested alists."
   (mapcar (function
 	   (lambda (elt)
 	     (if (and (consp elt)
@@ -532,8 +542,8 @@ A nested sub-alist element looks like (I
 	       elt)))
 	  alist))
 
-;;; Truncate all strings in MENULIST to imenu-max-item-length
 (defun imenu--truncate-items (menulist)
+  "Truncate all strings in MENULIST to `imenu-max-item-length'."
   (mapcar (function
 	   (lambda (item)
 	     (cond
@@ -571,6 +581,8 @@ as a way for the user to ask to recalcul
 		(save-restriction
 		  (widen)
 		  (funcall imenu-create-index-function))))
+	(setq imenu--flat-index-alist
+	      (imenu--flatten-alist imenu--index-alist))
 	(imenu--truncate-items imenu--index-alist)))
   (or imenu--index-alist noerror
       (error "No items suitable for an index found in this buffer"))
@@ -586,9 +598,9 @@ as a way for the user to ask to recalcul
 (defvar imenu--cleanup-seen)
 
 (defun imenu--cleanup (&optional alist)
-  ;; If alist is provided use that list.
-  ;; If not, empty the table of lists already seen
-  ;; and use imenu--index-alist.
+  "If ALIST is provided use that list.
+If not, empty the table of lists already seen
+and use `imenu--index-alist'."
   (if alist
       (setq imenu--cleanup-seen (cons alist imenu--cleanup-seen))
     (setq alist imenu--index-alist imenu--cleanup-seen (list alist)))
@@ -676,7 +688,7 @@ Their results are gathered into an index
 	     (save-excursion
 	       (setq name (funcall imenu-extract-index-name-function)))
 	     (and (stringp name)
- 		  ;; [ydi] updated for imenu-use-markers
+ 		  (not (save-match-data (syntax-ppss-context (syntax-ppss))))
 		  (push (cons name (if imenu-use-markers (point-marker) (point)))
 			index-alist)))
 	   (imenu-progress-message prev-pos 100 t)
@@ -1047,6 +1059,7 @@ for more information."
   ;; Convert a string to an alist element.
   (if (stringp index-item)
       (setq index-item (assoc index-item (imenu--make-index-alist))))
+  (setq imenu--last-index index-item)
   (when index-item
     (push-mark)
     (let* ((is-special-item (listp (cdr index-item)))
@@ -1058,6 +1071,58 @@ for more information."
 	   (rest (if is-special-item (cddr index-item))))
       (apply function (car index-item) position rest))
     (run-hooks 'imenu-after-jump-hook)))
+
+(defun imenu--flatten-alist (alist)
+  "Flatten an ALIST of the form of `imenu--index-alist'.
+This yields a simple alist with elements of the form
+\(INDEX-NAME . INDEX-POSITION) or
+\(INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...)."
+  (let (entries)
+    (dolist (elt alist)
+      (if (imenu--subalist-p elt)
+	  (setq entries (nconc entries (imenu--flatten-alist (cdr elt))))
+	(push elt entries)))
+    (nreverse entries)))
+
+;;;###autoload
+(defun imenu-all (index-item &optional after)
+  "Jump to a place in the buffer chosen using a buffer menu/completion.
+INDEX-ITEM specifies the position (prompted for interactively).
+
+This is mostly like `imenu' except that if the index has multiple
+levels, e.g. functions and variables, those levels are collapsed
+when searching for the item.  Interactively, with prefix arg,
+jump to the position of the next item (if any) in the index
+matching the last name found in the buffer by this command or
+\\[imenu].  E.g. in the imenu.el source, \\[imenu-all] jumps to
+the defgroup, and \\[universal-argument] \\[imenu-all] jumps to the defun.
+Programmatically, arg AFTER specifies the element in the list after
+which to search for INDEX-ITEM."
+  ;; Note that we could use `imenu--in-alist' to find the item in
+  ;; `imenu--index-alist', but that doesn't allow us to find the next
+  ;; one.  We need the flattened alist for that.
+  (interactive (progn (unless imenu--index-alist
+			(imenu--make-index-alist))
+		      (if current-prefix-arg
+			  (list (car-safe imenu--last-index) imenu--last-index)
+			  (list (imenu-choose-buffer-index
+				 nil imenu--flat-index-alist) nil))))
+  (unless imenu--index-alist	       ; in case we're non-interactive
+    (imenu--make-index-alist))
+  (let ((alist imenu--flat-index-alist)
+	(item index-item))
+    (if after				; look further down the list
+	(setq alist (cdr (member after alist))))
+    ;; Convert a string to an alist element.
+    (if (stringp item)
+	(setq item (assoc item alist)))
+    ;; Use the flattened alist for lookup.
+    (let ((imenu--index-alist alist))
+      (imenu item))
+    ;; Wrap around if appropriate.
+    (if (and after (null imenu--last-index))
+	(imenu-all index-item))
+    imenu--last-index))
 
 (dolist (mess
 	 '("^No items suitable for an index found in this buffer$"
