0

My Emacs customizations reside in a few separate .org files, all in the directory ~/emacs-prelude/personal. I'm always searching these files to find and change settings.

How can I define a function search-my-emacs-configutation-files to search the full text of these files?

It seems like the most obvious way would be to do a helm-projectile-grep, but Projectile seems to think the "project" is the entire Emacs-Prelude directory (including all my packages) when in fact I want to search only the subdirectory Personal which has my customizations.

helm-cmd-t seemed promising but it seems like it searches only filenames.

helm-do-grep works, but it asks me for the directory each time. I'd like to be able to call this function using a single keystroke.

  • You can just use M-x grep, and customize option grep-template to hard-code your directory. – Drew Oct 25 '15 at 15:37
3

There are many ways to do what you need, here is one by using helm's helm-do-grep-1.

(defun search-my-emacs-configutation-files ()
  (helm-do-grep-1 '("~/emacs-prelude/personal/*.org")))

If you even have .org files under some sub-directories under ~/emacs-prelude/personal/:

(defun search-my-emacs-configutation-files ()
  (helm-do-grep-1 '("~/emacs-prelude/personal") :recurse nil '("*.org")))

From C-h f helm-do-grep-1:

(helm-do-grep-1 TARGETS &optional RECURSE ZGREP EXTS DEFAULT-INPUT INPUT)

The 1st argument TARGETS is a list of files (including directories).

2

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

search results in the *elgrep* buffer

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:

*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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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