.. post:: 2017-02-06 :tags: Emacs :author: Rudi Grinberg Searching the ``load-path`` =========================== Here's another tip for taming your Emacs config. In particular, how to search the huge body of elisp that is present with most Emacs installs - the ``load-path``. While the ``load-path`` is a very important collection of directories, searching it isn't as easy and accessible as it should be. As usual, Emacs compensates with plugins: * `elisp-refs `__ - this excellent package is useful for canned searches that are often present in most IDE's. Quite useful whenever your search fits into one of the use case supported. * `el-search `__ - this is quite an advanced package that allows you to write queries with a deep understanding of elisp itself. An extremely useful plugin, but overkill when your query is simple. A problem that is shared by both of the options above is that they're a bit sluggish. Something that is fast, allows us to use familiar PCRE's, is a missing piece. Luckily, such a missing piece is glued together with a bit of elisp and the `silver searcher `__: .. code-block:: elisp (defun region-or-symbol-at-point () (if mark-active (buffer-substring-no-properties (region-beginning) (region-end)) (or (symbol-name (symbol-at-point)) ""))) (defun rg/grep-load-path (query) (interactive (let ((query (read-string (format "Grep (default %s): " (region-or-symbol-at-point)) nil 'git-grep (region-or-symbol-at-point)))) (list query))) (grep-find (mapconcat #'shell-quote-argument `("ag" "--search-zip" "--no-heading" "--no-color" ,query ,@(-filter #'f-exists? load-path)) " "))) This gives us an interactive command where we can either the query manually, or automatically insert the active region. Note that We'd like to use `ag` specifically because of its support for searching gzip files. This is common for elisp code in your ``load-path``. Folding Ergonomic with Origami ------------------------------ Not bad, but since the ``load-path`` can be quite huge, the command inserted in the grep output is a bit of an eye-sore. My favorite folding mode is origami, but surely this can be done with something like ``hideshow`` as well. First, let's define the folding functions: .. code-block:: elisp (defun rg/find-grep-command-bounds () (save-excursion (goto-char (point-min)) (let ((start (re-search-forward "^Grep started at"))) (progn (forward-line 3) (list start (- (point) 1)))))) ;; make sure you have lexical scoping enabled for this function (defun rg/origami-grep-command (create-fold) (lambda (content) (destructuring-bind (beg end) (rg/find-grep-command-bounds) (list (funcall create-fold beg end 20 nil))))) (with-eval-after-load 'origami (add-to-list 'origami-parser-alist '(rg/origami-grep-command-style . rg/origami-grep-command))) The gist of it being that we have a single fold spanning from our ``"Grep started at"`` marker to the next 3 lines. The only thing that remains is turn on this folding more and close all folds after completing the fold: .. code-block:: elisp (defun rg/grep-load-path (query) (interactive (let ((query (read-string (format "Grep (default %s): " (region-or-symbol-at-point)) nil 'git-grep (region-or-symbol-at-point)))) (list query))) (let ((myb (grep-find (mapconcat #'shell-quote-argument `("ag" "--search-zip" "--no-heading" "--no-color" ,query ,@(-filter #'f-exists? load-path)) " ")))) (with-current-buffer myb (setq-local origami-fold-style 'rg/origami-grep-command-style) (origami-close-all-nodes myb)))) Limitations ----------- One annoying limitation is that the our fold settings aren't preserved through updating the search results with `(recompile)`. I haven't ran into this problem enough for this issue to matter yet. Searching the ``load-path`` is nice for gauging all that code is available to Emacs, but what about searching what Emacs has actually loaded? This is where ``load-history`` comes in. It should be easy enough to only search these files with a similar command (or a prefix argument).