Improving Emacs isearch Usability with Transient
18 Dec 2023 Charles Choi
Emacs incremental search (isearch) has an embarrassingly rich feature set. That said, I rarely use isearch beyond its basics for the twofold reasons:
- There are many isearch commands that are difficult to discover, much less remember.
- The default keybindings for said commands are cursed. (Seriously,
C-M-@
to callisearch-query-replace-regexp
?)
However with the addition of the Transient package to Emacs 29.1, there is now recourse to work around these objections: when in isearch mode, we can make available an isearch-specific Transient menu. This post shows you how.
Use Case/Workflow
This is the use case I want solved:
When in basic isearch, I want to be able to use the function key (in this case <f2>
) to invoke a Transient menu offering a set of isearch-specific commands. These commands would be grouped as follows:
-
Edit commands on the search string/regexp
isearch-edit-string
isearch-yank-word-or-char
isearch-yank-symbol-or-char
isearch-yank-line
isearch-yank-kill
isearch-forward-thing-at-point
(imho, this is an amazing odd-ball function)
-
Replace commands (provided the buffer is not read-only)
isearch-query-replace
isearch-query-replace-regexp
-
Toggle commands
isearch-toggle-regexp
isearch-toggle-symbol
isearch-toggle-word
isearch-toggle-case-fold
isearch-toggle-lax-whitespace
-
Misc
isearch-occur
While not all isearch commands are enumerated in this menu, this selection seems more than sufficient for my routine needs.
Demo
The following demo screenshots show this menu at work. First is a screenshot of Emacs in basic isearch mode, searching for the string “Screenshot 2”.
Pressing the <f2>
button will activate the isearch-specific Transient menu shown below. The user can then select the next action by either a key press or mouse button (typically 1) press.
Implementation
The following source shows the implementation of the workflow above, patterned after the examples shown in Transient Showcase.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
|
Verified in Emacs 29.1
Closing Thoughts
Since implementing this Transient menu, isearch has become my primary interface to query-replace
and query-replace-regexp
. Also the ability to yank different object types and toggle different search behavior as I go along has been revelatory. Despite that fact that these features have always been there, their discoverability and keybindings have made them all but unusable to me. With Transient these features are finally made usable.
While the inclusion of Transient in Emacs 29.1 is relatively recent, the potential to revisit older Emacs workflows with this new capability seems to be a green field. I look forward to seeing what others do with Transient.
References
- Incremental Search (GNU Emacs Manual)
- Transient User and Developer Manual
- positron-solutions/transient-showcase: Example forms for transient UI's in Emacs
Addendum - 4 March 2024
The above code has been modified, packaged, and published on MELPA as cc-isearch-menu. More info here.