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)
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: