Fold Search Results Away in rg.el
With the power of outline-minor-mode
in Emacs, you can turn any text buffer into an outline – with the killer feature of “cycling”, i.e. folding and unfolding outline elements.
This includes rg.el
-managed buffers, search results powered by ripgrep.
Update 2024-06-07: I changed the approach to a more robust regex! The form-feed insertion actually broke result navigation. compilation-next-error
in turn would expect not to find a form-feed character at the start of a line. Working around that was more trouble.
To tell rg.el
buffers which line is a ‘heading’ in terms of outline-minor-mode
, change the regular expression to match each line beginning with "File:"
:
(defun ct/rg-folding ()
"Enable outline-minor-mode on file entries in rg.el results."
(setq-local outline-regexp "^File: ")
(outline-minor-mode t))
(define-key rg-mode-map (kbd "<tab>") #'outline-cycle)
With that, you can run a search and zoom out to all files via M-x outline-hide-sublevels
and then zoom into each with a tab.
Note that even though outline-regexp
’s documentation says that we can assume we’re at the beginning of a line etc., omitting the ^
to denote the start of a line produces wonky results: it will fold, but sometimes, it would fold too much. I had file entries further down the buffer be folded away, too, and outline-hide-sublevels
would hide the complete buffer.
My Previous Attempt That Is Actually Broken: Inserting a Form Feed
The default outline-regexp
value contains the form-feed character. That gave me ideas
I now decorate all "File:"
lines, prepending a form-feed character:
;;; Warning: this breaks navigation in result buffers!
(defun ct/rg-add-form-feed ()
"Prepend a form feed character to all file match lines."
(save-excursion
(goto-char (point-max))
(while (re-search-backward "^File: ")
(goto-char (match-beginning 0))
(insert "\n"))))
;; Do not add the hook to a broken function! :)
; (add-hook 'rg-filter-hook #'ct/rg-add-form-feed)
You can enter a literal Unicode 0x0C FORM FEED (FF)
character in Emacs by typing C-q C-l. I did that. But that doesn’t render well on the blog, so the code uses Unicode escape sequences. (You could also use "\f"
I learned later!)
I do render my form-feeds as lines, by the way. Check out form-feed-mode
; the code from my init file is:
(use-package form-feed
:ensure
:delight
:config
(custom-set-variables
'(form-feed-include-modes '(prog-mode text-mode help-mode compilation-mode org-mode)))
:init
(global-form-feed-mode +1))