3

I would like to have a single shortcut to jump to the next item on the imenu of current buffer. E.g., if the current buffer is in org mode, next-imenu-item = org-next-visible-heading.

Anyone did that before?

AhLeung
  • 1,083
  • 5
  • 14
  • I grepped the Emacs 25.1 source code for `next-imenu-item`, and came up with nothing -- i.e., it does not exist. In my setup, imenu creates a menu with all main first level headings, and the subheadings (e.g., second level) are alphabetized (if there are lots, then they are grouped into alphabetized groups). The main ingredient that creates this is `(org-set-local 'imenu-create-index-function 'org-imenu-get-tree)` within my `org-mode` setup. Please consider editing your question to provide some additional details regarding your setup and what it is specifically you wish to accomplish. – lawlist Feb 13 '17 at 22:58
  • And, also have this: `(eval-after-load "imenu" '(progn (add-hook 'imenu-after-jump-hook (lambda () (when (derived-mode-p 'org-mode) (org-show-context 'org-goto))))))` – lawlist Feb 13 '17 at 23:01
  • 1
    I implemented what I wanted and posted as an answer below. Feel free to comment. Thanks. – AhLeung Jun 24 '17 at 07:13

1 Answers1

3
(defun my-imenu-goto--closest-dir (direction)
  "Jump to the closest imenu item on the current buffer.
If direction is 1, jump to next imenu item.
If direction is -1, jump to previous imenu item.
See https://emacs.stackexchange.com/questions/30673
Adapted from `which-function' in::
https://github.com/typester/emacs/blob/master/lisp/progmodes/which-func.el"
  ;; Ensure `imenu--index-alist' is populated.
  (imenu--make-index-alist)

  (let ((alist imenu--index-alist)
        (minoffset (point-max))
        offset pair mark imstack destination)
    ;; Elements of alist are either ("name" . marker), or
    ;; ("submenu" ("name" . marker) ... ). The list can be
    ;; Arbitrarily nested.
    (while (or alist imstack)
      (if alist
          (progn
            (setq pair (car-safe alist)
                  alist (cdr-safe alist))
            (cond
             ((atom pair)) ;; Skip anything not a cons.

             ((imenu--subalist-p pair)
              (setq imstack   (cons alist imstack)
                    alist     (cdr pair)))

             ((number-or-marker-p (setq mark (cdr pair)))
              (when (> (setq offset (* (- mark (point)) direction)) 0)
                (when (< offset minoffset) ;; Find the closest item.
                  (setq minoffset offset
                        destination mark))))))

        (setq alist   (car imstack)
              imstack (cdr imstack))))
    (when destination
      (imenu-default-goto-function "" destination ""))))

(defun my-imenu-goto-next ()
  (interactive)
  (unless (my-imenu-goto--closest-dir 1)
    (goto-char (point-max))))

(defun my-imenu-goto-prev ()
  (interactive)
  (unless (my-imenu-goto--closest-dir -1)
    (goto-char (point-min))))
ideasman42
  • 8,375
  • 1
  • 28
  • 105
AhLeung
  • 1,083
  • 5
  • 14
  • You should think about commenting and explaining your answer. – theldoria Jun 24 '17 at 12:13
  • And you should think about submitting it for inclusion in imenu.el. – Stefan Jun 24 '17 at 13:46
  • @theldoria Added some comments to the function. – AhLeung Jul 01 '17 at 06:14
  • 1
    @Stefan I haven't submitted anything to open source project before. Do you have some related pointers / tutorials (on contributing to GNU emac?) for me to follow? Thanks. – AhLeung Jul 01 '17 at 06:16
  • 1
    You can check the file `CONTRIBUTE` at the top-level of Emacs's source code. Basically, in your case, change `imenu.el` by adding yur feature to it, then generate a patch for the change and send it via `M-x report-emacs-bug` (which is used not just for bug-reports but for patch submission and feature requests as well). – Stefan Jul 02 '17 at 02:35