11

In emacs, I want to be able to search only the 'headers' in an org mode file.

Idea 1: Search only Visible
I could achieve this by hiding everything, then showing only the outline (S-TAB, S-TAB) and then maybe search all that is visible.(in this case it would be the whole table of content). But how do I search only visible content? C-s searches everything.

Idea 2: use regex
I can potentially do:

C-c / /             //opens regex search
\*.*heading        //start with * (escaped), followed by any chars, then heading.

But at the moment it's cumbersome to type all of that. Considering I've started learning emacs like 3 hours ago, can I automate this somehow?
E.g, can I write a function to search with "*.*ARGUMENT" and tie it a hotkey? but still have the ability to go like 'next find, next find' etc..?

The use case for this is searching my notes. Some are like ~7000+ lines long and I commonly only search the headers.

[EDIT Solution 1]
@abo-abo's answer worked well for me. I now use helm-org-in-buffer-headings

I.e, I installed Melpa: https://github.com/milkypostman/melpa#usage

Then I installed helm from the package list: M-x package-list-packages

Then I edited my .emacs and bound a hotkey to it:
(global-set-key (kbd "C-=") 'helm-org-in-buffer-headings) ;Outline search.

I reloaded emacs and now when pressing Ctrl+= a searchable outline pops up that automatically narrows down as I type in additional characters. The usual C-n, C-p , buttons work for navigation.

Thanks!

[Edit Solution 2] Curiosity got the best of me. After enjoying helm's heading search, I messed around with worf also. It is like helm (it uses helm) but looks nicer and I can select a 'level' of outline by pressing the number key. I hacked out just the bits necessary for heading search, if of use:

;; ——— WORF Utilities ———————————————————————————————————————————————————————————————
;; https://github.com/abo-abo/worf/blob/master/worf.el
(defun worf--pretty-heading (str lvl)
  "Prettify heading STR or level LVL."
  (setq str (or str ""))
  (setq str (propertize str 'face (nth (1- lvl) org-level-faces)))
  (let (desc)
    (while (and (string-match org-bracket-link-regexp str)
                (stringp (setq desc (match-string 3 str))))
      (setq str (replace-match
                 (propertize desc 'face 'org-link)
                 nil nil str)))
    str))
(defun worf--pattern-transformer (x)
  "Transform X to make 1-9 select the heading level in `worf-goto'."
  (if (string-match "^[1-9]" x)
      (setq x (format "^%s" x))
    x))

(defun worf-goto ()
  "Jump to a heading with `helm'."
  (interactive)
  (require 'helm-match-plugin)
  (let ((candidates
         (org-map-entries
          (lambda ()
            (let ((comp (org-heading-components))
                  (h (org-get-heading)))
              (cons (format "%d%s%s" (car comp)
                            (make-string (1+ (* 2 (1- (car comp)))) ?\ )
                            (if (get-text-property 0 'fontified h)
                                h
                              (worf--pretty-heading (nth 4 comp) (car comp))))
                    (point))))))
        helm-update-blacklist-regexps
        helm-candidate-number-limit)
    (helm :sources
          `((name . "Headings")
            (candidates . ,candidates)
            (action . (lambda (x) (goto-char x)
                         (call-interactively 'show-branches)
                         (worf-more)))
            (pattern-transformer . worf--pattern-transformer)))))

And then tied it to a hot key:

(global-set-key (kbd "<f3>") 'worf-goto)
0

4 Answers 4

8

worf-goto from worf can do this, so can helm-org-in-buffer-headings from helm.

worf-goto actually uses helm as a back end. In addition to helm-org-in-buffer-headings, you get:

  • headings are colored in the same way as in the original buffer
  • you can select all headings with the same level using the appropriate digit
Sign up to request clarification or add additional context in comments.

2 Comments

worf-goto is so awesomeness. Thanks for sharing.
Glad you like it. Try lispy-goto if you want a similar thing for your Emacs Lisp files.
4

If you have ivy installed, you can use counsel-org-goto to search headings in the current buffer or counsel-org-goto-all to search the headings in all open org-mode buffers.

It's a good option if you don't want to install the other things that come with worf.

Comments

4

If you don't want to rely on external packages, org, in fact, already offers this capability: the function is org-goto.

If you want it to behave in a way similar to helm-org-in-buffer-headings, you have to set org-goto-interface to outline-path-completion, for instance by adding to your init file:

(setq org-goto-interface (quote outline-path-completion))

1 Comment

The only limitation of this approach, which I like, is that it does not show tags in the headings.
0

There are two way to do this, using only builtin Emacs feature.

  • When searching, you can press M-s i to toggle whether to search invisible body lines, this works for one shot thing.
  • If you want to make Emacs not searching invisible text by default, you can customize the search invisible option, set it to "Don't match hidden text".

This solution works for all other mode, this might be what you want or not.

Also, for your specific problem of "only searching headers", the builtin Imenu can be used, press M-g i, then type your filter, the Imenu only index headers in org-mode (or other text formatter mode). This is a the fastest way to do such things (kinda like sublime text's Ctrl-r).

(I'm using version 29, I don't know since when the customize option below became available, so might work for older version, too.)

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.