<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>notes from /dev/null - emacs</title><link href="http://yummymelon.com/devnull/" rel="alternate"/><link href="http://yummymelon.com/devnull/feeds/tags/emacs.atom.xml" rel="self"/><id>http://yummymelon.com/devnull/</id><updated>2026-06-04T09:35:00-07:00</updated><entry><title>Revisiting Emacs Keyboard Macros with a Mouse</title><link href="http://yummymelon.com/devnull/revisiting-emacs-keyboard-macros-with-a-mouse.html" rel="alternate"/><published>2026-06-04T09:35:00-07:00</published><updated>2026-06-04T09:35:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-06-04:/devnull/revisiting-emacs-keyboard-macros-with-a-mouse.html</id><summary type="html">&lt;p&gt;Yes, recording an Emacs keyboard macro with a mouse is a thing.&lt;/p&gt;</summary><content type="html">&lt;p&gt;“No-code automation” has been in Emacs far longer than its usage as a term of art. Better known as &lt;em&gt;keyboard macros&lt;/em&gt;, this feature has allowed Emacs users to achieve their bespoke needs for decades, all without needing to know a whit about Lisp. I can testify to this personally: though I’ve been using Emacs since the early 90’s, only in the past three years has writing Elisp played any part in it. For most of my Emacs journey, I got by with just making keyboard macros.&lt;/p&gt;
&lt;p&gt;If you’re unfamiliar with them, here are two links you should get to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Keyboard-Macros.html"&gt;The official Emacs manual for keyboard macros&lt;/a&gt; ((emacs) Keyboard Macros)&lt;/li&gt;
&lt;li&gt;Mickey Petersen’s post - &lt;a href="https://www.masteringemacs.org/article/keyboard-macros-are-misunderstood"&gt;“Keyboard Macros are Misunderstood”&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My addition to the knowledge of those posts is to boost this fact: &lt;strong&gt;mouse events can also be captured by a keyboard macro&lt;/strong&gt;. If you know where a command &lt;em&gt;is&lt;/em&gt; in a menu, you can also record clicking on it. I think the ability to combine both keyboard and mouse events in a keyboard macro is compelling, so much so that I decided to emphasize this in Anju.&lt;/p&gt;
&lt;p&gt;The recent &lt;a href="https://github.com/kickingvegas/anju"&gt;Anju&lt;/a&gt; v1.5.0 release added the menu “Tools › Macro Recorder” to the menu bar as shown below.&lt;/p&gt;
&lt;p&gt;&lt;img alt="img" src="images/anju-kmacros/anju-main-menu-tools-kmacro.png"&gt;&lt;/p&gt;
&lt;p&gt;With this, mouse enthusiasts can create and run keyboard macros without need to recall keybindings or deal with inconsistent command naming, as observed in Petersen’s post.&lt;/p&gt;
&lt;p&gt;One thing that I TILed about keyboard macros in building this menu was the command &lt;code&gt;list-keyboard-macros&lt;/code&gt; (see &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Kmacro-Menu.html"&gt;(emacs) Kmacro menu&lt;/a&gt;). This command is available in the “Macro Recorder” menu as the item “List macros”. This lets you manage multiple keyboard macros that have been defined during a session.&lt;/p&gt;
&lt;p&gt;If this interests you, I invite you install &lt;a href="https://melpa.org/#/anju"&gt;Anju from MELPA&lt;/a&gt; and give it a try. Let me know &lt;a href="https://github.com/kickingvegas/anju/discussions/121"&gt;what you think&lt;/a&gt;!&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="anju"/></entry><entry><title>Opening macOS Finder Folders in Emacs with Scrim</title><link href="http://yummymelon.com/devnull/opening-macos-finder-folders-in-emacs-with-scrim.html" rel="alternate"/><published>2026-06-01T19:00:00-07:00</published><updated>2026-06-01T19:00:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-06-01:/devnull/opening-macos-finder-folders-in-emacs-with-scrim.html</id><summary type="html">&lt;p&gt;Finder fun with the Scrim custom URL scheme and some musings on software orchestration.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;img alt="img" src="images/open-in-emacs-shortcut/open-in-emacs-quick-action.png"&gt;&lt;/p&gt;
&lt;h1&gt;TL;DR&lt;/h1&gt;
&lt;p&gt;If you use both &lt;a href="http://yummymelon.com/scrim/"&gt;Scrim&lt;/a&gt; and Emacs on macOS, you can “Open in Emacs” a file or directory from Finder via the “Quick Actions” context menu. This is implemented as a macOS Shortcut, shared as an iCloud link:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.icloud.com/shortcuts/f5c8499183dc44ec89cebfc78bfb0433"&gt;“Open in Emacs” Shortcut iCloud Link&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Motivation&lt;/h1&gt;
&lt;p&gt;I find macOS &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Drag-and-Drop.html"&gt;drag-and-drop&lt;/a&gt; operations from Finder to Emacs (in particular, the NS variant) to be frustratingly inconsistent.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dragging a file or folder from Finder to a non-Dired buffer will visit it.&lt;ul&gt;
&lt;li&gt;Not always! This behavior can be mode-specific.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dragging a file or folder from Finder to a Dired buffer will copy it.&lt;/li&gt;
&lt;li&gt;Dragging a file or folder from Finder to the Emacs icon in the Dock will visit it in a new frame.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add to that, drag-and-drop isn’t graceful with a long traversal path on a large screen.&lt;/p&gt;
&lt;p&gt;Ultimately, what I want is a single consistent action to “Open in Emacs” a file or directory from Finder. This post describes a solution for achieving this using the &lt;a href="http://yummymelon.com/scrim/"&gt;Scrim&lt;/a&gt; and &lt;a href="https://support.apple.com/guide/shortcuts-mac/intro-to-shortcuts-apdf22b0444c/mac"&gt;macOS Shortcuts&lt;/a&gt; apps.&lt;/p&gt;
&lt;h1&gt;Background&lt;/h1&gt;
&lt;h2&gt;Scrim&lt;/h2&gt;
&lt;p&gt;Scrim is an Org protocol proxy app that I had &lt;a href="http://yummymelon.com/devnull/announcing-scrim--an-org-protocol-proxy-for-emacs-on-macos.html"&gt;published on the App Store&lt;/a&gt; last year. Implementing Scrim was largely an exercise in reverse-engineering &lt;code&gt;emacsclient&lt;/code&gt; to be a macOS app. This is because macOS apps these days (macOS 10.14+) are packaged to execute as a &lt;a href="https://developer.apple.com/documentation/security/hardened-runtime"&gt;hardened runtime&lt;/a&gt; (aka “sandboxed”). Among the many things a hardened runtime restricts is the ability for an app to &lt;a href="https://en.wikipedia.org/wiki/Exec_(system_call)"&gt;exec&lt;/a&gt; another program outside of its sandbox (like &lt;code&gt;emacsclient&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In lieu of that restriction, macOS provides different APIs to let apps work with other apps, among them &lt;em&gt;Services&lt;/em&gt; (more below), &lt;a href="https://developer.apple.com/documentation/intents/"&gt;Intents&lt;/a&gt; (a whole different topic worthy of another post), and &lt;a href="https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app"&gt;custom URL schemes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A custom URL scheme is what Scrim provides to allow other apps to do &lt;code&gt;emacsclient&lt;/code&gt;-like things like opening a file. By design, Scrim does not surface all the capabilities of &lt;code&gt;emacsclient&lt;/code&gt; such as arbitrary Elisp execution. The custom URL scheme itself is &lt;code&gt;scrim://&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Currently the &lt;code&gt;scrim://&lt;/code&gt; URL scheme supports the following two actions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Visit a file or directory (e.g. &lt;code&gt;scrim://open?file=~/.profile&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Open an Info node (e.g. &lt;code&gt;scrim://info?node=(eshell) Top&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For this post, we will concern ourselves with (1) visiting (opening) a file or directory.&lt;/p&gt;
&lt;p&gt;Note that on a system where a custom URL scheme is installed, &lt;em&gt;any&lt;/em&gt; app on that system can open said custom URL scheme.&lt;/p&gt;
&lt;h2&gt;Services&lt;/h2&gt;
&lt;p&gt;The macOS &lt;a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/SysServices/introduction.html#/apple_ref/doc/uid/10000101-SW1"&gt;Services API&lt;/a&gt; allows an application to access the functionality of another.&lt;/p&gt;
&lt;p&gt;Apple uses this API to provide tools to help orchestrate workflows between different applications, namely AppleScript, Automator, and Shortcuts. Note that as of this writing, AppleScript and Automator are in maintenance mode, and Shortcuts is intended to supersede Automator. Once a workflow is defined, it is usually accessed via a context menu sub-menu labeled “Quick Actions” or “Services”.&lt;/p&gt;
&lt;h1&gt;“Open in Emacs” Shortcut&lt;/h1&gt;
&lt;p&gt;With the above background out of the way, let's turn our attention to the Shortcut itself.&lt;/p&gt;
&lt;p&gt;&lt;img alt="img" src="images/open-in-emacs-shortcut/open-in-emacs-shortcut.png"&gt;&lt;/p&gt;
&lt;p&gt;The shortcut invokes a Python script which forms the &lt;code&gt;scrim://open?file&lt;/code&gt; custom URL and then opens it with the &lt;code&gt;open&lt;/code&gt; command line utility.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;

&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;scrim://open?file=&lt;/span&gt;&lt;span class="si"&gt;{0}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="n"&gt;cmdList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;open&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmdList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This shortcut can be installed via iCloud link: &lt;a href="https://www.icloud.com/shortcuts/f5c8499183dc44ec89cebfc78bfb0433"&gt;“Open in Emacs” Shortcut iCloud Link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When installed, the menu item "Open in Emacs" will appear in the "Quick Actions" sub-menu when the context menu is raised on an Finder item.&lt;/p&gt;
&lt;h1&gt;“scrim link” Shortcut&lt;/h1&gt;
&lt;p&gt;&lt;img alt="img" src="images/open-in-emacs-shortcut/scrim-link-shortcut.png"&gt;&lt;/p&gt;
&lt;p&gt;What if you want just the Scrim URL to open a file or directory instead? The shortcut "scrim link" shown above provides that, putting the URL into the system clipboard to paste into another native macOS app like Notes or TextEdit. Such apps that recognize custom URL schemes will treat the URL as a “live” link.&lt;/p&gt;
&lt;p&gt;&lt;img alt="img" src="images/open-in-emacs-shortcut/scrim-notepad-example.png"&gt;&lt;/p&gt;
&lt;p&gt;This shortcut is available at &lt;a href="https://www.icloud.com/shortcuts/195d64f6e4474826b71834fd06523c14"&gt;“scrim link” Shortcut iCloud Link&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Closing Thoughts&lt;/h1&gt;
&lt;p&gt;While the behavior of "Open in Emacs" seems modest, a &lt;em&gt;lot&lt;/em&gt; of things need to happen under the hood to orchestrate the different apps required to make it happen on macOS. But taking a step back, I'd observe that this is not unique to just macOS alone. Other contemporary operating systems are following suit as seen with &lt;a href="https://en.wikipedia.org/wiki/Snap_(software)"&gt;Snap (Ubuntu)&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Flatpak"&gt;Flatpak&lt;/a&gt; for Linux, and UWP for Windows. Such isolating practices by OS vendors are &lt;em&gt;not&lt;/em&gt; going away.&lt;/p&gt;
&lt;p&gt;Running counter to this is the spate of interest in orchestrating apps and/or services together using AI tools, whose approach so far is to bypass all hardened runtime boundaries.&lt;/p&gt;
&lt;p&gt;Then there is comparison to the Emacs ecosystem, where orchestration of apps (or rather modes) is routinely done via Elisp. By implementation circumstance there are effectively no concerns for security boundaries within the internals of Emacs.&lt;/p&gt;
&lt;p&gt;There's a lot of ground to ruminate on, in particular software malleability and orchestration, which I intend to do with future posts on this blog.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="macos"/><category term="scrim"/><category term="software"/></entry><entry><title>Anju v1.5.0 Update</title><link href="http://yummymelon.com/devnull/anju-v150-update.html" rel="alternate"/><published>2026-05-28T10:00:00-07:00</published><updated>2026-05-28T10:00:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-05-28:/devnull/anju-v150-update.html</id><summary type="html">&lt;p&gt;Anju v1.5.0 update out in the wild. Lots of goodies in it.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Heads up for readers of this blog who are using &lt;a href="https://github.com/kickingvegas/anju"&gt;Anju&lt;/a&gt; or are mouse-curious Emacs users. I’ve recently released the &lt;a href="https://github.com/kickingvegas/anju/discussions/121"&gt;v1.5.0 update&lt;/a&gt; for it, now available on &lt;a href="https://melpa.org/#/anju"&gt;MELPA&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Many new features and enhancements are in this update as outlined below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Context Menus&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Selected-Text-Commands.html"&gt;Enhancements to selected text&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;Query Replace (Regexp)…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Enhancements to Org mode support&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Org-Headline-Context-Menu.html"&gt;Headline&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;Change to Body&lt;/li&gt;
&lt;li&gt;Sort…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Org-Item-Context-Menu.html"&gt;Item&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;Cycle Bullet…&lt;/li&gt;
&lt;li&gt;Sort…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Org-Table-Context-Menu.html"&gt;Table&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;Sort…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Org-_201cCopy-as_2026_201d-Context-Menu.html"&gt;Copy as…&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Org-Insert-Link.html"&gt;Link…&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Added support for &lt;a href="https://kickingvegas.github.io/anju/Makefile-Context-Menu.html"&gt;Makefile mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Added support for &lt;a href="https://kickingvegas.github.io/anju/Info-Context-Menu.html"&gt;Info mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Added support for &lt;a href="https://kickingvegas.github.io/anju/Compilation_002fGrep-Context-Menu.html"&gt;Compilation/Grep mode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Main Menu&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tools menu enhancements&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Tools-Menu-Features.html"&gt;Global Org Commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Macro-Recorder-Menu.html"&gt;Macro Recorder&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Edit › Delete menu enhancement&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kickingvegas.github.io/anju/Edit-Menu-Features.html"&gt;Delete Duplicate Lines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Users who work with both Org mode and Markdown formatted text should find interest in the &lt;a href="https://kickingvegas.github.io/anju/Org-_201cCopy-as_2026_201d-Context-Menu.html"&gt;Copy as…&lt;/a&gt; capability added to the Org mode context menu. This feature lets one use Org mode as the primary means of authoring text, exporting to Markdown (or another format) using a right-click mouse copy action.&lt;/p&gt;
&lt;p&gt;&lt;img alt="img" src="images/anju-1-5/anju-context-menu-org-copy-as.png"&gt;&lt;/p&gt;
&lt;p&gt;Thanks to Marcin Borkowski whose post &lt;a href="https://mbork.pl/2021-05-02_Org-mode_to_Markdown_via_the_clipboard"&gt;“Org-mode to Markdown via the clipboard”&lt;/a&gt;, inspired this feature.&lt;/p&gt;
&lt;p&gt;Anju also provides a complementary command “Paste Markdown as Org” for Org mode which lets one paste copied Markdown text into an Org file, doing the conversion of Markdown to Org under the hood using &lt;code&gt;pandoc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="img" src="images/anju-1-5/anju-paste-markdown-as-org.png"&gt;&lt;/p&gt;
&lt;p&gt;In summary, this is a big release with many changes. I invite you to explore all the links above to see what’s available in Anju.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="org mode"/><category term="anju"/></entry><entry><title>Using the Mouse for Emacs Rectangle Commands</title><link href="http://yummymelon.com/devnull/using-the-mouse-for-emacs-rectangle-commands.html" rel="alternate"/><published>2026-05-18T09:45:00-07:00</published><updated>2026-05-18T09:45:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-05-18:/devnull/using-the-mouse-for-emacs-rectangle-commands.html</id><summary type="html">&lt;p&gt;Never look up Emacs rectangle commands in the manual again. Announcing support for rectangle commands in Anju v1.4.0 update.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;img alt="img" src="images/rectangle-mouse-commands/anju-main-menu-edit-rectangle.png"&gt;&lt;/p&gt;
&lt;p&gt;Of all the built-in editing commands in Emacs, the commands that work with &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Rectangles.html"&gt;rectangles&lt;/a&gt; delight me the most. Once understood, they can save effort in many situations.&lt;/p&gt;
&lt;p&gt;That said, the biggest downside to rectangles is the amount of setup it takes to &lt;em&gt;use&lt;/em&gt; them. As with many things Emacs, by default you have to memorize a bunch of keybindings to get anything done with them.&lt;/p&gt;
&lt;p&gt;In Casual, I addressed the above downside by providing a &lt;a href="https://kickingvegas.github.io/casual/Edit-commands.html#Rectangle_203a-_0028casual_002deditkit_002drectangle_002dtmenu_0029"&gt;Transient menu for rectangle commands&lt;/a&gt;. Since building that, I've come to use rectangle commands routinely. But even then, there is ceremony to set up a rectangle selection.&lt;/p&gt;
&lt;p&gt;With my recent work on mouse-driven interactions in Anju, I’ve learned that &lt;a href="http://yummymelon.com/devnull/some-nice-to-know-keybindings-when-using-the-mouse-in-emacs.html"&gt;rectangle selection&lt;/a&gt; is trivial via &lt;code&gt;C-M-&amp;lt;mouse-1&amp;gt;&lt;/code&gt; dragging. Once selected, having a menu of rectangle commands makes working with them even easier. So I made one for the latest &lt;a href="https://github.com/kickingvegas/anju/discussions/94"&gt;v1.4.0 update for Anju&lt;/a&gt;, now on &lt;a href="https://melpa.org/#/anju"&gt;MELPA&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The “Rectangle” sub-menu is available via the &lt;a href="https://kickingvegas.github.io/anju/Edit-Menu-Features.html"&gt;main menu bar “Edit” menu&lt;/a&gt; (as shown in the screenshot above) or via &lt;a href="https://kickingvegas.github.io/anju/Rectangle-Context-Menu.html"&gt;context menu&lt;/a&gt;. Using rectangle commands in conjunction with the &lt;code&gt;align-regexp&lt;/code&gt; (“Edit › Align Regexp…”) and &lt;code&gt;whitespace-cleanup&lt;/code&gt; (“Edit › Delete › Whitespace Cleanup”) can make short work of editing text that is laid out in columns. Anju makes both of these commands available from the main menu.&lt;/p&gt;
&lt;p&gt;Side note: on using &lt;code&gt;C-M-&amp;lt;mouse-1&amp;gt;&lt;/code&gt;, sometimes Emacs will only read &lt;code&gt;M-&amp;lt;mouse-1&amp;gt;&lt;/code&gt; and do a &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Secondary-Selection.html"&gt;secondary selection&lt;/a&gt;, leaving an unwanted highlight. Enter &lt;code&gt;M-&amp;lt;mouse-1&amp;gt;&lt;/code&gt; to dismiss the highlight.&lt;/p&gt;
&lt;p&gt;If you find Anju to be useful, please support its development by &lt;a href="https://buymeacoffee.com/kickingvegas"&gt;buying me a coffee&lt;/a&gt;. I’ve got a &lt;a href="https://github.com/kickingvegas/anju/issues"&gt;number of new features planned for it&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="anju"/></entry><entry><title>Enhancing Elisp Development with Context Menus</title><link href="http://yummymelon.com/devnull/enhancing-elisp-development-with-context-menus.html" rel="alternate"/><published>2026-05-11T11:00:00-07:00</published><updated>2026-05-11T11:00:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-05-11:/devnull/enhancing-elisp-development-with-context-menus.html</id><summary type="html">&lt;p&gt;Announcing support for Elisp development in the Anju v1.3.0 update.&lt;/p&gt;</summary><content type="html">&lt;p&gt;As celebrated as Emacs is for its programmability, I find the actual process of developing Emacs Lisp (Elisp) to be quite underwhelming. Developing in Elisp has meant learning its libraries and idioms, which is to be expected. What I really don’t care for though are the arcane keybindings associated with doing basic things like evaluating, navigating (Xref), and debugging (especially debugging). While I’ve already committed to muscle memory most of said keybindings, I’d argue that having a mouse-based “point and click” interface is beneficial for both novice and experienced Elisp developers alike, as it lets one focus on the code and not on recalling the right key incantation &lt;em&gt;all the time&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The addition of &lt;code&gt;context-menu-mode&lt;/code&gt; in Emacs 28 has provided the opportunity to build a mouse-based UI for Elisp development and I’m happy to announce the availability of one in the latest &lt;a href="https://github.com/kickingvegas/anju/discussions/84"&gt;v1.3.0 update to Anju&lt;/a&gt;, now on &lt;a href="https://melpa.org/#/anju"&gt;MELPA&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To get an idea of what’s available in the v1.3.0 update, here’s a screenshot of the context menu when normally editing an Elisp file where the point is on the symbol &lt;code&gt;foo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="img" src="images/elisp-context-menus/anju-context-menu-elisp.png"&gt;&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;foo&lt;/code&gt; is instrumented for debugging and run, the context menu is adjusted to provide Edebug commands as shown below.&lt;/p&gt;
&lt;p&gt;&lt;img alt="img" src="images/elisp-context-menus/anju-context-menu-edebug.png"&gt;&lt;/p&gt;
&lt;p&gt;The context menu enhancements provided by Anju take full advantage of built-in functions that identify context at &lt;em&gt;point&lt;/em&gt;. Is the point on a symbol? In a function? In an ERT test? On a &lt;code&gt;lambda&lt;/code&gt;? The menu items added by Anju take these factors into account to provide a &lt;em&gt;relevant&lt;/em&gt; menu offering.&lt;/p&gt;
&lt;p&gt;Users can read more about Anju’s context menu enhancements for Elisp development at &lt;a href="https://kickingvegas.github.io/anju/Emacs-Lisp-Context-Menu.html"&gt;Emacs Lisp Context Menu (Anju User Guide)&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Some backstory with Edebug&lt;/h1&gt;
&lt;p&gt;Back in 2024, I did a deep dive into Edebug so as to &lt;a href="http://yummymelon.com/presentations/demystifying-edebug/demystifying-edebug.html"&gt;give a presentation on it&lt;/a&gt; at the &lt;a href="https://www.meetup.com/emacs-sf/events/301454544/?eventOrigin=group_events_list"&gt;EmacsSF meetup&lt;/a&gt;. In doing so, I realized that all the core features for having an Elisp IDE were there, but no good UI to present it. I set upon prototyping one using Transient, with decidedly mixed results due to both Edebug and Transient fighting each other over window management.&lt;/p&gt;
&lt;p&gt;A later &lt;a href="http://yummymelon.com/devnull/prototyping-a-toolbar-ui-for-edebug.html"&gt;Edebug UI prototype using the toolbar&lt;/a&gt; was attempted but it also had its issues, particularly with layout (or lack thereof) and toolbar-specific bugs in macOS. But a benefit of using the toolbar was that its UI interactions did not interfere with window management. The context menu also shares this benefit.&lt;/p&gt;
&lt;h1&gt;Closing Thoughts&lt;/h1&gt;
&lt;p&gt;The context menu has markedly improved my developer experience with Elisp, as I find myself using it more than typing out keybindings. Even with keybindings, I’ll use the &lt;a href="https://kickingvegas.github.io/casual/Elisp.html"&gt;Casual Elisp Transient&lt;/a&gt; to accomplish most Elisp interactions that don’t require Edebug.&lt;/p&gt;
&lt;p&gt;That said, I’m not here to eschew keybindings. I still use them, when convenient. But in many circumstances they are not. The context menu can provide an easier way to achieve the same thing. Isn’t that a good thing?&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="anju"/></entry><entry><title>Bulk Search &amp; Replace Commands for Files and Buffers in Emacs</title><link href="http://yummymelon.com/devnull/bulk-search-replace-commands-for-files-and-buffers-in-emacs.html" rel="alternate"/><published>2026-04-29T22:15:00-07:00</published><updated>2026-04-29T22:15:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-04-29:/devnull/bulk-search-replace-commands-for-files-and-buffers-in-emacs.html</id><summary type="html">&lt;p&gt;An inventory of bulk commands to search and/or replace multiple files or buffers in Emacs.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Emacs offers a dizzying number of commands to perform bulk operations on multiple files or buffers. These commands are quite capable and can make trivial the execution of workflows that would be heroic in other editors. Unfortunately these commands are also difficult to discover as a number of them are not featured in easily accessible menus.&lt;/p&gt;
&lt;p&gt;This post calls attention to bulk commands related to search and replace in Emacs and how their discoverability can be improved using the &lt;a href="https://kickingvegas.github.io/casual/index.html"&gt;Casual&lt;/a&gt; and &lt;a href="https://kickingvegas.github.io/anju/"&gt;Anju&lt;/a&gt; UI packages.&lt;/p&gt;
&lt;h1&gt;Regular Expressions&lt;/h1&gt;
&lt;p&gt;Before moving forward, let’s talk about how Emacs handles regular expression syntax in search and/or replace commands. Whenever using an Emacs command involving a regular expression (regexp), you will need to understand what kind of regexp syntax is expected. There are largely two to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Syntax-of-Regexps.html"&gt;Emacs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;grep (implementation dependent)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Commands using grep-style regexps do so because they invoke the local install of the &lt;code&gt;grep&lt;/code&gt; utility. The grep regex syntax is implementation dependent. If you use GNU grep, you can read its &lt;a href="https://www.gnu.org/software/grep/manual/html_node/Regular-Expressions.html"&gt;syntax here&lt;/a&gt;, which share some &lt;a href="https://www.gnu.org/software/grep/manual/html_node/Character-Classes-and-Bracket-Expressions.html"&gt;character classes&lt;/a&gt; with &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Char-Classes.html"&gt;Emacs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://kickingvegas.github.io/casual/RE_002dBuilder-Usage.html"&gt;Casual RE-Builder&lt;/a&gt; package is a great way to work with Emacs regexps as it provides a command to escape the regexp properly for interactive input. &lt;code&gt;re-builder&lt;/code&gt; alone only provides a regexp that can be used in Elisp code.&lt;/p&gt;
&lt;h1&gt;Bulk Search &amp;amp; Replace Commands&lt;/h1&gt;
&lt;p&gt;The table below shows the different search and/or replace workflows and their associated commands.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Workflows&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Command&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Regexp Type&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search regexp in files in directory&lt;/td&gt;
&lt;td style="text-align: left;"&gt;rgrep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;grep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;AKA “Find in Files.” Results can be edited using writeable grep (wgrep).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search regexp in files in project&lt;/td&gt;
&lt;td style="text-align: left;"&gt;project-find-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;grep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search regexp in files in directory and present in Dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;find-grep-dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;grep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search regexp in tagged files&lt;/td&gt;
&lt;td style="text-align: left;"&gt;tags-search&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search file names matching shell pattern in directory and present in Dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;find-name-dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;shell&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search file names matching regexp in directory and present in Dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;find-lisp-find-dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Implementation uses Emacs regexp type.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search file names matching regexp in current directory and present in Dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;casual-dired-find-dired-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Wrapper around find-lisp-find-dired using current directory. Available via Casual.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Query replace regexp in project files&lt;/td&gt;
&lt;td style="text-align: left;"&gt;project-query-replace-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Incremental search marked files with plain text&lt;/td&gt;
&lt;td style="text-align: left;"&gt;dired-do-isearch&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in Dired.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Incremental search marked files with regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;dired-do-isearch-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in Dired.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Query replace regexp in marked files&lt;/td&gt;
&lt;td style="text-align: left;"&gt;dired-do-query-replace-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in Dired.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search regexp in marked files&lt;/td&gt;
&lt;td style="text-align: left;"&gt;dired-do-find-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;grep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in Dired.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Search regexp in marked files and display first match&lt;/td&gt;
&lt;td style="text-align: left;"&gt;dired-do-search&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in Dired.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Replace regexp in marked files&lt;/td&gt;
&lt;td style="text-align: left;"&gt;dired-do-find-regexp-and-replace&lt;/td&gt;
&lt;td style="text-align: left;"&gt;grep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in Dired.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Replace regexp in marked files using diff interface.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;dired-do-replace-regexp-as-diff&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in Dired.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Incremental search marked buffers with plain text&lt;/td&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-isearch&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in IBuffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Incremental search marked buffers with plain text with regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-isearch-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in IBuffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;View lines which match regexp in marked buffers&lt;/td&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-occur&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in IBuffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Query replace plain text in marked buffers&lt;/td&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-query-replace&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in IBuffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Query replace regexp in marked buffers&lt;/td&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-query-replace-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;For use in IBuffer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Run git grep, searching for regexp in directory.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;vc-git-grep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;grep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Replace all references to identifier.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;xref-find-references-and-replace&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Interactively replace identifier in current xref buffer.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;xref-query-replace-in-results&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Rename symbol at point for project.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;eglot-rename&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Requires Eglot support.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Replace regexp in files using diff interface.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;multi-file-replace-regexp-as-diff&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Start multi-buffer incremental search on a list of files.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;multi-isearch-files&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Start multi-buffer incremental regexp search on a list of files.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;multi-isearch-files-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Start multi-buffer incremental search on a list of buffers.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;multi-isearch-buffers&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Start multi-buffer incremental regexp search on a list of buffers.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;multi-isearch-buffers-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Show all lines in buffers containing a match for regexp.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;multi-occur&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Show all lines containing a match for regexp in buffers that match bufregexp.&lt;/td&gt;
&lt;td style="text-align: left;"&gt;multi-occur-in-matching-buffers&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emacs&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Choice of command depends on the quantity and specificity of files or buffers to work on. Both Dired and IBuffer marking allow for specific selection of files or buffers respectively.&lt;/p&gt;
&lt;p&gt;Many of the commands in the table above are discoverable via menu using the Casual and Anju packages. Hierarchical menu categorization aids in the discovery and recognition of these commands, making them more &lt;strong&gt;usable&lt;/strong&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Command&lt;/th&gt;
&lt;th style="text-align: left;"&gt;UI&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;rgrep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-editkit-main-tmenu › (/) Search/Replace › (g) Find in Files…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Search-_0026-Replace-commands.html"&gt;Casual EditKit&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;rgrep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(Menu-bar) Edit › Search › Search in Files…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/anju/Edit-Menu-Features.html"&gt;Anju.&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;project-find-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(Menu-bar) Edit › Search › Search in Project Files…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;tags-search&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(Menu-bar) Edit › Search › Search Tagged Files…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;project-query-replace-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(Menu-bar) Edit › Replace › Replace in Project Files…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;find-name-dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-editkit-main-tmenu › (/) Search/Replace › (d) Files…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Search-_0026-Replace-commands.html"&gt;Casual EditKit&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;find-grep-dired&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-editkit-main-tmenu › (/) Search/Replace › (G) Files containing text…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Search-_0026-Replace-commands.html"&gt;Casual EditKit&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;casual-dired-find-dired-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-dired-tmenu › (f) Filter by name…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Dired-Usage.html"&gt;Casual Dired&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;dired-do-isearch&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-dired-tmenu › (/) Search/Replace › (C-s) I-search…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Dired-Search-_0026-Replace-_0028Search-_0026-Replace_203a_0029.html"&gt;Casual Dired&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;dired-do-isearch-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-dired-tmenu › (/) Search/Replace › (M-s) I-search regexp…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Dired-Search-_0026-Replace-_0028Search-_0026-Replace_203a_0029.html"&gt;Casual Dired&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;dired-do-query-replace-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-dired-tmenu › (/) Search/Replace › (r) Query regexp and replace…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Dired-Search-_0026-Replace-_0028Search-_0026-Replace_203a_0029.html"&gt;Casual Dired&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;dired-do-find-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-dired-tmenu › (/) Search/Replace › (g) Find regex…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Dired-Search-_0026-Replace-_0028Search-_0026-Replace_203a_0029.html"&gt;Casual Dired&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;dired-do-search&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-dired-tmenu › (/) Search/Replace › (s) Search first regexp match…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Dired-Search-_0026-Replace-_0028Search-_0026-Replace_203a_0029.html"&gt;Casual Dired&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;dired-do-find-regexp-and-replace&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-dired-tmenu › (/) Search/Replace › (G) Find regex and replace…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/Dired-Search-_0026-Replace-_0028Search-_0026-Replace_203a_0029.html"&gt;Casual Dired&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-isearch&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-ibuffer-tmenu › (C-s) I-Search…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/IBuffer-Usage.html"&gt;Casual IBuffer&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-isearch-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-ibuffer-tmenu › (C-M-s) I-Search Regexp…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/IBuffer-Usage.html"&gt;Casual IBuffer&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-occur&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-ibuffer-tmenu › (O) Occur…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/IBuffer-Usage.html"&gt;Casual IBuffer&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-query-replace&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-ibuffer-tmenu › (M-r) Query Replace…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/IBuffer-Usage.html"&gt;Casual IBuffer&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;ibuffer-do-query-replace-regexp&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(C-o) casual-ibuffer-tmenu › (C-M-r) Query Replace Regexp…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Available via &lt;a href="https://kickingvegas.github.io/casual/IBuffer-Usage.html"&gt;Casual IBuffer&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;vc-git-grep&lt;/td&gt;
&lt;td style="text-align: left;"&gt;(Menu-bar) Tools › Version Control &amp;gt; Git grep…&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;Refactoring Guidance&lt;/h1&gt;
&lt;p&gt;The replace commands can do catastrophic damage if not used with caution. Treat them like power tools.&lt;/p&gt;
&lt;p&gt;Some guidance before using replace commands:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Have a backup plan in case you need to recover anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;re-builder&lt;/code&gt; to help figure out the right regexp.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Know the scope of what you want to change (directory, files, buffers).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some commands will only modify the buffer of an affected file. Check if modified buffers are saved. You can use IBuffer to identify and save such buffers. It is left as an exercise to the reader to determine which commands exhibit this behavior.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Closing Thoughts&lt;/h1&gt;
&lt;p&gt;The inventory of commands above are from what I know of Emacs, which is guaranteed to not be comprehensive. If there are others missing from this list, please let me know at &lt;a href="mailto:kickingvegas@gmail.com?subject=Blog%20Post:%20Bulk%20Search%20and%20Replace"&gt;kickingvegas@gmail.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While many of these commands have been in Emacs for years (decades even), they were not usable to me until I built a UI for them. I think motivated readers using Casual and Anju for bulk search and/or replace tasks will find a similar sentiment.&lt;/p&gt;
&lt;hr/&gt;

&lt;p&gt;&lt;em&gt;Amended 2026-04-30&lt;/em&gt;: Added &lt;code&gt;vc-git-grep&lt;/code&gt;, &lt;code&gt;eglot-rename&lt;/code&gt;,  &lt;code&gt;xref-find-references-and-replace&lt;/code&gt;, and &lt;code&gt;xref-query-replace-in-results&lt;/code&gt;. Thanks to &lt;a href="https://social.lol/@hl/116492031100071433"&gt;Henry Leach&lt;/a&gt; and &lt;a href="https://toot.cat/@etenil/116492135347675653"&gt;Gene Pasquet&lt;/a&gt; for their input!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Amended 2026-05-04&lt;/em&gt;: Added &lt;code&gt;dired-do-replace-regexp-as-diff&lt;/code&gt;, &lt;code&gt;multi-file-replace-regexp-as-diff&lt;/code&gt;, &lt;code&gt;multi-isearch-files&lt;/code&gt;, &lt;code&gt;multi-isearch-files-regexp&lt;/code&gt;, &lt;code&gt;multi-isearch-buffers&lt;/code&gt;, &lt;code&gt;multi-isearch-buffers-regexp&lt;/code&gt;, &lt;code&gt;multi-occur&lt;/code&gt;, &lt;code&gt;multi-occur-in-matching-buffers&lt;/code&gt;. Learned about the diff commands from Christian Tietze's post &lt;a href="https://christiantietze.de/posts/2025/02/preview-mass-text-replacements-with-emacs-30-1-replace-regexp-as-diff/"&gt;Preview Mass Text Replacements with Emacs 30.1 replace-regexp-as-diff&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/></entry><entry><title>Some nice to know keybindings when using the mouse in Emacs</title><link href="http://yummymelon.com/devnull/some-nice-to-know-keybindings-when-using-the-mouse-in-emacs.html" rel="alternate"/><published>2026-04-24T13:40:00-07:00</published><updated>2026-04-24T13:40:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-04-24:/devnull/some-nice-to-know-keybindings-when-using-the-mouse-in-emacs.html</id><summary type="html">&lt;p&gt;Some keybindings to know whenever you’re working with a mouse in Emacs.&lt;/p&gt;</summary><content type="html">&lt;p&gt;These keybindings are good to know when working with a mouse in Emacs.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;F10&lt;/code&gt; (&lt;code&gt;menu-bar-open&lt;/code&gt;) :: Start key navigation of the menu bar in FRAME.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;S-F10&lt;/code&gt; (&lt;code&gt;context-menu-open&lt;/code&gt;) :: Start key navigation of the context menu. This needs &lt;code&gt;context-menu-mode&lt;/code&gt; enabled.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-M-mouse-1&lt;/code&gt; :: Activate a rectangular region around the text selected by dragging. Useful for &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Rectangles.html"&gt;rectangle&lt;/a&gt; operations.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;M-Drag-mouse-1&lt;/code&gt; ::  Set the secondary selection, with one end at the place where you press down the button, and the other end at the place where you release it. See &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Secondary-Selection.html"&gt;Secondary Selection&lt;/a&gt; for more info.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-mouse-3&lt;/code&gt;:: Raise menu populated with the menu mode map of the current mode and if Imenu is enabled, &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Imenu.html"&gt;an index menu for that buffer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-u&lt;/code&gt; &lt;em&gt;n (optional)&lt;/em&gt;  :: A &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Prefix-Command-Arguments.html"&gt;prefix argument&lt;/a&gt; can be passed to a menu item.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Keyboard Macro&lt;/em&gt; :: Commands issued via menu can be used when recording a &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Keyboard-Macros.html"&gt;keyboard macro&lt;/a&gt;.  (🤯 Who knew?)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-x z&lt;/code&gt; (&lt;code&gt;repeat&lt;/code&gt;) :: Repeat most recently executed command. Yes, &lt;code&gt;repeat&lt;/code&gt; works also for commands issued via mouse too!&lt;/p&gt;
&lt;p&gt;Knowing that &lt;code&gt;repeat&lt;/code&gt; works with menu commands (both main and context) is particularly useful with the additions to the main menu made by the latest &lt;a href="https://github.com/kickingvegas/anju/discussions/63"&gt;Anju v1.2.0 update&lt;/a&gt;. Shown below is a demo of using “Duplicate” (&lt;code&gt;duplicate-dwim&lt;/code&gt;) from the Edit menu, then using &lt;code&gt;C-x z&lt;/code&gt; and then &lt;code&gt;z&lt;/code&gt; successively to repeat the duplication.&lt;/p&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;video controls  muted=true poster="http://yummymelon.com/devnull/images/mouse-keybindings/anju-duplicate-demo-thumb.png" width="75%"&gt;
&lt;source src="http://yummymelon.com/devnull/images/videos/anju-duplicate-demo-720.mov" type="video/mp4" /&gt;
&lt;p&gt;
Your browser does not support HTML video. &lt;a href="http://yummymelon.com/devnull/images/videos/anju-duplicate-demo-720.mov" download="{static}images/videos/anju-duplicate-demo-720.mov"&gt;Link to video&lt;/a&gt;.
&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Amended 2026-04-25&lt;/em&gt;:  Added &lt;code&gt;C-M-mouse-1&lt;/code&gt;, &lt;code&gt;M-Drag-mouse-1&lt;/code&gt;, &lt;code&gt;C-mouse-3&lt;/code&gt;, &lt;code&gt;C-u n&lt;/code&gt;, &lt;em&gt;Keyboard Macro&lt;/em&gt; items.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="anju"/></entry><entry><title>Call for Testing: Scrim v1.1.3 TestFlight on pre-release Emacs 31</title><link href="http://yummymelon.com/devnull/call-for-testing-scrim-113-testflight-on-pre-release-emacs-31.html" rel="alternate"/><published>2026-04-23T14:40:00-07:00</published><updated>2026-04-23T14:40:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-04-23:/devnull/call-for-testing-scrim-113-testflight-on-pre-release-emacs-31.html</id><summary type="html">&lt;p&gt;Looking for folks who want to test a new pre-release build of Scrim v1.1.3 which fixes it for Emacs 31.&lt;/p&gt;</summary><content type="html">&lt;p&gt;For folks who like using the development build of Emacs (at the time of this writing Emacs 31.0.5) on macOS, it turns out there is a &lt;a href="https://github.com/kickingvegas/scrim/issues/76"&gt;bug&lt;/a&gt; in how &lt;a href="http://yummymelon.com/scrim/"&gt;Scrim&lt;/a&gt; sends Org protocol requests to it.&lt;/p&gt;
&lt;p&gt;A fix has been identified and so far it works fine for both Emacs 30.2 and 31.0.5 from my testing. That said, it is always better to have more folks trying it out.&lt;/p&gt;
&lt;p&gt;If you use the latest Emacs 31.0.5+ on macOS and use (or are interested in using) Org protocol, I invite you to &lt;a href="https://testflight.apple.com/join/5HNzNtft"&gt;try out a TestFlight build of Scrim v1.1.3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If this is the first time you’ve heard about Scrim, learn more about it at &lt;a href="http://yummymelon.com/scrim/"&gt;http://yummymelon.com/scrim/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks much!&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="org mode"/><category term="scrim"/><category term="macos"/></entry><entry><title>Computing Days Until with Emacs</title><link href="http://yummymelon.com/devnull/computing-days-until-with-emacs.html" rel="alternate"/><published>2026-04-08T16:00:00-07:00</published><updated>2026-04-08T16:00:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-04-08:/devnull/computing-days-until-with-emacs.html</id><summary type="html">&lt;p&gt;Countdown clocks are always useful. Here’s one for computing days until in Emacs.&lt;/p&gt;</summary><content type="html">&lt;p&gt;A recent Mastodon post showing the days until the next U.S. election got me to wonder, “how can I compute that in Emacs?” Turns out, this is trivial with the Org mode function &lt;code&gt;org-time-stamp-to-now&lt;/code&gt; doing the timestamp computation for you.&lt;/p&gt;
&lt;p&gt;We can wrap &lt;code&gt;org-time-stamp-to-now&lt;/code&gt; in an internal function &lt;code&gt;cc/--days-until&lt;/code&gt; that generates a formatted string of the days until a target date.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cc/--days-until&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;&amp;amp;optional&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Formatted string of days until TARGET.&lt;/span&gt;

&lt;span class="s"&gt;- TARGET: date string that conforms to &lt;/span&gt;&lt;span class="ss"&gt;`parse-time-string&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;
&lt;span class="s"&gt;- TEMPLATE : format string that includes ‘%d’ specifier.&lt;/span&gt;

&lt;span class="s"&gt;If TEMPLATE is nil, then a predefined format string will be&lt;/span&gt;
&lt;span class="s"&gt;used.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;template&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="nv"&gt;template&lt;/span&gt;
&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d days until &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;days&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;org-time-stamp-to-now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;days&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;From there we can then start defining commands that use &lt;code&gt;cc/--days-until&lt;/code&gt;. The command cc/days-until shown below will prompt you with a date picker to enter a date. Note that you can enter a date value (e.g. “Dec 25, 2026”) in the mini-buffer prompt for &lt;code&gt;org-read-date&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cc/days-until&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Prompt user for date and show days until in the mini-buffer.&lt;/span&gt;

&lt;span class="s"&gt;Use &lt;/span&gt;&lt;span class="ss"&gt;`org-read-date&amp;#39;&lt;/span&gt;&lt;span class="s"&gt; to compute days until to display in the mini-buffer.&lt;/span&gt;

&lt;span class="s"&gt;If prefix ARG is non-nil, then the computed result is stored in the&lt;/span&gt;
&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="ss"&gt;`kill-ring&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interactive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;org-read-date&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cc/--days-until&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kill-new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Going back to the original motivator for this post, here’s an implementation of days until the next two major U.S. election dates with the command &lt;code&gt;cc/days-until-voting&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cc/days-until-voting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Days until U.S. elections in 2026 and 2028.&lt;/span&gt;

&lt;span class="s"&gt;If prefix ARG is non-nil, then the computed result is stored in the&lt;/span&gt;
&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="ss"&gt;`kill-ring&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interactive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;midterms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cc/--days-until&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2026-11-03&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d days until 2026 midterms&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;election&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cc/--days-until&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2028-11-07&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d days until 2028 presidential election&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s, %s&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;midterms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;election&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kill-new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The result of &lt;code&gt;M-x cc/days-until-voting&lt;/code&gt; as of 8 April 2026 is:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;209 days until 2026 midterms, 944 days until 2028 presidential election&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It’s so human to want to know how long it’s going to take. Feel free to build your own countdown clocks using the code above. May your journey to whatever you plan be a happy one!&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="org mode"/></entry><entry><title>Calming Mouse Interaction in Dired</title><link href="http://yummymelon.com/devnull/calming-mouse-interaction-in-dired.html" rel="alternate"/><published>2026-04-07T13:25:00-07:00</published><updated>2026-04-07T13:25:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-04-07:/devnull/calming-mouse-interaction-in-dired.html</id><summary type="html">&lt;p&gt;Single click to open a file in Dired is too twitchy. This post shows how to change it.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Conventional file managers have conditioned me to expect that a single left-button mouse click (&lt;code&gt;&amp;lt;mouse-1&amp;gt;&lt;/code&gt;) will select a file (or directory) and double-click will open it. This is not the default behavior of Dired, where a single click is an open action. I find this far too twitchy for my taste.&lt;/p&gt;
&lt;p&gt;This post shows how to make Dired mouse interaction align with a conventional file manager where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Single-click on a file or directory will move the point to it, making it the implicit target for any subsequent Dired command.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Left double-click on file or directory will open it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Selecting multiple files is emulated using Dired marking, in this case using the binding &lt;code&gt;M-&amp;lt;mouse-1&amp;gt;&lt;/code&gt; to toggle marking a file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first two points above can be addressed with the global variable &lt;code&gt;mouse-1-click-follows-link&lt;/code&gt;. Dired uses this variable to control its mouse behavior, but we don’t want to change it everywhere, just for Dired buffers. This can be implemented by setting &lt;code&gt;mouse-1-click-follows-link&lt;/code&gt; locally as a hook to &lt;code&gt;dired-mode-hook&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;dired-mode-hook&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;lambda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;setq-local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;mouse-1-click-follows-link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;double&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To address multiple file selection, we can define a function &lt;code&gt;cc/dired-mouse-toggle-mark&lt;/code&gt; and bind it to &lt;code&gt;M-&amp;lt;mouse-1&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cc/dired-mouse-toggle-mark&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Toggle mark of a Dired item via mouse.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;unless&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;use-region-p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;mouse-set-point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;last-input-event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;char-equal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;char-after&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;line-beginning-position&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dired-marker-char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;call-interactively&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;dired-unmark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;call-interactively&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;dired-mark&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dired-mode-map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;mouse-1&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;cc/dired-mouse-toggle-mark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Coupled with &lt;a href="https://melpa.org/#/anju"&gt;Anju&lt;/a&gt; support for a &lt;a href="https://kickingvegas.github.io/anju/Dired-Mode-Context-Menu.html"&gt;Dired specific context menu&lt;/a&gt; and many basic file manager operations can be done in Dired via mouse with minimal fuss.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="anju"/></entry><entry><title>Announcing Anju</title><link href="http://yummymelon.com/devnull/announcing-anju.html" rel="alternate"/><published>2026-03-30T08:45:00-07:00</published><updated>2026-03-30T08:45:00-07:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-03-30:/devnull/announcing-anju.html</id><summary type="html">&lt;p&gt;Announcing Anju, a project to align mouse interactions in Emacs with contemporary (circa 2026) expectations. Now available on MELPA.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The recent post “&lt;a href="https://meanwhiling.com/you-dont-not-need-the-mouse.html"&gt;You don’t not need the mouse&lt;/a&gt;” by noa ks speaks to a sentiment that I’ve had for some time. Using the mouse in Emacs can be a good, daresay &lt;em&gt;delightful&lt;/em&gt;, experience. Unfortunately though, Emacs has antiquated default settings that presume we’re all still using a &lt;a href="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Sun_optical_mouse.jpg/960px-Sun_optical_mouse.jpg"&gt;90’s style 3-button workstation mouse&lt;/a&gt;. In addition, the overreliance on reusing menu keymaps for both the main &lt;em&gt;and&lt;/em&gt; context menus results in poor user experience. I feel strongly that context menus populated this way feel more like an inventory than a thoughtful selection of commands relevant to &lt;em&gt;context&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Thankfully, Emacs offers the mechanisms to sculpt mouse interactions to contemporary (circa 2026) expectations. Over the past three years, I’ve taken advantage of them to implement the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mode Line&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Right mouse click on blank space to pop-up a window management menu&lt;/li&gt;
&lt;li&gt;Left mouse click on buffer name to pop-up a customizable list of buffers&lt;/li&gt;
&lt;li&gt;Double click on blank space to toggle current window to maximize or return to prior window configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Context Menu&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Context-aware commands for selected text (&lt;code&gt;use-region-p&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Context-aware commands for Org and Dired mode&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Main Menu&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add Bookmarks menu&lt;/li&gt;
&lt;li&gt;Reorganize Help menu&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Several months ago, I decided these mouse interaction changes should be generalized into a package that others could use. So began the &lt;em&gt;Anju&lt;/em&gt; project.&lt;/p&gt;
&lt;p&gt;Today I’m happy to announce that &lt;a href="https://github.com/kickingvegas/anju"&gt;Anju v1.0&lt;/a&gt; is now available on &lt;a href="https://melpa.org/#/anju"&gt;MELPA&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Learn more details about Anju in its &lt;a href="https://kickingvegas.github.io/anju/"&gt;User Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As Anju is new, I’m always open to constructive feedback on it. Let me know &lt;a href="https://github.com/kickingvegas/anju/discussions/33"&gt;what you think&lt;/a&gt;. Work on Anju is ongoing with the plan to keep adding improvements to it over time, in particular with supporting more context menus for different modes.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="anju"/></entry><entry><title>Casual now available on NonGNU ELPA</title><link href="http://yummymelon.com/devnull/casual-now-available-on-nongnu-elpa.html" rel="alternate"/><published>2026-03-03T13:10:00-08:00</published><updated>2026-03-03T13:10:00-08:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-03-03:/devnull/casual-now-available-on-nongnu-elpa.html</id><summary type="html">&lt;p&gt;Casual is now available on NonGNU ELPA.&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you are an Emacs user who only uses 3rd party packages from ELPA or NonGNU ELPA, I’m happy to announce that &lt;a href="https://elpa.nongnu.org/nongnu/casual.html"&gt;Casual is now available on NonGNU ELPA&lt;/a&gt;. 🎉&lt;/p&gt;
&lt;p&gt;If this is the first time you’ve heard of Casual, it is a project to re-imagine the primary user interface for Emacs using keyboard-driven menus. Casual’s design intent is to make the vast feature set of Emacs easier to discover and use in &lt;em&gt;casual&lt;/em&gt; fashion. It does so by providing bespoke hand-crafted menus for different modes provided by Emacs. These menus are opinionated in that the design of what goes into those menus are editorially determined by yours truly. To understand more about what Casual has to offer, &lt;a href="https://kickingvegas.github.io/casual/"&gt;please peruse its User Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In terms of implementation, Casual is built using the &lt;a href="https://docs.magit.vc/transient/"&gt;Transient library&lt;/a&gt; made by Jonas Bernoulli. This is the same library that powers the UI for &lt;a href="https://magit.vc/"&gt;Magit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Development of Casual has been on-going for nearly &lt;em&gt;two years&lt;/em&gt; now. Interested readers can read about Casual’s progress over that time &lt;a href="http://yummymelon.com/devnull/tag/casual.html"&gt;from my blog posts here&lt;/a&gt;. Throughout it all I’ve learned a lot about Emacs, its ecosystem of modes, and the powerful features they bring. It has only reinforced my conviction that Casual makes these powerful features more &lt;em&gt;usable&lt;/em&gt; beyond what is offered by default in Emacs.&lt;/p&gt;
&lt;p&gt;To clarify, if you still get Casual from &lt;a href="https://melpa.org/#/casual"&gt;MELPA&lt;/a&gt; (or MELPA Stable), &lt;em&gt;you do not have to change anything&lt;/em&gt;. The only difference is that users can now choose to install Casual from either MELPA or NonGNU ELPA. Updates to Casual will be distributed on both equally.&lt;/p&gt;
&lt;p&gt;My thanks goes out to the NonGNU ELPA reviewers who have provided guidance in helping get Casual on there. Additional thanks goes out to all the Casual users whose input and support have kept me going at this since 2024.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="casual"/></entry><entry><title>Announcing Casual Org</title><link href="http://yummymelon.com/devnull/announcing-casual-org.html" rel="alternate"/><published>2026-02-19T15:00:00-08:00</published><updated>2026-02-19T15:00:00-08:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-02-19:/devnull/announcing-casual-org.html</id><summary type="html">&lt;p&gt;At long last, announcing Casual support for Org Mode.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Most Emacs Org users would concur that &lt;strong&gt;Org mode&lt;/strong&gt; is a magnificent tool for capturing and communicating thought. That said, Org mode’s &lt;a href="https://orgmode.org/features.html"&gt;vast set of features&lt;/a&gt; can be daunting to master. A common guidance for new users is to take it slow: incrementally learn a subset of Org’s features as you need them.&lt;/p&gt;
&lt;p&gt;A big reason for Org mode’s steep learning curve is that it adopts Emacs’ unfortunate culture of compelling users to memorize keybindings. Learning a distinct keybinding for each Org command (remember I said &lt;em&gt;vast&lt;/em&gt; feature set?) is onerous, so a different tack is made: reuse the same keybinding but have it possess different behavior based on context. This context is usually tied to the type of structure the point (aka cursor) is in. For example, if the point is in a source block, the binding &lt;code&gt;C-c C-c&lt;/code&gt; would execute it, but if the point is on a checkbox item, then &lt;code&gt;C-c C-c&lt;/code&gt; would toggle its checked state. Taking this approach lowers the effort to recall a keybinding at the cost of recalling what its contextual behavior would be. In practice, using such overloaded keybindings is…okay. But I’d argue that we could have a more usable interface, leading to the point of this post:&lt;/p&gt;
&lt;p&gt;Announcing support for &lt;a href="https://kickingvegas.github.io/casual/Org.html"&gt;Org mode&lt;/a&gt; in the &lt;a href="https://github.com/kickingvegas/casual/discussions/397"&gt;v2.14.0 update for Casual&lt;/a&gt;, now available on &lt;a href="https://melpa.org/#/casual"&gt;MELPA&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Readers of this blog will know that &lt;a href="https://kickingvegas.github.io/casual/"&gt;Casual&lt;/a&gt; is my project to re-imagine the primary user interface for Emacs using keyboard-driven menus. If this is new to you, I highly recommend reading this &lt;a href="https://github.com/kickingvegas/casual"&gt;introduction&lt;/a&gt; to it.&lt;/p&gt;
&lt;p&gt;Primary to the design of the Casual Org menus is to be context-sensitive, only showing a subset of Org mode commands that are relevant. This set of context-sensitive commands is opinionated, but seeks to provide utility to users both new and experienced with Org.&lt;/p&gt;
&lt;p&gt;Shown below is a demo of Casual Org at work:&lt;/p&gt;
&lt;video controls  muted=true poster="http://yummymelon.com/devnull/images/announcing-casual-org/casual-org-demo-poster.png" width="75%"&gt;
&lt;source src="http://yummymelon.com/devnull/images/videos/casual-org-demo.mp4" type="video/mp4" /&gt;
&lt;p&gt;
Your browser does not support HTML video. &lt;a href="http://yummymelon.com/devnull/images/videos/casual-org-demo.mp4" download="{static}images/videos/casual-org-demo.mp4"&gt;Link to video&lt;/a&gt;.
&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;While the design of this UI has been months in the making, there is nothing like real-world use and feedback. &lt;a href="https://github.com/kickingvegas/casual/discussions/397"&gt;Constructive input is appreciated&lt;/a&gt;, especially if you are relatively new to using Org.&lt;/p&gt;
&lt;p&gt;A great deal of thanks goes out to the maintainers of and contributors to Org mode and to the community that uses it. If you are able, &lt;a href="https://liberapay.com/org-mode"&gt;please support it&lt;/a&gt;. Also, if you find Casual useful, I’d &lt;a href="https://buymeacoffee.com/kickingvegas"&gt;appreciate a coffee&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;&amp;#x2014;&lt;/p&gt;
&lt;p&gt;Video music: &lt;a href="https://jonreyes.bandcamp.com/track/burna-boy-last-last-jon-reyes-findaway-blend"&gt;Burna Boy - Last Last (JON REYES FINDAWAY BLEND) | Jon Reyes&lt;/a&gt;&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="org mode"/><category term="casual"/></entry><entry><title>Deburring Emacs Imenu GUI Configuration</title><link href="http://yummymelon.com/devnull/deburring-emacs-imenu-gui-configuration.html" rel="alternate"/><published>2026-02-10T09:20:00-08:00</published><updated>2026-02-10T09:20:00-08:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-02-10:/devnull/deburring-emacs-imenu-gui-configuration.html</id><summary type="html">&lt;p&gt;A bit of tuning to get Imenu GUI configuration working with any derived mode from &lt;code&gt;prog-mode&lt;/code&gt;.&lt;/p&gt;</summary><content type="html">&lt;p&gt;A while back, I made a &lt;a href="http://yummymelon.com/devnull/til-imenu.html"&gt;post on Emacs Imenu configuration&lt;/a&gt; that made an unsafe assumption that any mode derived from &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Basic-Major-Modes.html#index-prog_002dmode"&gt;prog-mode&lt;/a&gt; would support Imenu. Turns out, that’s not always true (for example, looking at you &lt;code&gt;gnuplot-mode&lt;/code&gt;). This post shows how to deal with this using an error handler.&lt;/p&gt;
&lt;p&gt;One such implementation of an error handler is the lambda expression shown below using &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Handling-Errors.html"&gt;condition-case&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;prog-mode-hook&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;lambda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;condition-case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;imenu-add-menubar-index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;imenu-unavailable&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;inhibit-message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Warning: %s&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;error-message-string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A couple of observations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The error handler is opportunistic in applying &lt;code&gt;imenu-add-menubar-index&lt;/code&gt; to a mode derived from &lt;code&gt;prog-mode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the error &lt;code&gt;imenu-unavailable&lt;/code&gt; is caught, then a warning message is logged but not messaged to the mini-buffer.&lt;ul&gt;
&lt;li&gt;The variable &lt;code&gt;inhibit-message&lt;/code&gt; is used to avoid sending a warning message to the minibuffer (it will still be logged in &lt;strong&gt;&lt;em&gt;*Messages&lt;/em&gt;&lt;/strong&gt;*) to avoid noise from modes that do not support Imenu. (Thanks to bpalmer for this guidance.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you use Emacs and this is the first time you’ve heard of &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Imenu.html"&gt;Imenu&lt;/a&gt;, I highly recommend that you learn what it has to offer.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/></entry><entry><title>Using Casual to work with Emacs Registers, Rectangles, and Windows</title><link href="http://yummymelon.com/devnull/using-casual-to-work-with-emacs-registers-rectangles-and-windows.html" rel="alternate"/><published>2026-02-07T10:00:00-08:00</published><updated>2026-02-07T10:00:00-08:00</updated><author><name>Charles Choi</name></author><id>tag:yummymelon.com,2026-02-07:/devnull/using-casual-to-work-with-emacs-registers-rectangles-and-windows.html</id><summary type="html">&lt;p&gt;Use Casual to effectively use Emacs registers, rectangles, and windows on the regular.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The features of &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Registers.html"&gt;registers&lt;/a&gt;, &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Rectangles.html"&gt;rectangles&lt;/a&gt;, and &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Windows.html"&gt;window management&lt;/a&gt; in Emacs are quite powerful yet prior to building &lt;a href="https://kickingvegas.github.io/casual/"&gt;Casual&lt;/a&gt;, I rarely used them because of the cognitive load of remembering each feature’s command sets, much less their bindings. Using keyboard-driven menus tailored for these three features changed that. Now I only have to recall &lt;em&gt;three&lt;/em&gt; key bindings to get easy access to registers, rectangles, and window management. This post demonstrates how you can as well.&lt;/p&gt;
&lt;p&gt;Provided you have &lt;a href="https://melpa.org/#/casual"&gt;Casual installed from MELPA&lt;/a&gt;, consider making the following global key bindings to your Emacs setup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-c r&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;casual-editkit-rectangle-tmenu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-c g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;casual-editkit-registers-tmenu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-c w&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;casual-editkit-windows-tmenu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As always, you can adjust these bindings to your preference.&lt;/p&gt;
&lt;p&gt;Each of these menus are detailed further below.&lt;/p&gt;
&lt;h1&gt;Rectangle Menu (&lt;a href="https://kickingvegas.github.io/casual/Edit-commands.html#Rectangle_203a-_0028casual_002deditkit_002drectangle_002dtmenu_0029"&gt;casual-editkit-rectangle-tmenu&lt;/a&gt;)&lt;/h1&gt;
&lt;p&gt;The rectangle feature gives you the ability to mark (select) an arbitrary rectangle region in an Emacs buffer. There are many times where if the text is shaped like a rectangle, making transformations on them is exceptionally convenient. This menu provides you this.&lt;/p&gt;
&lt;p align='left'&gt;
&lt;img src='http://yummymelon.com/devnull/images/casual-registers-rectangles-windows/casual-editkit-rectangle-screenshot.png' alt='Screenshot of Casual rectangle menu' /&gt;
&lt;/p&gt;

&lt;h1&gt;Registers Menu (&lt;a href="https://kickingvegas.github.io/casual/Register-commands.html"&gt;casual-editkit-registers-tmenu&lt;/a&gt;)&lt;/h1&gt;
&lt;p&gt;Registers provide users a way to temporarily keep track of Emacs run-time state like text clippings, cursor (point) positions, macros, and arrangement of windows.&lt;/p&gt;
&lt;p align='left'&gt;
&lt;img src='http://yummymelon.com/devnull/images/casual-registers-rectangles-windows/casual-editkit-registers-screenshot.png' alt='Screenshot of Casual registers menu' /&gt;
&lt;/p&gt;

&lt;p&gt;Registers are a distinguishing feature of Emacs from other applications that support writing. It’s definitely a feature I miss when working outside of Emacs.&lt;/p&gt;
&lt;h1&gt;Windows Menu (&lt;a href="https://kickingvegas.github.io/casual/Window-management.html"&gt;casual-editkit-windows-tmenu&lt;/a&gt;)&lt;/h1&gt;
&lt;p&gt;In Emacs vernacular, a &lt;em&gt;window&lt;/em&gt; is a visual organization of how a buffer is displayed. Emacs windows are &lt;em&gt;not&lt;/em&gt; the same as what conventional GUIs (e.g. Wayland/X11, Apple macOS, Microsoft Windows) refer to as windows. In Emacs, GUI windows are referred to as &lt;em&gt;frames&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Emacs provides a number of commands to manage windows throughout their entire life-cycle which Casual organizes into the menu shown below:&lt;/p&gt;
&lt;p align='left'&gt;
&lt;img src='http://yummymelon.com/devnull/images/casual-registers-rectangles-windows/casual-editkit-window-screenshot.png' alt='Screenshot of Casual window management menu' /&gt;
&lt;/p&gt;

&lt;p&gt;In practice, I’ve found this menu to be most useful when using a compact/laptop-style keyboard or accessing Emacs via TTY. But if you are using GUI Emacs with a keyboard that has a number-pad, consider making the following number-pad bindings, particularly for selecting focus and swapping windows.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;;; Number pad bindings for window management.&lt;/span&gt;
&lt;span class="c1"&gt;;; Requires GUI Emacs.&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-add&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;enlarge-window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-subtract&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;shrink-window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;kp-add&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;enlarge-window-horizontally&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;kp-subtract&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;shrink-window-horizontally&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-enter&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;other-window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;kp-enter&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;switch-to-buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;return&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;other-window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-8&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-up&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-5&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-down&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-2&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-down&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-4&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-6&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;kp-8&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-swap-states-up&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;kp-5&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-swap-states-down&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;kp-2&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-swap-states-down&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;kp-4&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-swap-states-left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;M-&amp;lt;kp-6&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;windmove-swap-states-right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;;; These require the `ace-window&amp;#39; and `transpose-frame&amp;#39; packages.&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-0&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;ace-select-window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keymap-global-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;C-&amp;lt;kp-divide&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;transpose-frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note that the bindings for &lt;code&gt;ace-select-window&lt;/code&gt; and &lt;code&gt;transpose-frame&lt;/code&gt; require that you have the &lt;a href="https://melpa.org/#/ace-window"&gt;ace-window&lt;/a&gt; and &lt;a href="https://melpa.org/#/transpose-frame"&gt;transpose-frame&lt;/a&gt; packages installed.&lt;/p&gt;
&lt;h1&gt;Closing Thoughts&lt;/h1&gt;
&lt;p&gt;Registers, rectangles, and managing windows in Emacs are powerful features that are made easier to use with Casual. If you haven’t explored them, consider trying them out. I think you’ll be pleasantly surprised by what they offer and over time will consider them essential to your Emacs experience.&lt;/p&gt;</content><category term="misc"/><category term="emacs"/><category term="casual"/></entry></feed>