3

I am new to emacs, and org-mode pulled me away from vim. I am getting a hang of it. One thing I am missing a lot is a hierarchical search in emacs. I wrote a python script for that in vim, and I am looking for a solution in emacs (org-mode).

Let me explain. Let us say, here is the file:

* People
** Software related help
*** John
*** Amit
** Personal
*** John
*** Mike
* Project
** With Mike
*** Website development

When I am searching for a heading, I usually know I am searching for mike, but once I see that there are too many search results (I use 'swiper-all), I want to narrow the search based what the child headings and parent headings contain. In this case, I might want to extend the search to mike people or mike project based on what kind of heading I am searching for.

In other words, if each heading is a node in the tree, I want to search not only in the node, but in the concatenation of all nodes up to the root. (See a couple other nice-to-haves below.)

Is there any solution or package avaiable for this? If not, can you point me to how to go about writing a script/package for this?


Nice to haves:

  1. Ideally, the file name would be considered as the level zero heading.
  2. Ideally, the order of words in the search term does not matter. I sometimes don't remember if I wrote With Mike below Project heading, or wrote Project below Mike heading. In either case, I want to just search for mike project and be able to find what I am looking for.
4
  • 1
    I don't know about a ready-made package for it. But this can be useful to you: github.com/ndwarshuis/om.el
    – Muihlinn
    Commented Apr 8, 2020 at 19:20
  • 1
    As you have swiper you should have counsel-outline, try that one. Helm must have something as well. With ivy it's possible to ignore the order of the words, look for ivy–regex-ignore-order in the documemtation. Counsel-outline checks the current file only.
    – Hubisan
    Commented Apr 8, 2020 at 22:50
  • @Hubisan: Thanks for the counsel-outline reference. It is an alias for counsel-org-goto and that lead me to counsel-org-goto-all, which does the search across all files. I am not sure which files it searches in. Probably all agenda files. Or open buffers (I need to check). I will look into ignoring the order of words. Commented Apr 10, 2020 at 3:21
  • @Hubisan: The combination of counsel-org-goto-all and ivy–regex-ignore-order worked perfectly for me. The only thing missing is now the "Nice to have #1". Thanks for helping me. If you write this up quickly as an answer, I would definitely accept your answer. Commented Apr 16, 2020 at 4:33

2 Answers 2

5

If you have ivy installed you can use either counsel-org-goto (current buffer only) or counsel-org-goto-all (all currently opened org buffers). Both show the outline path for each heading and therefore let you search hierarchically:

searching with counsel-org-goto

Remark: Those commands should also work for emacs-lisp-mode, markdown-mode and latex-mode.

Ignore search order

To ignore the search order you can customize the ivy completion styles for those commands:

(add-to-list 'ivy-re-builders-alist '(counsel-org-goto . ivy--regex-ignore-order))
(add-to-list 'ivy-re-builders-alist '(counsel-org-goto-all . ivy--regex-ignore-order))

enter image description here

Add filename

To add the filename at the beginning you can advice counsel-outline-candidates:

(defun my-add-filename-to-counsel-outline-candidates (candidates)
  "Add the filename at the beginning for CANDIDATES from `counsel-outline-candidates'."
  (mapcar
   (lambda (candidate)
     (let* ((marker (cdr candidate))
            (filename (buffer-file-name (marker-buffer marker)))
            (filename-abbreviated (when filename (concat (abbreviate-file-name filename) " ")))
            ;; Use this if you want the buffer name. It's a bit shorter.
            ;; (buffername (buffer-name (marker-buffer (cdr candidate))))
            )
       (cons (concat filename-abbreviated (car candidate)) marker)))
   candidates))

(advice-add 'counsel-outline-candidates :filter-return #'my-add-filename-to-counsel-outline-candidates)

counsel-org-goto with filenames

1

For Doom Emacs (with vertico) users there is consult-org-heading command and it's mapped to SPC m . by default. Works in current buffer only.

consult-org-heading

Search with any word order:

searching

Your Answer

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

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