The package elgrep is a quite powerful search tool. I just listed the features in an answer to a similar question.
Recursive search for occurences of regexp matches in specified files is only one of its simplest applications.
After installation from melpa you get a comfortable settings dialog window using the menu bar:
Tools
→ Search Files (Elgrep)
.
The following settings are sufficient to search the org files in directory ~/KB/Soft/Emacs/elgrepTest/
and its subdirectories for the regexp \(one\|second\|third\) section
:
Expression: Regexp: \(one\|second\|third\) section
Directory: ~/KB/Soft/Emacs/elgrepTest/
File Name Regular Expression: \.org\'
Recurse into subdirectories [X]
A picture of the buffer with the search results:

The nice thing that fits perfectly your usecase is that Elgrep lists the calls run over the menu in an elgrep-call-list
that is part of the *elgrep-menu*
buffer:

You can copy the Form
entry, paste it into a command and adapt it to your needs.
(defun my-elgrep-call (regexp)
"Just run Elgrep for my config files."
(interactive (list (read-regexp "Search my config files for: ")))
(elgrep/i "~/KB/Soft/Emacs/elgrepTest/" "\\.org\\'" regexp :recursive t))
Alternatively you can also name the call list entry, e.g. with Search Config
and reuse it whenever you want. The call list entries are stored on disk when you leave Emacs and recovered at the start of the next session.
When you want to search your config files next time just press the [Set]
button of the call list entry Search Config
. The settings of the call list entry are adopted in the menu. Then you can change the regexp and press [Start Elgrep]
.
Naming the call list entry is important since the first call list entry is overwritten by the next Elgrep call if it is unnamed. This way the user decides which call list entries to keep.
The previous search is quite booring.
Let us try somewhat more interesting.
Assume you have the convention that each Elisp Org source block that contains a function definition should also containe some informative message.
You want to check whether there are some source blocks that contain a function definition but no message call. Thereby, stuff commented out or appearing in strings is irrelevant.
The following Elgrep settings define a search for records in Org files that contain matches for the regexp (defun
and no matches for the regexp (message
. The !
before (message
in the input field negates the match.
The records are delimited by matches for regular expression that mark the beginning and the end of Elisp source code blocks.
The context is chosen such that the full records are printed in the *elgrep*
buffer with the search results.
The search function is chosen such that it only accepts matches in Elisp code and not in comments or strings. Therefore, we search with the emacs-lisp-syntax-table
active.
Expression: List of regexps:
[INS] [DEL] Regexp: (defun
[INS] [DEL] Regexp: !(message
[INS]
Directory: ~/KB/Soft/Emacs/elgrepTest
File Name Regular Expression: \.org\'
Recurse into subdirectories [X]
Beginning of Record: Regexp: ^[[:space:]]*#\+begin_src[[:space:]]+emacs-lisp
End of Record: Regexp: ^[[:space:]]*#\+end_src\>
Context Lines Before The Match: Regexp: \`
Context Lines After The Match: Regexp: \'
Search function: (lambda (&rest args) (with-syntax-table emacs-lisp-mode-syntax-table (apply #'elgrep/re-search-code args)))
When you click on [Start Elgrep]
Elgrep executes the search, shows the results, and presents your settings as command in the call list:
(elgrep/i "/mnt/c/Users/Tobias.Zawada/Weiterbildung/Soft/Emacs/elgrepTest" "\\.org\\'"
("(defun" "!(message")
:recursive t :r-beg "^[[:space:]]*#\\+begin_src[[:space:]]+emacs-lisp" :r-end "^[[:space:]]*#\\+end_src\\>" :c-beg "\\`" :c-end "\\'" :search-fun
(lambda
(&rest args)
(with-syntax-table emacs-lisp-mode-syntax-table
(apply #'elgrep/re-search-code args))))
You can copy that entry and use it in your self-made Elisp command.
But, there is actually little need to define your own command since you can re-use the call list entry in the elgrep menu.