I've talked about DWIM in the past, that wonderful Emacs ability to do what ✨I✨ mean.
Emacs being hyper-configurable, we can always teach it more things, so it can do exactly what we mean.
There are no shortages of buffer searching packages for Emacs. I'm a fan of Oleh Krehel's swiper, but before that, I often relied on the built-in isearch. Swiper is my default goto mechanism and have it bound to C-s
(replacing the built-in isearch-forward).
Swiper services most needs until I start combining with other tools. Take keyboard macros and multiple cursors. Both wonderful, but neither can rely on swiper to do their thing. Ok, swiper does, but in a different way.
Rather than binding C-s
to swiper, let's write a DWIM function that's aware of macros and multiple cursors. It must switch between swiper, isearch, and phi-search depending on what I want (search buffer, define macro, or search multiple cursors).
Let's also tweak swiper's behavior a little further and prepopulate its search term with the active region. Oh, and I also would like swiper to wrap around (see ivy-wrap). But only swiper, not other ivy utilities. I know, I'm picky, but that's the whole point of DWIM… so here's my function to search forward that does exactly what ✨I✨ mean:
(defun ar/swiper-isearch-dwim ()
(interactive)
;; Are we using multiple cursors?
(cond ((and (boundp 'multiple-cursors-mode)
multiple-cursors-mode
(fboundp 'phi-search))
(call-interactively 'phi-search))
;; Are we defining a macro?
(defining-kbd-macro
(call-interactively 'isearch-forward))
;; Fall back to swiper.
(t
;; Wrap around swiper results.
(let ((ivy-wrap t))
;; If region is active, prepopulate swiper's search term.
(if (and transient-mark-mode mark-active (not (eq (mark) (point))))
(let ((region (buffer-substring-no-properties (mark) (point))))
(deactivate-mark)
(swiper-isearch region))
(swiper-isearch))))))
The above snippet searches forward, but I'm feeling a little off-balance. Let's write an equivalent to search backwards. We can then bind it to C-r
, also overriding the built-in isearch-backward.
(defun ar/swiper-isearch-backward-dwim ()
(interactive)
;; Are we using multiple cursors?
(cond ((and (boundp 'multiple-cursors-mode)
multiple-cursors-mode
(fboundp 'phi-search-backward))
(call-interactively 'phi-search-backward))
;; Are we defining a macro?
(defining-kbd-macro
(call-interactively 'isearch-backward))
;; Fall back to swiper.
(t
;; Wrap around swiper results.
(let ((ivy-wrap t))
;; If region is active, prepopulate swiper's search term.
(if (and transient-mark-mode mark-active (not (eq (mark) (point))))
(let ((region (buffer-substring-no-properties (mark) (point))))
(deactivate-mark)
(swiper-isearch-backward region))
(swiper-isearch-backward))))))
These may be on the hacky side of things, but hey… they do the job. If there are better/supported ways of accomplishing a similar thing, I'd love to hear about it.