1

Is it possible to use imenu (or another package) to copy the target (specified by a regex) rather than jumping to it?

This is an effort for tackling the question: How to list or autocomplete pandoc-crossref citations in an org-mode buffer?

I'd like to find all labels in the buffer that match a certain regex pattern. Then, instead of jump to that label, I'd like to copy it to the current point. Is this possible with imenu or similar packages?

Related:

How to use a menu to jump between sections of a document?

Get all regexp matches in buffer as a list

-- UPDATE --

To clarify what I was looking for with a minimal example:

I have the following packages installed for the auto-completion:

ivy ivy-hydra imenu imenu-anywhere counsel swiper

and then (require 'imenu) (as suggested).

Now in a buffer with two lines:

aaa
bbb

and the cursor at the third line, I'd like to use the regex aaa to insert the text aaa at the point. E.g. by :

imenu-match-insert('aaa')

I am using a trivial regex, but for a real one, I'd like to use imenu and the minibuffer to select from the list of all labels in the current buffer (before and after the point) that matches the regex.

3 Answers 3

1

I think that I misunderstood what the OP asked for. He wished to search for matches to arbitrary regexps not simply within the matches found by the usual imenu. This can be done.

(defun imenu-match-insert (s)
  (interactive "sRegexp to search with: ")
  (let ((imenu--index-alist nil)
        (imenu-generic-expression (list (list nil s 0))))
    (insert (completing-read "Choose a target: "
                             (seq-filter (lambda (z)
                                           (string-match s z))
                                         (seq-uniq (mapcar 'car (cdr (imenu--make-index-alist)))))))))

 (defun imenu-for-regexp (s)
  (interactive "sRegexp to search with: ")
  (let ((imenu--index-alist nil)
        (imenu-generic-expression (list (list nil s 0))))
    (imenu--make-index-alist)
    (call-interactively 'imenu)))

The first command allows you to insert at point a match within the buffer for a regexp. The second command allows you to go to an arbitrary match within the buffer just like imenu but for an arbitrary regexp you specify. To make this useful it would be good to use various regexp makers, functions from strings to regexps. For example

(defun symbol-fuzzy-regexp (str)
  (concat "\\_<\\(\\w\\|\\s_\\)*"
          (mapconcat #'identity (split-string str "" t) "\\(\\w\\|\\s_\\)*")
          "\\(\\w\\|\\s_\\)*\\_>"))

(defun imenu-insert-fuzzy-symbol (str)
  (interactive "sType some of the letters in the symbol: ")  
  (imenu-match-insert (symbol-fuzzy-regexp str)))

The command imenu-insert-fuzzy-symbol will find symbols that are matched fuzzily by the letters you type and you choose which of them you want and that is inserted at point

10
  • Thanks again. I added some clarification. Tried imenu-match-insert and imenu-insert-fuzzy-symbol, and then entered aaa at prompt, but I got: imenu-unavailable-error: imenu unavailable: "No items suitable for an index found in this buffer".
    – tinlyx
    Jun 22, 2020 at 18:14
  • I guess I'll do more reading on how to use imenu or ivy first before I can follow up with more meaningful questions.
    – tinlyx
    Jun 22, 2020 at 18:16
  • That means that imenu did not find anything that matched. Try inputting mzz when you call imenu-insert-fuzzy-symbol in a buffer that has this inside it. Jun 22, 2020 at 18:22
  • I just read your clarification and both imenu-match-insert and imenu-insert-fuzzy-symbol work with input aaa (as intended). Jun 22, 2020 at 18:41
  • This is weird. I was testing on an .org file, and it gave the error above. But with a .txt file, this actually works. Could org mode configuration interfere with this?
    – tinlyx
    Jun 22, 2020 at 18:51
1

This does what you ask for.

(defun imenu-insert-label (s)
  (interactive "sRegexp to search with: ")  
  (insert (completing-read "Choose a target: "
                           (seq-filter (lambda (z)
                                         (string-match s (car z)))
                                       (cdr (imenu--make-index-alist))))))

It uses the seq package to filter the labels. If you are using ivy or helm you get visual feedback on the labels you are choosing from. Obviously you could replace (cdr (imenu--make-index-alist)) by any list you wished to choose from so you could adjust this recipe for many other cases.

Assign this command to a key and you are ready to go.

2
  • Thanks! Could you give an example of how to use it with counsel-imenu? Sorry, I am new to elisp. Just added your code to init.el, and got cdr: Symbol’s function definition is void: imenu--make-index-alist.
    – tinlyx
    Jun 22, 2020 at 17:17
  • The error message means that you do not have imenu loaded at the time you tried the function. Put (require 'imenu) before this code. I do not have any experience with counsel-imenu so cannot help with that. Jun 22, 2020 at 17:39
0

This is a temporary workaround that worked for me based on @Aidan Schofield's answer.

The imenu-match-insert function there had some issues working with org files. And I added a variant imenu-match-insert-text below (a thin wrapper), which switches the current buffer temporarily to text mode, does the insert and then switch back to the original mode:

(defun imenu-match-insert (s)
  (interactive "sRegexp to search with: ")
  (let ((imenu--index-alist nil)
        (imenu-generic-expression (list (list nil s 0))))
    (insert (completing-read "Choose a target: "
                             (seq-filter (lambda (z)
                                           (string-match s z))
                                         (seq-uniq (mapcar 'car (cdr (imenu--make-index-alist)))))))))

(defun imenu-match-insert-text (s)
  (interactive "sRegexp to search with: ")
  (let ((current-mode major-mode))
    (text-mode)
    (imenu-match-insert s)
    (funcall current-mode)
  )
)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.