Is there in Emacs such a function to search within all headings of all Org mode files within a folder or group of folders?
2 Answers
Adapted from the answer given here. The following function will list all org mode headings in the directories passed to the function (more info in the docstring):
(require 'xref)
(setq my-search-dirs '("~/.emacs.d" "dir-2"))
(defun my-search-heading-across-directories ()
"Lists all org-mode headings in DIRECTORIES.
Takes any number of directories (separate by `SPC').
When called interactively then prompts for a directory after
which it lists all org mode headings in files of that directory."
(interactive)
(let ((files (seq-filter (lambda (b) (string-match "org$" b))
(mapcan (lambda (d)
(mapcar (lambda (f)
(concat (file-name-as-directory d) f))
(directory-files d)))
my-search-dirs))))
(xref--show-xrefs
(apply-partially #'xref-matches-in-files "^*\+"
(mapcar #'expand-file-name files))
nil)))
Functionality to subsequently easily search/narrow down over the headings is provided by packages like helm-xref and ivy-xref.
To search in multiple directories do
M-:
(my-search-heading-across-projects "~/dir-1" "dir-2")
To call it with a list of folders, call it using apply
.
There exists xref-matches-in-directory
also, but it requires some 'trickery' to make it work with xref--show-xrefs
while searching in multiple directories.
-
1Apparently, the function
xref-show-xrefs
, which callsxref--show-xrefs
was only added in Emacs 29. In Emacs < 29 one should callxref--show-xrefs
directly. I have updated the answer, where I have also fixed some other details. Please search the web for the meaning/usage ofapply
(and its difference fromfuncall
) in elisp/Emacs. Commented Dec 7, 2022 at 13:57 -
1If you use some completion framework like vertico/ivy/helm, then you can further narrow down to some specific heading (as mentioned in the linked answer). If you are not using any of these, then you can use 'isearch' (
C-s
) to further search for some specific heading. Alternatively, you could modify the function and filter the results returned byxref-matches-in-files
directly, but I would recommend you install one of the aforementioned completion frameworks (for simplicity I would recommend Ivy, which is what I use, but all of them are good). Commented Dec 8, 2022 at 10:19 -
1I've updated the answer, please try again to see what I mean, there is no extra typing compared to the other answer (when called via
M-x
, i.e. it prompts directly to find the heading). Before the update, there was the extra step of selecting directories, but I mentioned the option of using apply to pass the directories as a list. Anyway, now you can just configure the list like in the other answer. Commented Dec 9, 2022 at 9:59 -
1Okay, I have found that it requires the package helm-xref. I assumed this was simply configured by helm. I will again update the answer. Sorry, for the misunderstanding, and thanks for keep trying/and the feedback. B.t.w. I do think that this answer, i.c.w. helm-xref, does provide the nicer solution. Commented Dec 9, 2022 at 10:34
-
1Did you see my latest comment (and the updated answer)? Because it mentions, that this functionality requires the package
helm-xref
to be installed. Then, you can narrow down, with helm (as usual in helm). Commented Dec 9, 2022 at 11:56
There is. You can search with grep. For example, M-x rgrep * todo
should list your TODOs. There's also a grep-find
command you try.
Personally, I like a combination of helm and ripgrep, so to search all headings in the current directory I use M-x helm-do-grep-ag ^\*+ foobar
.
org-agenda-files
list with just those files). I describe a method to search for headlines in a single file in there. If you combine those two ideas, you might be able to do what you want.