<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>yakshaving on Karthinks</title>
    <link>https://karthinks.com/tags/yakshaving/</link>
    <description>Recent content in yakshaving on Karthinks</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>Karthik Chikmagalur</copyright>
    <lastBuildDate>Wed, 25 Dec 2024 22:11:00 -0800</lastBuildDate><atom:link href="https://karthinks.com/tags/yakshaving/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>Fringe Matters: Finding the Right Difference</title>
      <link>https://karthinks.com/software/fringe-matters-finding-the-right-difference/</link>
      <pubDate>Wed, 25 Dec 2024 22:11:00 -0800</pubDate>
      
      <guid>https://karthinks.com/software/fringe-matters-finding-the-right-difference/</guid>
      <description>&lt;p&gt;Continuing my avocation of writing to increasingly niche audiences, today we have a matter at the intersection of several small Venn bubbles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the group of Emacs users who code in Emacs,&lt;/li&gt;
&lt;li&gt;who use Git (or version control) everywhere,&lt;/li&gt;
&lt;li&gt;who work using offshoot or feature branches,&lt;/li&gt;
&lt;li&gt;while using the diff-hl package to visually track changes in their buffers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As minutiae go, this one is quite &lt;em&gt;minute&lt;/em&gt;, a real fringe matter.  It&amp;rsquo;s also not a paen to Emacs&amp;rsquo; extensibility or composability, because as much as I enjoy beating that drum the feature we&amp;rsquo;re looking for is actually in plain sight for once.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s just really neat though, so I&amp;rsquo;m going to describe it to you.  You&amp;rsquo;re here now.  Settle in.&lt;/p&gt;
&lt;h2 id=&#34;rise-and-shine-dr-dot-diffman-dot-rise-and-shine-dot&#34;&gt;Rise and shine, Dr. Diffman.  Rise and shine.&lt;/h2&gt;
&lt;p&gt;If you load a file that&amp;rsquo;s tracked via version control into your editor, most modern text or code editors will indicate in the buffer the bits that have been modified since the last commit, i.e. the last set of registered changes.  Here&amp;rsquo;s the &lt;a href=&#34;https://zed.dev&#34;&gt;Zed editor&lt;/a&gt; showing this via yellow/red marks in the fringe to the left of the text:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/zed-diff-hl.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;In Emacs this is provided by Dmitry Gutov&amp;rsquo;s &lt;a href=&#34;https://github.com/dgutov/diff-hl&#34;&gt;diff-hl&lt;/a&gt; or Shohei Yoshida&amp;rsquo;s  &lt;a href=&#34;https://github.com/emacsorphanage/git-gutter&#34;&gt;git-gutter&lt;/a&gt; packages, with the former pictured here:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/emacs-diff-hl.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This inline-indication business usually goes &lt;em&gt;much&lt;/em&gt; further, with editors annotating lines with when they were last changed, or whose fault it was.  My relatively tiny code or prose projects with 2-4 participants (at most) have little need for these fancier features.  Emacs makes it easy enough to generate them when required anyway
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
&lt;code&gt;vc-region-history&lt;/code&gt; (&lt;code&gt;C-x v h&lt;/code&gt;) and &lt;code&gt;vc-annotate&lt;/code&gt; (&lt;code&gt;C-x v g&lt;/code&gt;), respectively &amp;ndash; no Magit required.
&lt;/small&gt;&lt;/span&gt;
.&lt;/p&gt;
&lt;p&gt;But diff-hl is mighty handy.  Being able to identify changed regions at a glance is good, but you can also navigate and act on them.  Jump between hunks with one key, see changes inline, mark or revert hunks and more:&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://i.imgur.com/6ixIlZe.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/emacs-diff-hl-demo.mp4&#34;&gt;[VIDEO: diff-hl demo]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;The keys being pressed are indicated in the header.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;diff-hl-mode&lt;/code&gt; enabled in the buffer,&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;diff-hl-next-hunk&lt;/code&gt; (&lt;code&gt;C-x v n&lt;/code&gt;).  This moves the cursor to the next hunk,&lt;/li&gt;
&lt;li&gt;and it activates a &lt;a href=&#34;https://karthinks.com/software/it-bears-repeating/&#34;&gt;repeat-map&lt;/a&gt;, making subsequent diff-hl commands accessible with just &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt; and so on.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;*&lt;/code&gt; (shortened from &lt;code&gt;C-x v *&lt;/code&gt; by &lt;code&gt;repeat-mode&lt;/code&gt;) to show inline diffs of changed hunks.&lt;/li&gt;
&lt;li&gt;After navigating some more, press &lt;code&gt;SPC&lt;/code&gt; (shortened from &lt;code&gt;C-x v SPC&lt;/code&gt; by &lt;code&gt;repeat-mode&lt;/code&gt;) to mark a hunk.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id=&#34;the-right-diff-in-the-wrong-place-dot-dot-dot&#34;&gt;The right diff in the wrong place&amp;hellip;&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s only one problem: when working on a branch with many commits, diff-hl tracks changes relative to the &lt;code&gt;HEAD&lt;/code&gt; of the branch.  This is almost never what I want when I&amp;rsquo;m working on a feature off in a different branch.  Representing each commit as a sphere, here&amp;rsquo;s what I mean:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/diff-hl-default-revision-tree.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;At this stage, the change from &lt;code&gt;feature&lt;/code&gt; / &lt;code&gt;HEAD&lt;/code&gt; to the worktree is at best an incomplete picture.  Unless looking for something very specific, it doesn&amp;rsquo;t help to highlight worktree changes against earlier commits on &lt;code&gt;feature&lt;/code&gt; either.  The previous commits in this branch are temporary checkpoints in an experiment, and don&amp;rsquo;t necessarily represent atomic, self-contained or meaningful changes &amp;ndash; hence the jumble of colors in each commit in the figure.  What I find actually helpful is to compare the contents of the buffer to the state of the &lt;em&gt;main branch&lt;/em&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/diff-hl-customized-revision-tree.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is, of course, readily accessible via Magit or VC via a couple of keystrokes.  Either one can produce pleasingly formatted diff buffers showing the right changes for any range.  But as mentioned above, being able to have the right changes indicated in the work buffer is only one of the advantages.  With diff-hl and the right range of changes indicated, you can jump between them, mark them, revert them and more.&lt;/p&gt;
&lt;p&gt;Recreating the commits in &lt;code&gt;feature&lt;/code&gt; to encode atomic &amp;ndash; or at least limited &amp;ndash; changes is on the docket, but for later.  This involves &amp;ldquo;unscrambling&amp;rdquo; the commits into uniformly colored spheres, often via an interactive rebase, or just selective git-resets:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/diff-hl-cleanup-commits.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Usually the true &amp;ldquo;shape&amp;rdquo; of the changes can only be limned at the end of the &lt;code&gt;feature&lt;/code&gt; experiment, at which point a &amp;ldquo;logical&amp;rdquo; history can be forged before merging into the main branch using your preferred strategy
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Unless your preferred strategy is to &lt;em&gt;squash&lt;/em&gt; all the carefully recreated, atomic commits into a giant merge commit.  Then your preferred strategy is wrong.
&lt;/small&gt;&lt;/span&gt;
.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/diff-hl-merge-strategy.png&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;dot-dot-dot-can-make-all-the-difference-in-the-world-dot&#34;&gt;&amp;hellip;can make all the difference in the world.&lt;/h2&gt;
&lt;p&gt;As it turns out diff-hl understands this problem to a limited extent.  It provides a secondary minor-mode, &lt;code&gt;diff-hl-amend-mode&lt;/code&gt;, that shows the change markers with respect to &lt;code&gt;HEAD^&lt;/code&gt;, the parent of &lt;code&gt;HEAD&lt;/code&gt;.  This is typically what you want when your changes are intended to amend the latest commit instead of creating a new one.  While it&amp;rsquo;s not what we&amp;rsquo;re looking for, it&amp;rsquo;s a good starting point.&lt;/p&gt;
&lt;p&gt;But the mechanism is simple enough.  In this pseudo Elisp block:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;show-changes-between&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;from-commit&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;current-buffer-state&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;we&amp;rsquo;d like a way to set &lt;code&gt;from-commit&lt;/code&gt;, but just for this buffer or project.  If you use &lt;code&gt;diff-hl-amend-mode&lt;/code&gt;, &lt;code&gt;from-commit&lt;/code&gt; would be &lt;code&gt;HEAD^&lt;/code&gt;.  If we can set it to &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;master^&lt;/code&gt; (or &lt;code&gt;main&lt;/code&gt;), we&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;And set it we can.  &lt;code&gt;from-commit&lt;/code&gt; is actually a single global variable conveniently exposed by diff-hl: &lt;code&gt;diff-hl-reference-revision&lt;/code&gt;.  We can deal with the globality by making it buffer local.  And that&amp;rsquo;s it as far as the Elisp hacking goes &amp;ndash; no hooks or advice needed today.&lt;/p&gt;
&lt;h2 id=&#34;not-that-i-wish-to-imply-you-have-been-sleeping-on-the-margins-dot&#34;&gt;Not that I wish to imply you have been sleeping on the margins.&lt;/h2&gt;
&lt;p&gt;Only there&amp;rsquo;s still the matter of the interface.  The absolute spartan way of using this option would be to run &lt;code&gt;M-x eval-expression&lt;/code&gt; (&lt;code&gt;M-:&lt;/code&gt;) and type in&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;diff-hl-reference-revision&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;master&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On later uses, you can search the minibuffer history for this code via &lt;code&gt;minibuffer-complete-history&lt;/code&gt; (&lt;code&gt;M-r&lt;/code&gt;).  After a few weeks of this, the mild frustration mounts until it crosses a threshold: &lt;em&gt;I should really put this somewhere more convenient&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The logical next step is to define a command that does this.  diff-hl actually includes one
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
It&amp;rsquo;s &lt;code&gt;diff-hl-set-reference-rev&lt;/code&gt;
&lt;/small&gt;&lt;/span&gt;
, but that sets it globally, across Emacs.  So we sigh and grow our configuration files a little bit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/diff-hl-set-reference&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Set the reference revision for showing diff-hl changes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;Do so buffer-locally.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;setq-local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#963&#34;&gt;diff-hl-reference-revision&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;read-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Set reference revision (buffer %s): &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;buffer-name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;diff-hl-update&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dust your hands, the problem&amp;rsquo;s solved.  &lt;code&gt;M-x my/diff-hl-set-reference&lt;/code&gt; works pleasingly for a few weeks, especially since the minibuffer completion system floats this up with frequent usage
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
You do use &lt;code&gt;savehist-mode&lt;/code&gt; or &lt;code&gt;prescient&lt;/code&gt;, right?
&lt;/small&gt;&lt;/span&gt;
for easy access.&lt;/p&gt;
&lt;p&gt;But eventually two further needs appear:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I use this so often that I need it on a key, dammit.&lt;/li&gt;
&lt;li&gt;Can&amp;rsquo;t I just set this across my project instead of in every buffer?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Needs 1 and 2 obviate each other somewhat, in that either one makes it less necessary to call the &lt;code&gt;-set-reference&lt;/code&gt; command via &lt;code&gt;M-x&lt;/code&gt;.  But let&amp;rsquo;s address them separately anyway.&lt;/p&gt;
&lt;h3 id=&#34;all-the-effort-in-the-world-would-have-gone-to-waste-until-dot-dot-dot&#34;&gt;All the effort in the world would have gone to waste until&amp;hellip;&lt;/h3&gt;
&lt;p&gt;Setting up a keybind is easy if we can find room for it.  And then if we can remember it.  Emacs keymaps are crowded spaces.  On more than one occasion I&amp;rsquo;ve opened up my init file intending to add a handy keybinding for a useful command, only to discover that I already did months ago&amp;hellip; and then forgot it was available.&lt;/p&gt;
&lt;p&gt;To some extent you can mitigate this effect by placing it logically with the other diff-hl commands, which are conveniently grouped together into &lt;code&gt;diff-hl-command-map&lt;/code&gt;.  So assuming you use &lt;em&gt;any&lt;/em&gt; diff-hl commands, this one should show up in &lt;code&gt;which-key&lt;/code&gt; or your keymap prompter of choice.&lt;/p&gt;
&lt;p&gt;But in my case even this is a lost cause.  I already combine &lt;code&gt;vc-prefix-map&lt;/code&gt;, used by Emacs for version control actions, with &lt;code&gt;diff-hl-command-map&lt;/code&gt; under the &lt;code&gt;C-x v&lt;/code&gt; prefix because their functions are related.  So &lt;code&gt;C-x v&lt;/code&gt; is quite a busy junction.  Here&amp;rsquo;s which-key doing its best to show me what&amp;rsquo;s available:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/vc-prefix-map-preview.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The solution is to place it where I turn on/off &lt;code&gt;diff-hl-mode&lt;/code&gt; in the first place: in a catchall transient menu I use to access all minor-modes I need in Emacs buffers
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
A good chunk of this menu deals with settings that make no sense for most Emacs users &amp;ndash; for example, a switch to toggle requiring sentence ends to be single/double spaced, adjust line-spacing on the fly, or switch between different sets of &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Completion-in-Buffers.html&#34;&gt;CAPFs&lt;/a&gt;.
&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/toggle-modes-transient.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Calling the diff-hl option from this menu with a prefix-arg now (essentially) runs the above function, allowing me to set the reference revision before turning on the mode (if required).&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/diff-hl-rev-comparison.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Here&amp;rsquo;s a demo combining this with a few other nifty diff-hl commands and &lt;a href=&#34;https://karthinks.com/software/it-bears-repeating/&#34;&gt;repeat-mode&lt;/a&gt;:&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://i.imgur.com/kFPo8BW.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/diff-hl-toggle-modes-demo.mp4&#34;&gt;[VIDEO: Toggling diff-hl reference revision]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;The keys being pressed are indicated at the top.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Begin in a buffer in some feature branch that is some &amp;ldquo;distance&amp;rdquo; away from &lt;code&gt;master&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use diff-hl commands to navigate to hunks. diff-hl is currently showing buffer changes in the working tree against &lt;code&gt;HEAD&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;diff-hl-show-hunk&lt;/code&gt; (&lt;code&gt;C-x v *&lt;/code&gt;) to see the diffs for individual hunks inline.&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;toggle-modes&lt;/code&gt; transient mentioned above.&lt;/li&gt;
&lt;li&gt;Choose the &lt;code&gt;g&lt;/code&gt; option with a prefix-arg (&lt;code&gt;C-u&lt;/code&gt;).  This causes the reference revision (the &lt;code&gt;from-commit&lt;/code&gt; we want) to be read from the minibuffer.  Ask to see changes from &lt;code&gt;master&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;diff-hl updates to mark changes from &lt;code&gt;master&lt;/code&gt;.  As you might expect, there are more changes &amp;ndash; everything that&amp;rsquo;s changed since &lt;code&gt;master&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Navigate through the changes again with diff-hl commands.&lt;/li&gt;
&lt;li&gt;Pick the &lt;code&gt;toggle-modes&lt;/code&gt; transient menu option again, this time setting the reference revision to &lt;code&gt;HEAD&lt;/code&gt;&amp;rsquo;s grandparent, &lt;code&gt;HEAD^^&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;diff-hl updates the changes again.  As you might expect, there are fewer changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Here&amp;rsquo;s the actual function that &lt;code&gt;g&lt;/code&gt; in the &lt;code&gt;toggle-modes&lt;/code&gt; menu is bound to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Toggle &lt;/span&gt;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;`diff-hl-mode&amp;#39;&lt;/span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;With prefix ARG ensure &lt;/span&gt;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;`diff-hl-mode&amp;#39;&lt;/span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt; and set revision to compare
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;against.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;P&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;diff-hl-mode&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;toggle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;read-string&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Reference revision for diff-hl: &amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;diff-hl-reference-revision&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;diff-hl-mode&lt;/span&gt;) (&lt;span style=&#34;color:#963&#34;&gt;diff-hl-update&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Showing changes against %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;dot-dot-dot-well-let-s-just-say-your-hour-has-come-again-dot&#34;&gt;&amp;hellip;well, let&amp;rsquo;s just say your hour has come again.&lt;/h3&gt;
&lt;p&gt;As you might expect, the way to apply diff-hl&amp;rsquo;s reference revision setting to all buffers in a project is to use a &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html&#34;&gt;directory-local variable&lt;/a&gt;.  In most cases, setting it once per project (or git-worktree, in my case) is all you need.&lt;/p&gt;
&lt;p&gt;This approach requires a little forethought but no moment-to-moment busywork: Run &lt;code&gt;M-x add-dir-local-variable&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;with a major-mode choice of &lt;code&gt;nil&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;and setting the variable &lt;code&gt;diff-hl-reference-revision&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;to &lt;code&gt;&amp;quot;master&amp;quot;&lt;/code&gt; .&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This produces the following &lt;code&gt;.dir-locals.el&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;;; Directory Local Variables            -*- no-byte-compile: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;;; For more information see (info &amp;#34;(emacs) Directory Variables&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;diff-hl-reference-revision&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;master&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Typically you would want to chuck this file into version control as well &amp;ndash; but in this case that may be something you want to consider carefully!&lt;/p&gt;
&lt;h2 id=&#34;so-wake-up-dr-dot-diffman-dot-wake-up-and-mark-the-fringes-dot&#34;&gt;So, wake up, Dr. Diffman.  Wake up and mark the fringes.&lt;/h2&gt;
&lt;p&gt;Before I thought to adapt diff-hl to how I worked, I was coding in feature branches in a strange way.  I would make a bunch of work-in-progress checkpoint commits and store them on a remote, then soft-reset the branch to the original branch point so I could see indicators for all changed regions in buffers, jump between them with &lt;code&gt;diff-hl-next-hunk&lt;/code&gt; and so on.&lt;/p&gt;
&lt;p&gt;It took a while
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
a &amp;ldquo;while&amp;rdquo; is code for &lt;em&gt;years&lt;/em&gt;
&lt;/small&gt;&lt;/span&gt;
to consider that it didn&amp;rsquo;t have to be this way.  This isn&amp;rsquo;t an adjustment that requires Emacs&amp;rsquo; much vaunted flexibility &amp;ndash; you can probably do this in any editor that provides the diff-hl feature.  I just never thought to do it, and worked around the tool instead of making the tool work for me.  Well that&amp;rsquo;s sorted.&lt;/p&gt;
&lt;p&gt;There is no other upshot.  This yak has been shaved.  You&amp;rsquo;re free now, go mark some fringes.&lt;/p&gt;
</description>
    </item><item>
      <title>For Your Reference: RefTeX in Org Mode</title>
      <link>https://karthinks.com/software/reftex-in-org-mode/</link>
      <pubDate>Fri, 16 Feb 2024 04:48:00 -0800</pubDate>
      
      <guid>https://karthinks.com/software/reftex-in-org-mode/</guid>
      <description>&lt;div class=&#34;subtitle&#34;&gt;
&lt;p&gt;TL;DR: &amp;ldquo;We have X-references at home&amp;rdquo;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Cross-references in Org mode are not as well developed as its (relatively) new citation system.  Org&amp;rsquo;s built-in linking system is fairly comprehensive and exports to all formats well enough.  But if you&amp;rsquo;re coming to Org from LaTeX, you might prefer something more familiar and oriented towards the label/references mental mapping than the anchor/link system.  Over the decades, I drifted into Org mode from writing LaTeX, and brought along RefTeX support.  &lt;em&gt;Sort of&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In the past few months I received a number of questions about my usage of LaTeX-style cross-references in Org, so here&amp;rsquo;s a short explanation and, uh, reference.&lt;/p&gt;
&lt;h2 id=&#34;just-give-me-the-code&#34;&gt;Just give me the code&lt;/h2&gt;
&lt;p&gt;One half of my long-winded Emacs articles begin or end with a call to action:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;hellip;and it&amp;rsquo;s a package, and here&amp;rsquo;s a link, it&amp;rsquo;s on MELPA, try it out.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is not one of those.  There &lt;em&gt;is&lt;/em&gt; a package, and more code besides.  But this is stuff extracted from my Emacs init file, which is a cross between a palimpsest, a crime scene and a dry-erase board that don&amp;rsquo;t erase no more.  Use at your own peril, or better yet, reuse these ideas to make something coherent and plug-and-play:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/karthink/consult-reftex&#34;&gt;&lt;code&gt;consult-reftex&lt;/code&gt;&lt;/a&gt;: A better interface to RefTeX, with &lt;a href=&#34;https://github.com/minad/consult&#34;&gt;Consult&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/karthink/reftex-xref&#34;&gt;&lt;code&gt;reftex-xref&lt;/code&gt;&lt;/a&gt;: xref and eldoc support for RefTeX&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gist.github.com/karthink/d2419098c9312e3bf2c63b052464ef5f&#34;&gt;Some configuration&lt;/a&gt; to turn on these enhancements.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Demos and explanations below.&lt;/p&gt;
&lt;h2 id=&#34;background-org-link-org-ref-and-oxr&#34;&gt;Background: &lt;code&gt;org-link&lt;/code&gt;, &lt;code&gt;org-ref&lt;/code&gt; and &lt;code&gt;oxr&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;There are other solutions &amp;ndash; actual solutions &amp;ndash; for cross-references in Org mode.  Org&amp;rsquo;s built-in linking system can be repurposed for this, and it will export to all document formats.  Bruce D&amp;rsquo;Arcus&amp;rsquo; &lt;a href=&#34;https://github.com/bdarcus/oxr&#34;&gt;&lt;code&gt;oxr&lt;/code&gt;&lt;/a&gt; is a proof of concept of a cross-referencing system built on top of Org&amp;rsquo;s links.  For LaTeX exports, there&amp;rsquo;s John Kitchin&amp;rsquo;s frighteningly full-featured &lt;a href=&#34;https://github.com/jkitchin/org-ref/&#34;&gt;&lt;code&gt;org-ref&lt;/code&gt;&lt;/a&gt;, with simple and elegant &lt;a href=&#34;https://github.com/jkitchin/org-ref/blob/master/org-ref.org#ref-links-ref-links&#34;&gt;cross-referencing syntax&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of these is probably what you want.&lt;/p&gt;
&lt;p&gt;One of these is probably what I would have used if I had given my slow transition from LaTeX to Org any active thought.  Instead I just continued to use RefTeX.&lt;/p&gt;
&lt;h2 id=&#34;what-s-a-reftex&#34;&gt;What&amp;rsquo;s a RefTeX?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.gnu.org/software/auctex/reftex.html&#34;&gt;RefTeX&lt;/a&gt; is an Emacs minor mode with distinct support for &lt;code&gt;\ref&lt;/code&gt;, &lt;code&gt;\label&lt;/code&gt;, &lt;code&gt;\cite&lt;/code&gt;, and &lt;code&gt;\index&lt;/code&gt; commands in (multi-file) LaTeX documents.  It is included with Emacs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The official description undersells it.  RefTeX is extensive: it supports cross-references and citations, semi-automatic label creation, reference tracking and updates, indexes, multi-file documents, references to external documents, a dynamic table of contents and more, and provides the means to do everything that we&amp;rsquo;re about to do more clumsily below.&lt;/p&gt;
&lt;p&gt;In a happy coincidence, RefTeX works without a hitch in Org documents&amp;hellip; to a point
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
It gets dicey with multi-file Org documents.
&lt;/small&gt;&lt;/span&gt;
.  This is an oft-ignored advantage of regexp-based, structure-agnostic parsing &amp;ndash; once you iron out the many, many edge cases over a few years, it tends to work pretty much everywhere.  RefTeX&amp;rsquo;s Org mode &amp;ldquo;support&amp;rdquo; is good enough for my purposes, and having it work the same in Org and LaTeX documents is a bonus.&lt;/p&gt;
&lt;p&gt;It even integrates with &lt;a href=&#34;https://karthinks.com/software/latex-input-for-impatient-scholars/#step-2-cdlatex&#34;&gt;&lt;code&gt;cdlatex&lt;/code&gt; and &lt;code&gt;org-cdlatex&lt;/code&gt;&lt;/a&gt;, with automatic label insertion when inserting environments.  (This is not a coincidence.)&lt;/p&gt;
&lt;p&gt;There are two limitations.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Obviously, LaTeX style cross-references only work with LaTeX exports.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The other issue with RefTeX, and the main focus of this write-up, is the UI.  It&amp;rsquo;s very&amp;hellip; 90s, let&amp;rsquo;s say.  Better previewing, faster navigation, integration into the modern Emacs API, some DWIM behavior &amp;ndash; these are all achievable with a few band-aids.  The result is a patchwork, but that&amp;rsquo;s most things Emacs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Finally, there&amp;rsquo;s one other deep connection between RefTeX, CDLaTeX and Org mode.  It&amp;rsquo;s two words.  Take your guesses, or open up &lt;code&gt;reftex.el&lt;/code&gt; and read the header!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;sprucing-up-the-reftex-experience&#34;&gt;Sprucing up the RefTeX experience&lt;/h2&gt;
&lt;p&gt;A reassertion: RefTeX already works reasonably well in Org mode, and you can work around edge cases if you encounter them.  The write-up until now was thus mainly a PSA.  What follows is minor improvements to the UI and the general experience of Org when using RefTeX.&lt;/p&gt;
&lt;h3 id=&#34;insert-references-with-consult-reftex&#34;&gt;Insert references with &lt;code&gt;consult-reftex&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned above, RefTeX is a kitchen sink library &amp;ndash; it provides everything you need to manage references, including a multi-step reference insertion menu.  But this process leaves a bit to be desired:&lt;/p&gt;
&lt;img src=&#34;https://karthinks.com/img/reftex-insert-reference.png&#34; style=&#34;box-shadow:0px -5px 5px #421D5D;margin-top:14px;margin-bottom:14px;border-radius:8px;&#34;&gt;
&lt;p&gt;I wrote &lt;a href=&#34;https://github.com/karthink/consult-reftex&#34;&gt;consult-reftex&lt;/a&gt; a while ago to provide a better interface for reference creation:
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
The LaTeX previews in the buffer, in &lt;code&gt;consult-reftex&lt;/code&gt;&amp;rsquo;s previews and elsewhere are from Org&amp;rsquo;s &lt;a href=&#34;https://www.youtube.com/watch?v=n-AfvuV-bYo&#34;&gt;upcoming LaTeX preview system overhaul&lt;/a&gt;.
&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/consult-reftex-insert-demo-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/consult-reftex-insert-demo-small.mp4&#34;&gt;[VIDEO: consult-reftex label insertion]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;ul&gt;
&lt;li&gt;Call &lt;code&gt;consult-reftex-insert-reference&lt;/code&gt; to insert a reference at point.  I&amp;rsquo;ve bound it to a snippet, so I invoke it by typing in &lt;code&gt;ref&lt;/code&gt; and pressing &lt;code&gt;TAB&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;This command presents a completing-read interface where you can narrow the candidates to just equations, figures, sections etc.  Candidate objects are previewed above the minibuffer.&lt;/li&gt;
&lt;li&gt;You can choose how to insert this reference (as a &lt;code&gt;\ref&lt;/code&gt;, &lt;code&gt;\eqref&lt;/code&gt;, &lt;code&gt;\cref&lt;/code&gt; etc).&lt;/li&gt;
&lt;li&gt;Repeat this a couple of times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;I wrote it for LaTeX documents, but thanks to RefTeX&amp;rsquo;s flexibility it works all the same in Org mode.&lt;/p&gt;
&lt;h4 id=&#34;looking-up-references-consult-reftex--again&#34;&gt;Looking up references: &lt;code&gt;consult-reftex&lt;/code&gt; (again)&lt;/h4&gt;
&lt;p&gt;The preview interface for &lt;code&gt;consult-reftex&lt;/code&gt; serves a second purpose &amp;ndash; you can use it as a listing of the equations in your document (by label), and act on labels via Embark.&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/consult-reftex-lookup-demo-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/consult-reftex-lookup-demo-small.mp4&#34;&gt;[VIDEO: consult-reftex to look up labels]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;Same usage pattern, different focus from the above&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cycle through labeled objects (equations/sections etc) in the document&lt;/li&gt;
&lt;li&gt;Invoke &lt;a href=&#34;https://karthinks.com/software/fifteen-ways-to-use-embark/&#34;&gt;Embark&lt;/a&gt; on a candidate to access additional RefTeX actions: change the label (and all references to it), reparse the file, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;I don&amp;rsquo;t do this when writing, but it&amp;rsquo;s occasionally useful when reviewing work.&lt;/p&gt;
&lt;h3 id=&#34;fontify-dot-dot-dot&#34;&gt;Fontify&amp;hellip;&lt;/h3&gt;
&lt;p&gt;RefTeX labels in Org are plain by default,&lt;/p&gt;
&lt;img src=&#34;https://karthinks.com/img/reftex-hack-no-font-lock.png&#34; style=&#34;box-shadow:0px -5px 5px #421D5D;margin-top:14px;margin-bottom:10px;border-radius:8px;&#34;&gt;
&lt;p&gt;so a little syntax highlighting goes a long way:&lt;/p&gt;
&lt;img src=&#34;https://karthinks.com/img/reftex-hack-with-font-lock.png&#34; style=&#34;box-shadow:0px -5px 5px #421D5D;margin-top:14px;margin-bottom:10px;border-radius:8px;&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;font-lock-add-keywords&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\\(\\(?:\\\\\\(?:label\\|ref\\|eqref\\)\\)\\){\\(.+?\\)}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;font-lock-keyword-face&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;font-lock-constant-face&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I didn&amp;rsquo;t bother making a comprehensive regexp for font-locking here, you might want to thrown in more keywords.&lt;/p&gt;
&lt;p&gt;This is more than eye-candy: a little further below, we use the faces we specify here as anchors for jumping between references.  If you use different faces for the keywords, you&amp;rsquo;ll need to update the &lt;a href=&#34;#org-target--reftex-navigation-code&#34;&gt;navigation code below&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;dot-dot-dot-and-prettify-tex-fold-mode&#34;&gt;&amp;hellip;and Prettify: &lt;code&gt;TeX-fold-mode&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;TeX-fold-mode&lt;/code&gt;, provided with &lt;a href=&#34;https://www.gnu.org/software/auctex&#34;&gt;AucTeX&lt;/a&gt;, is useful for shortening long references by placing overlays over them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;:&lt;/p&gt;
&lt;img src=&#34;https://karthinks.com/img/TeX-fold-before.png&#34; style=&#34;box-shadow:0px -5px 5px #421D5D;margin-top:14px;margin-bottom:10px;border-radius:8px;&#34;&gt;
&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt; (with the mouse over one of the references):&lt;/p&gt;
&lt;img src=&#34;https://karthinks.com/img/TeX-fold-after.png&#34; style=&#34;box-shadow:0px -5px 5px #421D5D;margin-top:14px;margin-bottom:10px;border-radius:8px;&#34;&gt;
&lt;p&gt;The effect is purely visual, moving the cursor into the overlay reveals the full reference:&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/TeX-fold-enable-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/TeX-fold-enable-small.mp4&#34;&gt;[VIDEO TeX-fold-mode]&lt;/a&gt;&lt;/video&gt;
&lt;p&gt;This requires turning on &lt;code&gt;TeX-fold-mode&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://karthinks.com/software/latex-input-for-impatient-scholars/#the-rest-of-auctex&#34;&gt;It can fold most LaTeX constructs&lt;/a&gt;, including environments, sections, comments and even individual math symbols and operators.  We&amp;rsquo;re only interested in folding references and labels here, though, so we can specify this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;TeX-fold-type-list&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;macro&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can make this Org mode-specific with a hook if you want to fold more constructs in LaTeX documents.&lt;/p&gt;
&lt;p&gt;Optional: we can tweak the overlay styling for labels and refs as well:&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img src=&#34;https://karthinks.com/img/lisp-icon.png&#34; class=detail-icon&gt;&lt;/span&gt; Reference/Label folding style: code&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; Faces&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;set-face-attribute&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;TeX-fold-folded-face&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:foreground&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:inherit&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;shadow&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; Custom folded display for labels and refs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/TeX-fold-ref&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;m&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;string-match&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;^\\([^:]+:\\)\\(.*\\)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#963&#34;&gt;cat&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;match-string&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;) &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;match-string&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;) &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt;) &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;13&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;6&lt;/span&gt;) &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;-6&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cat&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;shadow&lt;/span&gt;) &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/TeX-fold-label&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;texts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;texts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#963&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;string-match&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;^\\([^:]+:\\)\\(.*\\)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#963&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cat&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;match-string&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;) &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#963&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;match-string&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;) &lt;span style=&#34;color:#963&#34;&gt;text&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#963&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cat&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;shadow&lt;/span&gt;) &lt;span style=&#34;color:#963&#34;&gt;ref&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#963&#34;&gt;into&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;labels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#963&#34;&gt;finally&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;mapconcat&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;identity&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;labels&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;setq-default&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;TeX-fold-macro-spec-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#963&#34;&gt;my/TeX-fold-label&lt;/span&gt; (&lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;cite&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;my/TeX-fold-label&lt;/span&gt; (&lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;label&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;my/TeX-fold-ref&lt;/span&gt; (&lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;ref&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;pageref&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;eqref&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;footref&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Lastly, you might want to turn folding on in Org buffers.  &lt;code&gt;TeX-fold&lt;/code&gt; uses the &lt;code&gt;C-c C-o&lt;/code&gt; key as a prefix, watch out for key conflicts with Org!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-mode-hook&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;TeX-fold-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;moving-around-references-big-ol-pile-o-hacks&#34;&gt;Moving around references: big ol&amp;rsquo; pile o&amp;rsquo;hacks&lt;/h3&gt;
&lt;p&gt;This is mostly to avoid having to use the mouse &amp;ndash; Isearch or Avy aren&amp;rsquo;t very useful if the reference is folded.  That said, its main advantage is not that it moves the cursor (for editing), but that it enables other actions we might want to take immediately after, such as jumping to the definition of a label &lt;a href=&#34;#jumping-to-definition-xref-support-more-hacks&#34;&gt;with &lt;code&gt;xref&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/reftex-hack-jumping-around-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/reftex-hack-jumping-around-small.mp4&#34;&gt;[VIDEO: Jumping around reftex references]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;I jump to the next reference with &lt;code&gt;M-g r&lt;/code&gt;, and then jump forward and backward across references, labels and citations with &lt;code&gt;M-g r&lt;/code&gt; and &lt;code&gt;M-g R&lt;/code&gt;.  Actually, after invoking it once I jump forward and back with just &lt;code&gt;r&lt;/code&gt; and &lt;code&gt;R&lt;/code&gt;, thanks to &lt;code&gt;repeat-mode&lt;/code&gt;.  The code is below.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;We want several things to happen when we jump to a reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Org should open up folded/invisible text if the references is in a hidden region,&lt;/li&gt;
&lt;li&gt;Any TeX-fold overlay at the reference should be cleared,&lt;/li&gt;
&lt;li&gt;and if we jumped &lt;em&gt;from&lt;/em&gt; a reference it should be folded again by TeX-fold.&lt;/li&gt;
&lt;li&gt;If a preview is available (via Eldoc, &lt;a href=&#34;#auto-preview-reference-at-point-eldoc-support&#34;&gt;see below&lt;/a&gt;), it should be activated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The code for this is below.  It&amp;rsquo;s not pretty.&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;org-target&#34; id=&#34;org-target--reftex-navigation-code&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img src=&#34;https://karthinks.com/img/lisp-icon.png&#34; class=detail-icon&gt;&lt;/span&gt; Jumping by reference: code&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/next-reference-or-label&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;_arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;prop&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;pcase-let&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          ((&lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-char-property-and-overlay&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;TeX-fold-type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;TeX-fold-hide-item&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;save-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prop&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;text-property-search-forward&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;memq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;font-lock-constant-face&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;org-cite&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;progn&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;prop-match-beginning&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prop&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;derived-mode-p&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-mode&lt;/span&gt;) (&lt;span style=&#34;color:#963&#34;&gt;org-invisible-p&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#963&#34;&gt;org-fold-show-context&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;link-search&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;eldoc-mode&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;eldoc--invoke-strategy&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;pcase-let&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     ((&lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-char-property-and-overlay&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;TeX-fold-type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;TeX-fold-show-item&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;No more references/labels.&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/previous-reference-or-label&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;_arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;p&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#007020&#34;&gt;save-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;text-property-search-backward&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;memq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;font-lock-constant-face&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;org-cite&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#963&#34;&gt;TeX-fold-folded-face&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#007020&#34;&gt;pcase-let&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ((&lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-char-property-and-overlay&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;TeX-fold-type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;TeX-fold-hide-item&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;p&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;goto-char&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;derived-mode-p&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-mode&lt;/span&gt;) (&lt;span style=&#34;color:#963&#34;&gt;org-invisible-p&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#963&#34;&gt;org-fold-show-context&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;link-search&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;eldoc-mode&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;eldoc--invoke-strategy&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#007020&#34;&gt;pcase-let&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ((&lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-char-property-and-overlay&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;TeX-fold-type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;TeX-fold-show-item&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While we&amp;rsquo;re at it, we might as well make this command repeatable, so you can navigate with just &lt;code&gt;r&lt;/code&gt; and &lt;code&gt;R&lt;/code&gt; after the first jump:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;keymap-set&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;org-mode-map&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;M-g r&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;my/next-reference-or-label&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;keymap-set&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;org-mode-map&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;M-g R&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;my/previous-reference-or-label&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;defvar-keymap&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/TeX-ref-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#007020&#34;&gt;:repeat&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;my/next-reference-or-label&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;R&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;my/previous-reference-or-label&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;h3 id=&#34;jumping-to-definition-xref-support-more-hacks&#34;&gt;Jumping to definition: &lt;code&gt;xref&lt;/code&gt; support, more hacks&lt;/h3&gt;
&lt;p&gt;With the cursor at a reference, jump to the corresponding label using Emacs&amp;rsquo; standard &lt;code&gt;xref&lt;/code&gt; mechanism:&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/reftex-hack-jumping-around-and-xref-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/reftex-hack-jumping-around-and-xref-small.mp4&#34;&gt;[VIDEO: reftex-xref]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;ul&gt;
&lt;li&gt;Jump to the next reference with &lt;code&gt;M-g r&lt;/code&gt;, as before.&lt;/li&gt;
&lt;li&gt;Jump to the corresponding label with &lt;code&gt;M-.&lt;/code&gt;, Emacs&amp;rsquo; standard keybinding for &lt;code&gt;xref-find-definitions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Jump back with &lt;code&gt;M-,&lt;/code&gt;, Emacs&amp;rsquo; standard keybinding for &lt;code&gt;xref-go-back&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Repeat a couple of times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Code below.  Again, not pretty.&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;org-target&#34; id=&#34;org-target--reftex-xref-code-block&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img src=&#34;https://karthinks.com/img/lisp-icon.png&#34; class=detail-icon&gt;&lt;/span&gt; &lt;code&gt;xref&lt;/code&gt; support for RefTeX: code&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;xref&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;reftex-ref&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;xref-backend-identifier-at-point&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;_backend&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;looking-back&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\\\\\\(?:page\\|eq\\|auto\\|c\\)?ref{[-a-zA-Z0-9_*.:]*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;line-beginning-position&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		    (&lt;span style=&#34;color:#963&#34;&gt;reftex-this-word&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;-a-zA-Z0-9_*.:&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;xref-backend-definitions&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;_backend&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex&lt;/span&gt;)) &lt;span style=&#34;color:#963&#34;&gt;prompt&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbol-value&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-docstruct-symbol&lt;/span&gt;) (&lt;span style=&#34;color:#963&#34;&gt;reftex-parse-one&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;when-let*&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;docstruct&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbol-value&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-docstruct-symbol&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;assoc&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;docstruct&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;label&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;file&lt;/span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;find-buffer-visiting&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#963&#34;&gt;reftex-get-file-buffer-force&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#963&#34;&gt;file&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-keep-temporary-buffers&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;re&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-find-label-regexp-format&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;regexp-quote&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;label&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;found&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;re-search-backward&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;re&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#007020&#34;&gt;progn&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point-min&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;re-search-forward&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-find-label-regexp-format2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;regexp-quote&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;label&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;xref-make&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prompt&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;xref-make-buffer-location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             &lt;span style=&#34;color:#963&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;found&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;xref-backend-apropos&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;_backend&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex&lt;/span&gt;)) &lt;span style=&#34;color:#963&#34;&gt;pattern&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;xref-backend-definitions&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;reftex&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-xref&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Function to activate buffer-local backend.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;Add this function to &lt;/span&gt;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;`xref-backend-functions&amp;#39;&lt;/span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt; to use xref to find
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;function and variable definitions in the same buffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;This should have a low priority among xref backends.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;reftex&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; Eldoc support via xref, because why not&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-xref--display-in-eldoc&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;callback&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Display reference label location in Eldoc.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;Call CALLBACK if possible.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;cl-intersection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#963&#34;&gt;ensure-list&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-char-property&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;face&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;font-lock-keyword-face&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;font-lock-constant-face&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#963&#34;&gt;TeX-fold-unfolded-face&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;save-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;when-let*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          ((&lt;span style=&#34;color:#963&#34;&gt;inhibit-redisplay&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;_macro&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;reftex-what-macro-safe&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;key&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;reftex-this-word&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;^{}%\n\r, \t&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;item&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;xref-backend-definitions&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;reftex&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;key&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;location&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;xref-item-location&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;item&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;pos&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;xref-buffer-location-position&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;location&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;docstring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#007020&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;xref-buffer-location-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;location&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;goto-char&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;pos&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#007020&#34;&gt;pcase-let&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  ((&lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#007020&#34;&gt;condition-case&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#963&#34;&gt;LaTeX-find-matching-begin&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#007020&#34;&gt;:success&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#888&#34;&gt;;; Found \begin{}...\end{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;cons&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;color:#007020&#34;&gt;progn&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;forward-char&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    (&lt;span style=&#34;color:#963&#34;&gt;LaTeX-find-matching-end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#f00;font-weight:bold&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#888&#34;&gt;;; No \begin, find \section{} or Org heading instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;goto-char&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;pos&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;re-search-backward&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#007020&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;major-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-mode&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;^*&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\\(&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;LaTeX-outline-regexp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\\|\\`\\)&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;line-beginning-position&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;-2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;cons&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;line-beginning-position&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;line-end-position&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;buffer-substring-no-properties&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;end&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;if-let*&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;prop-and-ov&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-char-property-and-overlay&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#963&#34;&gt;xref-buffer-location-position&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;location&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#007020&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;major-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-mode&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-overlay-type&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;latex-mode&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;category&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;memq&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prop-and-ov&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;org-latex-overlay&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;preview-overlay&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prop-and-ov&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;callback&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;docstring&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;display&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                          (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;overlay-get&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;preview-image&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;docstring&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-eldoc-activate&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;eldoc-documentation-functions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;reftex-xref--display-in-eldoc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:local&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-xref-activate&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Activate reftex support using xref.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;xref-backend-functions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;reftex-xref&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:local&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;provide&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;reftex-xref&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;To turn on &lt;code&gt;xref&lt;/code&gt; support for references in Org mode:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-xref&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#007020&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;org&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;latex&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#007020&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;org-mode&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-xref-activate&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;auto-preview-reference-at-point-eldoc-support&#34;&gt;Auto-preview reference at point: &lt;code&gt;eldoc&lt;/code&gt; support&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re jumping to label definitions with &lt;code&gt;xref&lt;/code&gt; just to look at the corresponding equations, we can skip that step with previews of the referenced object.  With &lt;code&gt;eldoc-mode&lt;/code&gt;
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Eldoc is Emacs&amp;rsquo; standard and recommended way of showing contextual help.
&lt;/small&gt;&lt;/span&gt;
enabled:&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/reftex-hack-jumping-around-and-eldoc-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/reftex-hack-jumping-around-and-eldoc-small.mp4&#34;&gt;[VIDEO: reftex-eldoc]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;eldoc-mode&lt;/code&gt; enabled, move the cursor into (or jump into) a reference.&lt;/li&gt;
&lt;li&gt;This activates a preview of the relevant label, mostly equations in this example.&lt;/li&gt;
&lt;li&gt;Works for sections too, but not figures or tables (yet).&lt;/li&gt;
&lt;li&gt;Repeat a few times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Equations and figures can be pretty tall, so if you&amp;rsquo;re not using a dedicated Eldoc buffer (or &lt;a href=&#34;https://github.com/casouri/eldoc-box&#34;&gt;eldoc-box&lt;/a&gt;) you might want to change the height that the echo area can expand to.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;eldoc-echo-area-use-multiline-p&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#963&#34;&gt;max-mini-window-height&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To activate reference previews as an Eldoc documentation function, we use the helper function defined as part of &lt;a href=&#34;#org-target--reftex-xref-code-block&#34;&gt;reftex-xref above&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-xref&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#007020&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;org&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;latex&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#007020&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;org-mode&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;reftex-eldoc-activate&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;yep-reftex-dcr-exists&#34;&gt;Yep, &lt;code&gt;reftex-dcr&lt;/code&gt; exists&lt;/h2&gt;
&lt;p&gt;Earlier I mentioned that we would be clumsily recreating features RefTeX already includes.  Indeed, most of the above features, like jumping to label definitions and previewing the reference at point, are already provided in the &lt;code&gt;reftex-dcr&lt;/code&gt; library, included with RefTeX.  The problem is that it predates Emacs&amp;rsquo; &lt;code&gt;xref&lt;/code&gt; and &lt;code&gt;eldoc&lt;/code&gt; APIs (if not their libraries), and like most 90s Emacs packages it reinvents all the wheels.  This is painful on more than an aesthetic level &amp;ndash; I prefer to have one well-supported and convenient way for each semantic task.  The mental model is simpler, as are the required keyboard gymnastics.&lt;/p&gt;
&lt;p&gt;Thankfully, there&amp;rsquo;s enough of a separation between the data-parsing RefTeX backend and the UI that I was able to drive a wedge through and beat it into a more consistent shape.  Needless to say, this shape is not very robust.  Emacs makes it very easy to cobble together an 80% solution &amp;ndash; I spent much longer writing this little explainer than I did actually slapping together the code.  Due to a pies ≫ fingers situation, I&amp;rsquo;m not going to be able to get these hacks to a stage beyond &amp;ldquo;it works for me&amp;rdquo;.  The interest around this topic suggests that perhaps someone might be interested in developing the idea further and modernizing RefTeX, or working on a better cross-referencing system for Org mode.   Have at it!&lt;/p&gt;
</description>
    </item><item>
      <title>Different Strokes For Different Folks</title>
      <link>https://karthinks.com/software/different-strokes-for-different-folks/</link>
      <pubDate>Fri, 24 Nov 2023 15:15:00 -0800</pubDate>
      
      <guid>https://karthinks.com/software/different-strokes-for-different-folks/</guid>
      <description>&lt;div class=&#34;subtitle&#34;&gt;
&lt;p&gt;A modest defense of the rodent&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So, Emacs and the mouse.  This is an unexpectedly contentious topic, with discussions that end, at best, with careless dismissal.  More often they turn into arguments with folks talking past one another.&lt;/p&gt;
&lt;p&gt;The advantages of using the mouse for common actions in Emacs are immediate and obvious.  Window selection is a natural extension of basic mouse usage.  Resizing windows is a snap.  Context (right-click) menus
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
See &lt;code&gt;context-menu-mode&lt;/code&gt;.
&lt;/small&gt;&lt;/span&gt;
and drag and drop support, which improve with each new Emacs release, are very intuitive.  The mouse provides access to basic editor functions with no learning curve, and no exhortations to work through the Emacs tutorial are necessary.  Also, feature discoverability via Emacs&amp;rsquo; menu-bar is surprisingly good.&lt;/p&gt;
&lt;p&gt;Unfortunately, I have to address the rodent in the room carefully before we can talk about mitigating the many disadvantages of mouse-first interaction, since Emacs users tend to be very opinionated about this topic.  &lt;strong&gt;Ergonomics&lt;/strong&gt;, &lt;strong&gt;speed&lt;/strong&gt;, and &lt;strong&gt;efficiency&lt;/strong&gt; are three common reasons people advocate for the keyboard against the mouse for non-graphical work.  I&amp;rsquo;m not convinced any of these arguments hold water.  The first two are research-worthy topics on their own, with many quotable precedents, and beyond my ability to argue for or against convincingly just from personal experience
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Besides, anyone who&amp;rsquo;s had bouts of RSI has made up their mind already on this topic.
&lt;/small&gt;&lt;/span&gt;
.  On the matter of speed, for instance, I am obliged to include this quote because y&amp;rsquo;all are going to send me emails linking to it otherwise:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We’ve done a cool $50 million of R &amp;amp; D on the Apple Human Interface. We discovered, among other things, two pertinent facts:&lt;/p&gt;
&lt;p&gt;Test subjects consistently report that keyboarding is faster than mousing.&lt;/p&gt;
&lt;p&gt;The stopwatch consistently proves mousing is faster than keyboarding.&lt;/p&gt;
&lt;p&gt;&amp;ndash; &lt;a href=&#34;https://en.wikipedia.org/wiki/Bruce_Tognazzini&#34;&gt;Bruce Tognazzini&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So let&amp;rsquo;s pretend for the purpose of today&amp;rsquo;s discussion that we&amp;rsquo;re not concerned about the difference in editing speed one way or another.&lt;/p&gt;
&lt;p&gt;In the context of Emacs specifically, there are further disadvantages.  For example, mouse actions compose in limited ways (such as when dragging to form selections) and cannot build on each other like key sequences can with prefix keys and transient maps.  You can&amp;rsquo;t automate mouse usage with keyboard macros easily.&lt;/p&gt;
&lt;p&gt;But today we&amp;rsquo;re primarily going to address the third reason: efficiency.&lt;/p&gt;
&lt;p&gt;I find the arguments about efficiency, in the sense of poor expressivity or economy of motion, shortsighted at best.  Here are two facets of this argument, where &amp;ldquo;mouse&amp;rdquo; includes any kind of pointing device.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Economy&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Frequent context switching between the keyboard, mouse and keyboard+mouse is wasteful and causes low amounts of constant friction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Expressivity&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mouse usage has a low ceiling: it makes easy tasks trivial but involved actions impossible.  Adding buttons or widgets to the screen doesn&amp;rsquo;t scale.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;economy-and-interprogram-contexts&#34;&gt;Economy and interprogram contexts&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Economy&lt;/strong&gt; first.  I actually agree with the context switching argument, to the extent that the friction of repeated switching feels progressively more annoying.  But the conclusion &amp;ndash; it&amp;rsquo;s best to avoid the mouse to avoid context switching &amp;ndash; is shortsighted because it only applies if you&amp;rsquo;re &lt;em&gt;only ever&lt;/em&gt; in Emacs and never have to use the mouse, or conversely if you&amp;rsquo;re &lt;em&gt;never&lt;/em&gt; in a text editor and always in a mouse-driven (or keyboard+mouse driven) application like a 3D modeling tool or a big commercial IDE.  Most of us are somewhere in the middle.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m as keyboard-centric as you can reasonably get: besides Emacs, I use a tiling window manager, a &lt;a href=&#34;https://qutebrowser.org/&#34;&gt;keyboard-driven web browser&lt;/a&gt; and mostly TUI applications.  Keybindings are the topic I&amp;rsquo;ve written the most about on this website &amp;ndash; an embarrassing amount of yakshaving devoted to an inane subject.  Even so, I use the mouse frequently because it&amp;rsquo;s often the best way to select text, images and links, do graphical work, and to interact with (both simple and complex) GUI software.&lt;/p&gt;
&lt;p&gt;When working on something that involves Emacs &lt;em&gt;and&lt;/em&gt; one of these mouse driven applications, having to move over to the keyboard for the Emacs bit is exactly the friction we&amp;rsquo;d like to avoid.  The other app may not be flexible, but Emacs is!  So we don&amp;rsquo;t need to switch to the Emacs-typical both-hands-at-keyboard context.  Here are a few examples of quick interprogram interaction involving Emacs that you can easily do without moving your hand off the mouse.&lt;/p&gt;
&lt;h3 id=&#34;pasting-text-from-other-applications-into-a-new-buffer&#34;&gt;Pasting text from other applications into a new buffer&lt;/h3&gt;
&lt;p&gt;Switch to a scratch buffer+window in Emacs to paste some text:&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/strokes-drag-text.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/strokes-drag-text.mp4&#34;&gt;[VIDEO: Create a scratch buffer with strokes]&lt;/a&gt;&lt;/video&gt;
&lt;p&gt;I use a mouse gesture in Emacs to create a scratch buffer in Org mode &amp;ndash; courtesy of the &lt;a href=&#34;https://codeberg.org/emacs-weirdware/scratch&#34;&gt;scratch&lt;/a&gt; package &amp;ndash; then drag some text into it
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Incidentally, the text is a LaTeX environment that is rendered automatically via Org&amp;rsquo;s new LaTeX preview system.
&lt;/small&gt;&lt;/span&gt;
.  I then switch back to the previous buffer using another mouse gesture.&lt;/p&gt;
&lt;h3 id=&#34;git-clone-from-a-repository-url&#34;&gt;git-clone from a repository URL&lt;/h3&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/strokes-git-clone.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/strokes-git-clone.mp4&#34;&gt;[VIDEO: git-clone from repository URL]&lt;/a&gt;&lt;/video&gt;
&lt;p&gt;Middle click to paste a link from the clipboard.  (This is only for clarity, it&amp;rsquo;s unrelated to the actual action.)  Then use a mouse gesture to git-clone from that link to a prespecified directory.&lt;/p&gt;
&lt;h3 id=&#34;open-a-project-directory-in-dired-so-we-can-drag-and-drop-a-file&#34;&gt;open a project directory in dired so we can drag and drop a file&lt;/h3&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/strokes-project-dired.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/strokes-project-dired.mp4&#34;&gt;[VIDEO: project directory in dired]&lt;/a&gt;&lt;/video&gt;
&lt;p&gt;Use a mouse gesture to bring up a list of directories in the active project.  Pick one &amp;ndash; also using the mouse &amp;ndash; then drag an image file into dired before switching back.&lt;/p&gt;
&lt;h3 id=&#34;mpv-plus-live-video-transcript-in-emacs&#34;&gt;mpv + live video transcript in Emacs&lt;/h3&gt;
&lt;p&gt;Control mpv (a video player) by clicking around in a live transcript file in Emacs:&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://i.imgur.com/DQ9cmED.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://i.imgur.com/DQ9cmED.mp4&#34;&gt;[VIDEO: live, clickable transcripts with elfeed-tube]&lt;/a&gt;&lt;/video&gt;
&lt;p&gt;No mouse gestures here &amp;ndash; the clickable transcripts and mpv connection are provided by &lt;a href=&#34;https://github.com/karthink/elfeed-tube&#34;&gt;elfeed-tube&lt;/a&gt;, which was designed to be usable with the mouse since it involves interacting with a video player.&lt;/p&gt;
&lt;p&gt;My counter-argument can be summarized: &lt;strong&gt;Use the lowest effort means of interaction in each context you work in.  Often this means driving Emacs with the mouse.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;expressivity&#34;&gt;Expressivity&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;expressivity&lt;/strong&gt; counterargument: Buttons and widgets indeed don&amp;rsquo;t scale, but they bear the additional burdern of discoverability.  Mouse interactions in Emacs don&amp;rsquo;t have to be prescribed or discoverable &amp;ndash;  when they are actions &lt;em&gt;we&lt;/em&gt; set up, typically after repeatedly observing a cumbersome task that could be mouse-driven.  Point-and-click in an editor is not as expressive as full-on keyboard usage, but that&amp;rsquo;s only true in the generic sense.  The relevant question is if we can express the &lt;em&gt;specific verbs that we care about&lt;/em&gt;, and from the above demos it&amp;rsquo;s clear we can.&lt;/p&gt;
&lt;p&gt;An example: considering that using the mouse to select and resize windows is already a more natural experience than spamming &lt;code&gt;C-x o&lt;/code&gt; and friends (or your &lt;code&gt;evil-mode&lt;/code&gt; equivalents), it is possible to extend it to be a more comprehensive approach to window and buffer management:&lt;/p&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/strokes-window-handling.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/strokes-window-handling.mp4&#34;&gt;[VIDEO: strokes window handling demo]&lt;/a&gt;
&lt;/video&gt;
&lt;p&gt;This demo showcases the use of mouse gestures to do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Split the frame vertically and horizontally&lt;/li&gt;
&lt;li&gt;Delete windows&lt;/li&gt;
&lt;li&gt;Cycle through buffers in windows by left and right clicking the buffer name in the mode line.&lt;/li&gt;
&lt;li&gt;Delete other windows&lt;/li&gt;
&lt;li&gt;Swap windows to the right and left&lt;/li&gt;
&lt;li&gt;Toggle between the last two buffers shown in a window&lt;/li&gt;
&lt;li&gt;Go back to a previous window configuration (via &lt;code&gt;tab-bar-history-back&lt;/code&gt; or &lt;code&gt;winner-undo&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;how-to-mouse-around&#34;&gt;How to mouse around&lt;/h2&gt;
&lt;p&gt;This is not, strictly speaking, an article on how to use the mouse in Emacs &amp;ndash; it&amp;rsquo;s more about &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;when&lt;/em&gt;.  For the how I suggest reading &lt;a href=&#34;https://amodernist.com/texts/emacs-mouse.html&#34;&gt;Philip Kaludercic&amp;rsquo;s write-up&lt;/a&gt;.  You could also try just clicking around, especially in the mode line!  However the use of gestures in Emacs rarely gets much attention, so here we go.&lt;/p&gt;
&lt;p&gt;For once, this is going to be a short description, since this is a &lt;a href=&#34;https://karthinks.com/software/more-batteries-included-with-emacs/#strokes--m-x-strokes-help&#34;&gt;batteries included&lt;/a&gt; situation.  Emacs ships with everything you need.&lt;/p&gt;
&lt;p&gt;Adding mouse gesture support to Emacs is easy with the included Strokes library
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Many thanks to David Bakhash and the Emacs maintainers for strokes.el.
&lt;/small&gt;&lt;/span&gt;
.  For each action you want to map to a gesture,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find or (optional) write a command that does the thing.&lt;/li&gt;
&lt;li&gt;Set it to a mouse stroke (gesture) with &lt;code&gt;strokes-global-set-stroke&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;rsquo;s it
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
&lt;code&gt;M-x strokes-help&lt;/code&gt; has more information.
&lt;/small&gt;&lt;/span&gt;
.&lt;/p&gt;
&lt;p&gt;Optionally, you could change the mouse button you hold down to perform a gesture.  The default is &lt;code&gt;S-mouse-2&lt;/code&gt;, which is rather awkward.  I use a side button on my mouse (typically the &amp;ldquo;forward&amp;rdquo; button):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;keymap-global-set&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;down-mouse-9&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;strokes-do-stroke&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also optionally, you can hide the live-display of the stroke as you draw (&lt;code&gt;strokes-use-strokes-buffer&lt;/code&gt;) &amp;ndash; I left it in for clarity in the demos.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve not had to customize anything else about the strokes library, but feel free to explore &amp;ndash; it has support for multi-glyph (complex) strokes, for instance.&lt;/p&gt;
&lt;p&gt;There are a few general mouse settings you might be interested in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mouse-autoselect-window&lt;/code&gt;: Set to &lt;code&gt;t&lt;/code&gt; for focus-follows-mouse behavior inside Emacs.  Typically what you&amp;rsquo;d want if you use mouse gestures.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mouse-drag-and-drop-region&lt;/code&gt;: To enable text drag-and-drop within Emacs,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mouse-drag-and-drop-region-cross-program&lt;/code&gt;: (Emacs 29+) and across programs from Emacs.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dired-mouse-drag-files&lt;/code&gt;: To drag files from dired to other programs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;improving-strokes&#34;&gt;Improving Strokes&lt;/h2&gt;
&lt;p&gt;Mouse gestures are a decades-old concept, as many features included with Emacs are.  And the Strokes library has a list of notes and todos, as many features included with Emacs do.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;No contextual actions&lt;/strong&gt;: The use of strokes is limited, as of Emacs 29, by the lack of support for mode-specific or buffer-local strokes.  This means the same gesture cannot do different things in different contexts without writing cumbersome, bespoke dispatch commands to handle this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Somewhat unreliable gesture matching&lt;/strong&gt;:  Drawing with the mouse or trackpad is fuzzy and imprecise.  The matching algorithm is quite rudimentary and there are mismatches when you have many strokes defined (&amp;gt; 25, let&amp;rsquo;s say), even with an increased &amp;ldquo;grid&amp;rdquo; resolution when drawing.  Fixing 1 can take the pressure off the matching algorithm, but we could also use a more sophisticated approach to matching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No multi-touch gestures&lt;/strong&gt;: This can increases the dimensionality of the gesture space, allowing for a greater number of &amp;ldquo;basic strokes&amp;rdquo; &amp;ndash; although the OS usually captures and maps most of these for its window management.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Despite these limitations, this is a very handy tool.  I&amp;rsquo;m not sure why gestures aren&amp;rsquo;t more common &amp;ndash; we only see them on touch interfaces these days.  You can draw them anywhere on the screen, and they tolerate a fair bit of fuzz.  They avoid the problem of having to move the mouse over to a small target on screen.  Not having to fill the screen up with buttons is a win by itself.  The only significant problem appears to be that they&amp;rsquo;re not (re)discoverable, but this isn&amp;rsquo;t a problem inside Emacs: we have &lt;code&gt;strokes-describe-stroke&lt;/code&gt; (like &lt;code&gt;describe-key&lt;/code&gt;) and &lt;code&gt;strokes-list-strokes&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;it-s-not-all-or-nothing-dot-it-s-not-even-something-dot&#34;&gt;It&amp;rsquo;s not all or nothing.  It&amp;rsquo;s not even something.&lt;/h2&gt;
&lt;p&gt;Some of the &amp;ldquo;talking past each other&amp;rdquo; I mentioned in the beginning is because of assumptions we make about using the mouse in text editors.  We gravitate to one of two specious requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The mouse should &lt;em&gt;substitute&lt;/em&gt; for the keyboard, such as when using menu or toolbar buttons &lt;em&gt;instead&lt;/em&gt; of keybindings.&lt;/li&gt;
&lt;li&gt;The mouse should &lt;em&gt;complement&lt;/em&gt; the keyboard, so we work best with a hand each on the keyboard and mouse.  (This is the &lt;a href=&#34;http://acme.cat-v.org/&#34;&gt;Acme editor&lt;/a&gt; approach.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Actual usage patterns are messier than either of these.  Sometimes we&amp;rsquo;re working in a mouse-heavy context, sometimes it&amp;rsquo;s two handed keyboarding, sometimes its a mix.  Often the editor is at the periphery of the task at hand, sometimes it&amp;rsquo;s dead center
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
This is true despite Emacs swallowing up my desktop applications.  Calendar, email, reading, some web browsing&amp;hellip; the list keeps growing.
&lt;/small&gt;&lt;/span&gt;
.  Any degree of flexibility on the part of the editor is welcome.  Instead of dismissing the mouse on the basis of the available design affordances, it can help to think about what we actually care to avoid &amp;ndash; frequent context switching for me, your answer will be different &amp;ndash; and how driving Emacs with the mouse helps us do that.&lt;/p&gt;
</description>
    </item><item>
      <title>Cool your heels, Emacs</title>
      <link>https://karthinks.com/software/cool-your-heels-emacs/</link>
      <pubDate>Mon, 14 Aug 2023 17:54:00 -0700</pubDate>
      
      <guid>https://karthinks.com/software/cool-your-heels-emacs/</guid>
      <description>&lt;div class=&#34;subtitle&#34;&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Sometimes Emacs needs a &lt;a href=&#34;https://github.com/karthink/timeout&#34;&gt;timeout&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;A diamond is very pretty.  But it is very hard to add to a diamond.  A ball of mud is not so pretty.  But you can always add more mud to a ball of mud.&lt;/p&gt;
&lt;div class=&#34;attribution&#34;&gt;
&lt;p&gt;&amp;ndash; Gerald Sussman, paraphrasing Joel Moses&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;A common problem with Emacs&amp;rsquo; giant ball of shared state: Any code can step on the feet of any other &amp;ndash; including yours.  There are conventions in place to keep this from being too much of an issue: Code included in Emacs is tested extensively for edge cases by the tireless maintainers, and third-party package authors are generally careful these days about stepping on too many toes.&lt;/p&gt;
&lt;p&gt;In practice the casualty here is not &lt;em&gt;correctness&lt;/em&gt;, it&amp;rsquo;s &lt;em&gt;performance&lt;/em&gt;.  Emacs can, as of today, only do one thing at a time.  So every &amp;ldquo;background&amp;rdquo; task must, at some point, surface to the foreground and block Emacs for a bit
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Many types of &amp;ldquo;background&amp;rdquo; processing are interruptible by signalling a &lt;code&gt;quit&lt;/code&gt; with &lt;code&gt;keyboard-quit&lt;/code&gt;, but then the task isn&amp;rsquo;t done!  This doesn&amp;rsquo;t help the situation beyond giving you control of Emacs again.
&lt;/small&gt;&lt;/span&gt;
.&lt;/p&gt;
&lt;p&gt;The resultant hitching is experienced both with commands you initiate (&amp;quot;&lt;a class=&#34;org-gls&#34; href=&#34;#gls-8&#34;&gt;push operations&lt;/a&gt;&amp;quot;, let&amp;rsquo;s say) and timers that run code without your involvement (&amp;quot;&lt;a class=&#34;org-gls&#34; href=&#34;#gls-9&#34;&gt;pull operations&lt;/a&gt;&amp;quot;).  Every hook and timer installed by packages to dazzle you with real-time updates or feedback is another fraction of a second for which Emacs is blocked.  Ideally these run when Emacs is idle and you don&amp;rsquo;t notice them.  In practice there are many cases, especially with &amp;ldquo;&lt;a class=&#34;org-gls&#34; href=&#34;#gls-8&#34;&gt;push operations&lt;/a&gt;&amp;rdquo;, that involve significant chunks of synchronous auxiliary processing.&lt;/p&gt;
&lt;p&gt;Under these limitations, a few obvious solutions present themselves.&lt;/p&gt;
&lt;h2 id=&#34;as-a-package-author-you-can&#34;&gt;As a package author, you can&lt;/h2&gt;
&lt;h3 id=&#34;use-conservative-defaults&#34;&gt;Use conservative defaults&lt;/h3&gt;
&lt;p&gt;&amp;hellip;or provide user options to selectively turn off or extend these timers.  Packages for which responsiveness is a marquee feature generally do a good job of this.&lt;/p&gt;
&lt;h3 id=&#34;account-for-as-many-contexts-as-possible&#34;&gt;Account for as many contexts as possible&lt;/h3&gt;
&lt;p&gt;&amp;hellip;when writing packages.&lt;/p&gt;
&lt;p&gt;Elisp code doesn&amp;rsquo;t always run in the context that the author intends.  A &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; update in one window can stagger image display in another.  In-buffer completion can slow down keyboard macro execution.  The more overarching the mode, the larger the surface area for these kinds of interactions.  The list of ways in which a sprawling library like Org+plugins can slow down Emacs (and vice-versa) is long and convoluted.  Few Emacs packages can afford the foresight to be, essentially, paranoid defensive drivers that guard against this unpredictable traffic.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;These examples are not hypothetical&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; update affecting image display: The first example was &lt;code&gt;pdf-tools&lt;/code&gt;&amp;rsquo;s &lt;code&gt;pdf-misc-size-indication-minor-mode&lt;/code&gt; freezing Emacs when updating LaTeX preview images in an unrelated buffer/window.&lt;/li&gt;
&lt;li&gt;The second is a completion-at-point front-end like Company slowing down playback when using &lt;a href=&#34;https://github.com/corytertel/macrursors&#34;&gt;Macrursors&lt;/a&gt;, a multiple-cursors emulator that uses keyboard macros.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id=&#34;as-a-user-you-can&#34;&gt;As a user, you can:&lt;/h2&gt;
&lt;h3 id=&#34;report-slowdowns&#34;&gt;Report slowdowns&lt;/h3&gt;
&lt;p&gt;&amp;hellip;so package maintainer(s) can fix them.&lt;/p&gt;
&lt;p&gt;This is easier said than done.  Binary-searching your way by toggling active modes is tedious.  Profiler output can be mysterious without a good sense for how Emacs&amp;rsquo; command loop works.  A package like &lt;a href=&#34;https://github.com/lastquestion/explain-pause-mode&#34;&gt;explain-pause-mode&lt;/a&gt; does some of this work for you, but the causes can be subtle interactions.  Generally &amp;ndash; but not always &amp;ndash; if you are at the point where you can pinpoint causes of slowdowns, you can also avoid them without much trouble.&lt;/p&gt;
&lt;h3 id=&#34;use-fewer-packages&#34;&gt;Use fewer packages&lt;/h3&gt;
&lt;p&gt;Turn down the bling. Use less mud.&lt;/p&gt;
&lt;p&gt;The saner option.  Emacs&amp;rsquo; first-class extensibility, one of its biggest strengths, is also an inherent limitation.  A significant fraction of complaints I read about Emacs being too slow are usually the result of installing packages with wild abandon.  This results in busy, full-fat hooks (&lt;code&gt;post-command-hook&lt;/code&gt;, &lt;code&gt;post-self-insert-hook&lt;/code&gt;, &lt;code&gt;window-state-change-hook&lt;/code&gt;, …)
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Among many others, like major-mode hooks.  These hooks contain functions that run after every Emacs command, after typing in text, after window changes&amp;hellip; &lt;em&gt;i.e. all the time&lt;/em&gt;.
&lt;/small&gt;&lt;/span&gt;
that bring things to a crawl before long.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;All right!  That was the preamble.  Now that we&amp;rsquo;ve exhausted the &lt;em&gt;good&lt;/em&gt; options, we&amp;rsquo;re free to ignore the less-is-more approach to code today.  It&amp;rsquo;s time to be irresponsible and fix the giant mud ball by&amp;hellip; &lt;strong&gt;adding more mud&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;timeouts-and-delays&#34;&gt;Timeouts and Delays&lt;/h2&gt;
&lt;p&gt;The problem common to both &amp;ldquo;push&amp;rdquo; and &amp;ldquo;pull&amp;rdquo; slowdowns is non-critical code running more often than it should.  Our no-context, no-Chesterton&amp;rsquo;s-fence solution is to force such code into a timeout.  There are two common ways of doing this, with different use patterns, and we&amp;rsquo;re going to implement both.&lt;/p&gt;
&lt;h3 id=&#34;first-up-throttle&#34;&gt;First up: &lt;strong&gt;Throttle&lt;/strong&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/throttle_description.svg&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Throttled code (&lt;code&gt;foo&lt;/code&gt;) is placed in a timeout after it runs once.  Attempts to run again for the duration of the timeout (the &amp;ldquo;Throttle time&amp;rdquo; above) are ignored.  See &lt;a href=&#34;https://redd.one/blog/debounce-vs-throttle&#34;&gt;this resource&lt;/a&gt; for an interactive explanation.&lt;/p&gt;
&lt;p&gt;In the context of Emacs, throttling works well for &amp;ldquo;&lt;a class=&#34;org-gls&#34; href=&#34;#gls-9&#34;&gt;pull operations&lt;/a&gt;&amp;rdquo;, i.e. code that runs non-interactively and independent of user input
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Typically this means messing with timers, which is generally &lt;em&gt;a bad idea&lt;/em&gt;&amp;hellip; but we covered all the good solutions already, didn&amp;rsquo;t we?
&lt;/small&gt;&lt;/span&gt;
.  Throttling user commands (or their consequents) leads to state changes being completely ignored, which is rarely what we want.&lt;/p&gt;
&lt;p&gt;Of course, if packages with over-eager timers allow for customizable eagerness, then the simpler solution is to tweak the frequency directly.  Packages that implement &amp;ldquo;&lt;a class=&#34;org-gls&#34; href=&#34;#gls-9&#34;&gt;pull operations&lt;/a&gt;&amp;rdquo; are generally conscientious about this.  If something is running far more often than it should, searching for the variable(s) &lt;code&gt;&amp;lt;package-name&amp;gt;-*-delay&lt;/code&gt; or  &lt;code&gt;&amp;lt;package-name&amp;gt;-*-timer&lt;/code&gt; is a good start to fixing it.  Further, these actions typically run on &lt;a class=&#34;org-gls&#34; href=&#34;#gls-6&#34;&gt;idle timers&lt;/a&gt;, which is like a built-in debounce and unlikely to block Emacs in a perceptible way.&lt;/p&gt;
&lt;p&gt;But there are many exceptions.  What we&amp;rsquo;d like, in the absence of a provided dial for tuning this, is an elisp function or macro that can easily &amp;ndash; and generically &amp;ndash; &lt;em&gt;throttle&lt;/em&gt; any other elisp function.&lt;/p&gt;
&lt;h3 id=&#34;second-debounce&#34;&gt;Second: &lt;strong&gt;Debounce&lt;/strong&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/debounce-description.svg&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Debounced code (&lt;code&gt;foo&lt;/code&gt;) runs after a pre-specified delay from when it is called (the &amp;ldquo;Debounce time&amp;rdquo; above).  If the command is called again before the delay ends, it resets to its full duration.  See &lt;a href=&#34;https://redd.one/blog/debounce-vs-throttle&#34;&gt;this resource&lt;/a&gt; for an interactive explanation.&lt;/p&gt;
&lt;p&gt;In the context of Emacs, debouncing makes more sense with &amp;ldquo;&lt;a class=&#34;org-gls&#34; href=&#34;#gls-8&#34;&gt;push operations&lt;/a&gt;&amp;rdquo;.  Debounced user commands are ignored when there are too many calls in quick succession, except for the last one.  This is typically what we want in an interactive context, since the intermediate states from running each call would have been invalidated by the next call anyway.&lt;/p&gt;
&lt;p&gt;Again, we want an elisp function or macro that can easily &amp;ndash; and generically &amp;ndash; &lt;em&gt;debounce&lt;/em&gt; any other elisp function.&lt;/p&gt;
&lt;h3 id=&#34;aside-memoize&#34;&gt;Aside: &lt;strong&gt;Memoize&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;i.e.&lt;/em&gt; just caching &amp;ndash; store the results of expensive calculations and use a look-up table instead.
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Emacs 29+ includes a handy &lt;code&gt;with-memoization&lt;/code&gt; macro to facilitate this for any chunk of code.
&lt;/small&gt;&lt;/span&gt;
We do a bit of caching with the throttle implementation below.  But in general this doesn&amp;rsquo;t work for our purposes because the functions we want to use this with are rarely pure &amp;ndash; they work by side-effect using (and on) Emacs&amp;rsquo; current state as a potential input.  So there&amp;rsquo;s no way to provide a generic memoization routine without knowing what the specific code in question is doing.&lt;/p&gt;
&lt;h2 id=&#34;throttle-and-debounce&#34;&gt;&lt;code&gt;throttle!&lt;/code&gt; and &lt;code&gt;debounce!&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;What we&amp;rsquo;d like: given a command or plain function &lt;code&gt;foo&lt;/code&gt;, modify it so that&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;throttle!&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;2.0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;throttles it to run no more than once every 2 seconds, and&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;debounce!&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;debounces it to run with a delay of 0.5 seconds.&lt;/p&gt;
&lt;p&gt;We can also envision the safer, &amp;ldquo;non-destructive&amp;rdquo; versions
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Although our versions of &lt;code&gt;throttle!&lt;/code&gt; (etc) won&amp;rsquo;t be destructive because of Emacs&amp;rsquo; robust advice system.
&lt;/small&gt;&lt;/span&gt;
that return new functions, so we could do&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;fset&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo-throttled&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;2.0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;fset&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo-debounced&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;debounce&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This turns out to actually be trickier to do well (&lt;a href=&#34;#throttle-and-debounce-non-destructive-finagling&#34;&gt;see below&lt;/a&gt;).  For the in-place versions, we can rely on Emacs&amp;rsquo; advice system to do most of the work for us.&lt;/p&gt;
&lt;p&gt;Before we implement &lt;code&gt;throttle!&lt;/code&gt; and &lt;code&gt;debounce!&lt;/code&gt;, let&amp;rsquo;s look at the kinds of thing we&amp;rsquo;d like to do with them.&lt;/p&gt;
&lt;h3 id=&#34;example-throttle-smart-mode-line-updates&#34;&gt;Example: throttle &lt;code&gt;smart-mode-line&lt;/code&gt; updates&lt;/h3&gt;
&lt;p&gt;Updating the &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; display is one of the exceptions I mentioned in the &lt;a href=&#34;#first-up-throttle&#34;&gt;throttle description&lt;/a&gt;.  Typically the &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; is updated along with &lt;a class=&#34;org-gls&#34; href=&#34;#gls-10&#34;&gt;redisplay&lt;/a&gt;, and Emacs is quite fast at handling all display elements that Emacs has C-level support for (typically the &lt;code&gt;%&lt;/code&gt;-prefixed &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/_0025_002dConstructs.html&#34;&gt;format specifiers&lt;/a&gt;).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For efficiency, Emacs does not continuously recompute each window’s mode line and header line.  It does so when circumstances appear to call for it—for instance, if you change the window configuration, switch buffers, narrow or widen the buffer, scroll, or modify the buffer.&lt;/p&gt;
&lt;div class=&#34;attribution&#34;&gt;
&lt;p&gt;&amp;ndash;&lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Mode-Line-Basics.html&#34;&gt; Mode Line Basics&lt;/a&gt;, elisp manual.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;The problem is that it appears to compute &lt;em&gt;every&lt;/em&gt; element on the &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; under &lt;em&gt;any&lt;/em&gt; of these circumstances.&lt;/li&gt;
&lt;li&gt;You can evaluate arbitrary Lisp code during a &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; update, and we sure do like to stuff the Emacs &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; with fancy widgets in &lt;code&gt;:eval&lt;/code&gt; blocks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The combination of these two facts is a recipe for slowdown.&lt;/p&gt;
&lt;p&gt;Case in point: the &lt;code&gt;smart-mode-line&lt;/code&gt; package uses the function &lt;code&gt;sml/generate-minor-modes&lt;/code&gt; to display active minor-modes in the &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; with rich formatting.  Generating this string
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
A rather plain one too, despite support for rich text.
&lt;/small&gt;&lt;/span&gt;
takes up to 10% of Emacs&amp;rsquo; time during routine text-editing.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/sml-minor-mode-string-annotated.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;As the Emacs profiler illustrates:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Samples   %    Function
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   1076  65% - redisplay_internal (C function)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    705  43%  + jit-lock-function
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    404  22%  - eval
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    220  13%   + and-let*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--&amp;gt; 166   9%   + sml/generate-minor-modes   &amp;lt;-- PRE-THROTTLE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      4   0%     sml/generate-modified-status
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     52   3% - ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     52   3%    Automatic GC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Recomputing the minor-modes string after every buffer insertion or window scroll is a waste.  We&amp;rsquo;re actually fine so long as it&amp;rsquo;s updated soon after a minor-mode is enabled or disabled.  So we throttle this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; only allowed to run once every 4 seconds.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;throttle!&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;sml/generate-minor-modes&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;4.0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This frees up Emacs to do other things.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Samples    %   Function
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   1482  66% - redisplay_internal (C function)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    733  33%  - eval
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    681  30%   + and-let*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     17   0%     sml/generate-modified-status
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--&amp;gt;   9   0%   + sml/generate-minor-modes   &amp;lt;-- POST-THROTTLE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      6   0%   + format
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    700  31%  + jit-lock-function
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    117   5% - ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    117   5%    Automatic GC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Throttling lets us work around, in a coarse way, our lack of control over the &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; update logic.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Throttle vs Debounce&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;In this example, using a debounce would have worked too&amp;hellip; for the most part.  There would be scenarios where it wouldn&amp;rsquo;t work well, though, such as turning on/off a minor mode and then immediately scrolling the window or typing.  If we can tolerate slightly-out-of-date reports of Emacs&amp;rsquo; state, throttling is generally the better option.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h3 id=&#34;example-debounce-org-agenda-follow-mode&#34;&gt;Example: debounce &lt;code&gt;org-agenda-follow-mode&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;An example of an Org-mode feature that&amp;rsquo;s too eager for its own good:  when following along entries with a preview in the Org Agenda, running down the list to the next item you&amp;rsquo;re interested in causes previews to be generated for each intermediate item (first video).  Org does a fair bit of work &amp;ndash; relative to the cursor movement speed - to set up the preview display, causing Emacs to hitch.&lt;/p&gt;
&lt;div class=&#34;wide&#34;&gt;
&lt;div class=&#34;column&#34;&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/org-agenda-no-debounce.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/org-agenda-no-debounce.mp4&#34;&gt;[Video: org-agenda without a debounce]&lt;/a&gt;&lt;/video&gt;
&lt;/div&gt;
&lt;div class=&#34;column&#34;&gt;
&lt;video preload=&#34;metadata&#34; style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/org-agenda-debounce.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/org-agenda-debounce.mp4&#34;&gt;[Video: org-agenda with a debounce]&lt;/a&gt;&lt;/video&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s debounce this feature:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; run after a resettable delay of 0.3 seconds.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;debounce!&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-agenda-do-context-action&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Throwing in a debounce causes the intermediate cursor positions to be ignored (second video), making the process smoother and less visually noisy while keeping Emacs responsive.&lt;/p&gt;
&lt;p&gt;Debouncing lets us work around, in a coarse way, user input that&amp;rsquo;s coming too fast to be smoothly acted on.&lt;/p&gt;
&lt;h3 id=&#34;an-inside-out-implementation&#34;&gt;An inside-out implementation&lt;/h3&gt;
&lt;p&gt;To implement &lt;code&gt;throttle!&lt;/code&gt; and &lt;code&gt;debounce!&lt;/code&gt;, we can work our way outwards from the specification of what throttles and debounces should do.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;But before we dig in&amp;#x2026;&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;This is primarily a fun elisp exercise.&lt;/p&gt;
&lt;p&gt;If you are considering throttling elisp from outside of packages as an actual solution to addressing performance issues, you should have already tried the better options listed at the start of this write-up.  We don&amp;rsquo;t play with mud balls without getting our hands dirty.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;A throttled function will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run when first called,&lt;/li&gt;
&lt;li&gt;and start keeping time.&lt;/li&gt;
&lt;li&gt;If called again within the timeout period,&lt;/li&gt;
&lt;li&gt;it refuses to run or returns immediately.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The core of this idea is captured in this thunk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; FUNC is the function to be throttled, called with arguments ARGS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; TIMEOUT is the throttle duration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; If the timer is running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;;; do nothing, return nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;;; else run and start the timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#888&#34;&gt;;; clear the timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where &lt;code&gt;throttle-timer&lt;/code&gt; and &lt;code&gt;timeout&lt;/code&gt; need to be persistent between calls to this function.&lt;/p&gt;
&lt;p&gt;The debounce version is built similarly.  A debounced function will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Not run immediately, and start a timer when first called.&lt;/li&gt;
&lt;li&gt;If called again before the timer expires,&lt;/li&gt;
&lt;li&gt;the timer is reset and starts over.&lt;/li&gt;
&lt;li&gt;If the timer ends, the function finally runs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The core of this process is captured in the following thunk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; FUNC is the function to be throttled, called with arguments ARGS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; DELAY is the debounce period&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; If the timer is running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;;; Do not run the function, reset the timer instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#963&#34;&gt;timer-set-idle-time&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;;; start the timer over&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;run-with-idle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#888&#34;&gt;;; Timer ran, finally run the function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where &lt;code&gt;debounce-timer&lt;/code&gt; and &lt;code&gt;delay&lt;/code&gt; need to be persistent between calls to this function.  We use an idle-timer when debouncing, and a regular timer for the throttle.  Using an &lt;a class=&#34;org-gls&#34; href=&#34;#gls-6&#34;&gt;idle timer&lt;/a&gt; here is technically incorrect, but the better choice since &lt;code&gt;func&lt;/code&gt; is presumably an expensive call.  The throttle timer only has to clear itself, which is cheap.&lt;/p&gt;
&lt;p&gt;Next, we need to wrap these in a function that effectively acts as the throttled/debounced &lt;code&gt;func&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;warning&#34;&gt;
&lt;p&gt;If you are trying this in Emacs, be sure to &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html&#34;&gt;turn on&lt;/a&gt; &lt;code&gt;lexical-binding&lt;/code&gt; first.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--throttled-closure&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Run with a throttle.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;;; do nothing, return nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;;; else run and start the timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#888&#34;&gt;;; clear the timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;throttle-timer&lt;/code&gt; and &lt;code&gt;timeout&lt;/code&gt; are now defined in the enclosing environment.  Provided &lt;code&gt;lexical-binding&lt;/code&gt; is turned on, the inner lambda is a closure and these two objects will be persistent across calls to this closure.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;func&lt;/code&gt; is still undefined/free.  We place the above code into a &amp;ldquo;throttle-maker&amp;rdquo; function that &amp;ldquo;closes over&amp;rdquo; &lt;code&gt;func&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Return a throttled version of FUNC.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;It runs at most once every TIMEOUT seconds (default 1.0).&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that this is the &amp;ldquo;non-destructive&amp;rdquo; version, it returns a new function instead of modifying &lt;code&gt;func&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While we&amp;rsquo;re at it, we can return the previous result instead of &lt;code&gt;nil&lt;/code&gt; during the throttle duration.  This is unimportant for top-level interactive commands, but might at least help avoid type errors if this is a pure function, or if we&amp;rsquo;re monkey-patching something deep inside an elisp library.&lt;/p&gt;
&lt;p&gt;We effectively memoize the &lt;code&gt;result&lt;/code&gt; of calling &lt;code&gt;func&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Return a throttled version of FUNC.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;It runs at most once every TIMEOUT seconds (default 1.0).&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The debounce version is similar, but there&amp;rsquo;s nowhere to return the &lt;code&gt;result&lt;/code&gt; to this time.  &lt;code&gt;func&lt;/code&gt; may be called from anywhere in the code but runs (eventually, via the timer) at top-level, so it doesn&amp;rsquo;t make sense to store its return value.
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
We also couldn&amp;rsquo;t if we wanted to, since the return value doesn&amp;rsquo;t exist yet.
&lt;/small&gt;&lt;/span&gt;
To satisfy the calling code, we can prespecify a constant return value when constructing the function.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a new wrinkle as well: the throttled &lt;code&gt;func&lt;/code&gt; runs immediately or not at all.  The debounced &lt;code&gt;func&lt;/code&gt;, however, runs at a later time when the environment can be different &amp;ndash; or invalid.  So we need to capture as much of the current context as we can and restore it when &lt;code&gt;func&lt;/code&gt; runs.  Capturing the full context at call time is not possible (it could be anything)
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
As far as I know.  This might be possible in other Lisps with continuations, etc.
&lt;/small&gt;&lt;/span&gt;
, but we can set the active buffer at least.&lt;/p&gt;
&lt;p&gt;Adding a &lt;code&gt;default&lt;/code&gt; &amp;ldquo;immediate-return&amp;rdquo; value and the calling context, we get&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--debounced-closure&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Return a debounced version of FUNC.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;It runs with a delay of DELAY seconds (default 0.5).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;DEFAULT is the immediate return value of the function when
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;called.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.5&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#963&#34;&gt;timer-set-idle-time&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;run-with-idle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#888&#34;&gt;;set buffer when running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;current-buffer&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;re on the right track, but there are many issues with &lt;code&gt;throttle&lt;/code&gt; and &lt;code&gt;debounce&lt;/code&gt; above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The generated closures don&amp;rsquo;t have &lt;code&gt;interactive&lt;/code&gt; forms, so they cannot be run as commands.  We can&amp;rsquo;t add interactive forms unconditionally, since we might want to throttle/debounce non-interactive functions too.&lt;/li&gt;
&lt;li&gt;The generated closures don&amp;rsquo;t have any documentation.  Assigning them to variables with &lt;code&gt;fset&lt;/code&gt; will leave them (mostly) non-introspectable.&lt;/li&gt;
&lt;li&gt;Most importantly, we wanted a &lt;code&gt;throttle!&lt;/code&gt; and &lt;code&gt;debounce!&lt;/code&gt; to corral existing errant elisp code, not generate new, quieter variants.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It turns out most of these issues can be resolved in one go, with some&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;advising-around&#34;&gt;Advising around&lt;/h3&gt;
&lt;p&gt;We have on hand our throttled and debounced versions of &lt;code&gt;func&lt;/code&gt;, albeit lacking some niceties.  To replace &lt;code&gt;func&lt;/code&gt; with these variants, we will depend on Emacs&amp;rsquo; advice system.  We&amp;rsquo;re specifically looking for a recipe that routes around &lt;code&gt;func&lt;/code&gt; while letting us call it when necessary.  The &lt;code&gt;:around&lt;/code&gt; advice combinator fits the bill:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;‘:around’&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Call &lt;code&gt;FUNCTION&lt;/code&gt; instead of the old function, but provide the old function as an extra argument to &lt;code&gt;FUNCTION&lt;/code&gt;. This is the most flexible composition. For example, it lets you call the old function with different arguments, or many times, or within a let-binding, or &lt;strong&gt;you can sometimes delegate the work to the old function and sometimes override it completely&lt;/strong&gt;. More specifically, the composition of the two functions behaves like:
&lt;code&gt;(lambda (&amp;amp;rest r) (apply FUNCTION OLDFUN r))&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;-Manual section on Advice Combinators (emphasis mine)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This time let&amp;rsquo;s work our way outside-in.  The basic idea is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define a function that accepts as arguments the original function (&lt;code&gt;oldfun&lt;/code&gt;) and &lt;em&gt;its&lt;/em&gt; arguments.&lt;/li&gt;
&lt;li&gt;Add this as &lt;code&gt;:around&lt;/code&gt; advice to &lt;code&gt;oldfun&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Emacs runs this function instead of &lt;code&gt;oldfun&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;!--listend--&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;newfun&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;oldfun&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;;; do stuff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;predicate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;oldfun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;;; do something else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;oldfun&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:around&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;newfun&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Our &lt;code&gt;newfun&lt;/code&gt; is the generated closure (&lt;a href=&#34;#code-snippet--throttled-closure&#34;&gt;throttled&lt;/a&gt; or &lt;a href=&#34;#code-snippet--debounced-closure&#34;&gt;debounced&lt;/a&gt;) from the previous section.  Here&amp;rsquo;s the same throttled closure as before, but following the above pattern instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;oldfun&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Throttle this function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;oldfun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This closure, intended as &lt;code&gt;:around&lt;/code&gt; advice, accepts &lt;code&gt;oldfun&lt;/code&gt; as an argument along with &lt;code&gt;args&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This time there&amp;rsquo;s nothing to &amp;ldquo;close over&amp;rdquo; save the (customizable) &lt;code&gt;timeout&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle--advice&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;oldfun&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Throttle this function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;oldfun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;throttle--advice&lt;/code&gt; is an &amp;ldquo;advice maker&amp;rdquo; that, when called with a timeout, returns an &amp;ldquo;advice function&amp;rdquo; that throttles the function it advises. Phew!&lt;/p&gt;
&lt;p&gt;Of course, we need to actually add this advice:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:around&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;throttle--advice&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This advice (closure) is nameless &amp;ndash; we require a way to refer to it so that we can restore &lt;code&gt;foo&lt;/code&gt; to its un-throttled, over-eager, Emacs-blocking state.  We should also add this advice &lt;em&gt;last&lt;/em&gt;, in that any other advice placed on &lt;code&gt;foo&lt;/code&gt; should take precedence &amp;ndash; the result of throttling the function would be unpredictable otherwise.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;advice-add&lt;/code&gt; provides the machinery to do both these things:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:around&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;throttle--advice&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#963&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;depth&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;-99&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wrapping up this action in a function (finally) gives us the &lt;code&gt;throttle!&lt;/code&gt; we are looking for:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle!&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;advice-remove&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;func&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;throttle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#963&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:around&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;throttle--advice&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#963&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#963&#34;&gt;depth&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;-99&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead of defining an &lt;code&gt;unthrottle!&lt;/code&gt;, we make it so passing a &lt;code&gt;timeout&lt;/code&gt; of &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;throttle!&lt;/code&gt; restores the original function.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;debounce!&lt;/code&gt; works the exact same way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; advice-maker&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce--advice&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.5&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;oldfun&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Debounce this function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#963&#34;&gt;timer-set-idle-time&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;run-with-idle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;oldfun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;current-buffer&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; advice-adder or remover&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce!&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;advice-remove&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;debounce&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#963&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:around&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;debounce--advice&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#963&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#963&#34;&gt;depth&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;-98&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;debounce--advice&lt;/code&gt; is an &amp;ldquo;advice maker&amp;rdquo; that, when called with a delay, returns an &amp;ldquo;advice function&amp;rdquo; that debounces the function it advises.  &lt;code&gt;debounce!&lt;/code&gt; can then add or remove this advice function to its argument.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Fortuitously, the other two problems &amp;ndash; mirroring the interactive spec and adding function documentation &amp;ndash; have worked themselves out.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Advice functions that don&amp;rsquo;t have an interactive spec &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Core-Advising-Primitives.html&#34;&gt;will reuse&lt;/a&gt; that of the function they are advising.&lt;/li&gt;
&lt;li&gt;The documentation of the original function is still available, with a note about the advice at the end.  This note is the documentation of the advice function itself, &lt;em&gt;i.e.&lt;/em&gt; &amp;ldquo;Throttle this function&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;top-level-vs-nested-calls-what-can-we-timeout&#34;&gt;Top-level vs nested calls: what can we timeout?&lt;/h2&gt;
&lt;p&gt;A short digression on Emacs&amp;rsquo; command loop.&lt;/p&gt;
&lt;p&gt;Throttling or debouncing code that runs at top-level, such as user commands or timers, is simple.  Since there&amp;rsquo;s nothing for them to &amp;ldquo;return to&amp;rdquo;, introducing delays or (effectively) refusing to run code has no consequences beyond a delay in the corresponding library&amp;rsquo;s understanding of Emacs&amp;rsquo; current state.&lt;/p&gt;
&lt;p&gt;Things get tricky when we mess with &amp;ldquo;internal&amp;rdquo; code.  Often it&amp;rsquo;s not user commands themselves that need debouncing, but something heavy lurking well inside a hook that runs as a result of the command.  Our throttle example above (&lt;code&gt;sml/generate-minor-modes&lt;/code&gt;) is a &amp;ldquo;hook function&amp;rdquo; triggered by &lt;a class=&#34;org-gls&#34; href=&#34;#gls-11&#34;&gt;mode-line&lt;/a&gt; updates.  Our debounce example (&lt;code&gt;org-agenda-do-context-action&lt;/code&gt;) is a function called from deep inside the &lt;code&gt;org-agenda&lt;/code&gt; machinery when the cursor moves.  Since&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;throttled functions can return &lt;code&gt;nil&lt;/code&gt; or repeat a previous result, and&lt;/li&gt;
&lt;li&gt;debounced functions always return &lt;code&gt;nil&lt;/code&gt; immediately,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;we require &lt;code&gt;nil&lt;/code&gt; to be (at minimum) a valid return value wherever they are called, and (better) a value that stops further processing in the moment.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Picking a different return value&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;The same is true for any other &lt;code&gt;non-nil&lt;/code&gt; value we choose to return (&lt;a href=&#34;#code-snippet--debounced-closure&#34;&gt;see implementation&lt;/a&gt;).  Reusing return values from past calls to debounced functions is not possible without setting up global variables&amp;hellip;  which is a project for another time.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Having throttled and debounced a bunch of internal functions now, I can report that this is generally true of elisp code that needs a timeout, so long as a little care is exercised in picking them.&lt;/p&gt;
&lt;h2 id=&#34;throttle-and-debounce-non-destructive-finagling&#34;&gt;&lt;code&gt;throttle&lt;/code&gt; and &lt;code&gt;debounce&lt;/code&gt;: Non-destructive finagling&lt;/h2&gt;
&lt;p&gt;So why is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;fset&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo-debounced&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;debounce&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;foo&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;difficult to pull off well?&lt;/p&gt;
&lt;p&gt;We have the basic skeleton in place &lt;a href=&#34;#code-snippet--debounced-closure&#34;&gt;from before&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Return a debounced version of FUNC.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;It runs with a delay of DELAY seconds (default 0.5).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;DEFAULT is the immediate return value of the function when
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;called.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.5&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#963&#34;&gt;timer-set-idle-time&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;prog1&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;run-with-idle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#888&#34;&gt;;set buffer when running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;current-buffer&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problems are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mirroring the interactive form of &lt;code&gt;func&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Documenting the unnamed closure that &lt;code&gt;debounce&lt;/code&gt; returns.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;mirroring-interactive-forms&#34;&gt;Mirroring &lt;code&gt;interactive&lt;/code&gt; forms&lt;/h4&gt;
&lt;p&gt;We can lean on the advice system again for the former, but it&amp;rsquo;s ugly.  We essentially write both versions of the function and pick one.  Here&amp;rsquo;s &lt;code&gt;throttle&lt;/code&gt;:&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Mirroring interactive forms: &lt;code&gt;throttle&lt;/code&gt;&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Return a throttled version of function FUNC.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;THROTTLE defaults to 1 second.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;iform&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;interactive-form&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;iform&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;;; INTERACTIVE version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;advice-eval-interactive-spec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#963&#34;&gt;cadr&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;iform&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;;; NON-INTERACTIVE version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;&lt;code&gt;debounce&lt;/code&gt; is similar.&lt;/p&gt;
&lt;h4 id=&#34;inserting-function-documentation&#34;&gt;Inserting function documentation&lt;/h4&gt;
&lt;p&gt;Named symbols can have function documentation inserted directly into their &lt;code&gt;function-documentation&lt;/code&gt; &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Standard-Properties.html&#34;&gt;symbol property&lt;/a&gt;.  Documenting unnamed closures programmatically is beyond me at this point &amp;ndash; unless of course, we embrace the idea that we&amp;rsquo;re writing code that writes code&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;it-s-macrotime&#34;&gt;It&amp;rsquo;s macrotime!&lt;/h3&gt;
&lt;p&gt;At this point it would actually be easier to get Emacs to write the code for us.  This process is much more accessible (if not simpler) with a macro.  We can fetch the relevant interactive form and documentation and shove them verbatim into the closure definition:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#888&#34;&gt;;; Add the documentation from FUNC with an extra note&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;documentation&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\n\nThis function is debounced -- it runs after a delay of %.3f seconds.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;;; Add the interactive form from FUNC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;interactive-form&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;;; Rest of the debounce code from above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While we&amp;rsquo;re at it, we can even skip the &lt;code&gt;fset&lt;/code&gt; step and just define the new function &lt;code&gt;func--debounced&lt;/code&gt; directly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;) &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;--debounced&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#888&#34;&gt;;; Add the documentation from FUNC with an extra note&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;documentation&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\n\nThis function is debounced -- it runs after a delay of %.3f seconds.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;;; Add the interactive form from FUNC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;interactive-form&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;;; Rest of the debounce code from above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Adding the lexical environment (for &lt;code&gt;debounce-timer&lt;/code&gt; etc) and the rest of the macro definition, we get&lt;/p&gt;
&lt;div class=&#34;warning&#34;&gt;
&lt;p&gt;If you are trying this in Emacs, be sure to &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html&#34;&gt;turn on&lt;/a&gt; &lt;code&gt;lexical-binding&lt;/code&gt; first.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Return a debounced version of function FUNC.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;DELAY defaults to 0.5 seconds.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.5&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;) &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;--debounced&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;;; Add the documentation from FUNC with an extra note&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;documentation&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\n\nThis function is debounced -- it runs after a delay of %.3f seconds.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;;; Add the interactive form from FUNC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;interactive-form&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#963&#34;&gt;timer-set-idle-time&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;current-buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#963&#34;&gt;run-with-idle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#963&#34;&gt;delay&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;debounce-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#007020&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;))))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works as we intended, only the function name should no longer be quoted. The following code&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;debounce&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;next-line&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;expands to a definition for &lt;code&gt;next-line--debounced&lt;/code&gt;, replete with the correct documentation and &lt;code&gt;interactive&lt;/code&gt; behavior
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Or we could stick to the anonymous closure version and run &lt;code&gt;(fset &#39;next-line--debounced (debounce next-line))&lt;/code&gt;
&lt;/small&gt;&lt;/span&gt;
.&lt;/p&gt;
&lt;p&gt;For completeness, here is &lt;code&gt;throttle&lt;/code&gt; as a macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Return a throttled version of function FUNC.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;TIMEOUT defaults to 1 second.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;default&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;) &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;--debounced&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;documentation&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\n\nThis function is throttled -- it runs at most once every %.3f seconds.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;interactive-form&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;timerp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;run-with-timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#963&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#963&#34;&gt;cancel-timer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;throttle-timer&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;questions&#34;&gt;Questions&lt;/h2&gt;
&lt;p&gt;A few concerns bubbled up on this excursion, and I don&amp;rsquo;t know how to address them:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Debouncing a function a few hundred times is easy to do just by holding down a key.  &lt;del&gt;This creates and destroys many timers &amp;ndash; I don&amp;rsquo;t know if the ensuing garbage is worth worrying about, and whether it can be avoided.&lt;/del&gt;
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
This is now avoided in the code, see acknowledgments.
&lt;/small&gt;&lt;/span&gt;
Here is the &lt;code&gt;atimer&lt;/code&gt; struct that Emacs uses:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;struct&lt;/span&gt; atimer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888&#34;&gt;/* The type of this timer.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;enum&lt;/span&gt; atimer_type type;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888&#34;&gt;/* Time when this timer is ripe.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;struct&lt;/span&gt; timespec expiration;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888&#34;&gt;/* Interval of this timer.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;struct&lt;/span&gt; timespec interval;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888&#34;&gt;/* Function to call when timer is ripe.  Interrupt input is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;        guaranteed to not be blocked when this function is called.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     atimer_callback fn;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888&#34;&gt;/* Additional user-specified data to pass to FN.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#339;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;*&lt;/span&gt;client_data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888&#34;&gt;/* Next in list of active or free atimers.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;struct&lt;/span&gt; atimer &lt;span style=&#34;color:#333&#34;&gt;*&lt;/span&gt;next;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is&amp;hellip; about 48 bytes of memory?  &lt;del&gt;Debouncing a command 200 times &amp;ndash; not an uncommon occurrence &amp;ndash; then creates at least 10KB of garbage.  How does this compare with the regular rate of garbage creation in Emacs?&lt;/del&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How long does it take, realistically speaking, to create and clear timers?  Some testing suggests that this is not an insignificant number when done in bulk, especially coupled with garbage collection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using a macro to implement the &amp;ldquo;non-destructive&amp;rdquo; versions of &lt;code&gt;throttle!&lt;/code&gt; and &lt;code&gt;debounce!&lt;/code&gt; does not pair well with our functions &amp;ndash; the call signatures are different.  Perhaps there is a way to do this with functions that isn&amp;rsquo;t janky?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;the-timeout-library&#34;&gt;The &lt;code&gt;timeout&lt;/code&gt; library&lt;/h2&gt;
&lt;p&gt;This functionality is available as an elisp package: &lt;a href=&#34;https://github.com/karthink/timeout&#34;&gt;timeout&lt;/a&gt;.  So far it&amp;rsquo;s exactly the code developed above, and just a couple of helper functions.&lt;/p&gt;
&lt;p&gt;Writing debouncers and throttlers this way wasn&amp;rsquo;t a careful design process on my part.  In fact, I have no idea how else I could write them in elisp.  This suggests that I don&amp;rsquo;t understand the problem very well, or don&amp;rsquo;t understand elisp well, or (more likely) both.  If you have corrections, suggestions or answers for me, please get in touch.&lt;/p&gt;
&lt;p&gt;All right then &amp;ndash; that&amp;rsquo;s it for me.  Gotta debounce!&lt;/p&gt;
&lt;details class=&#34;details apinote&#34; open style=&#34;font-size:0.8rem;margin-top:18px&#34;&gt;
&lt;summary&gt;Glossary&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;a name=&#34;gls-6&#34;&gt;Idle timer&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;An idle timer is some Lisp code scheduled to run when Emacs is idle for a specified period.  What it means for Emacs to be idle is complicated: at minimum, this means no user input, no subprocess communication and no non-idle timers that need running. [2 uses]&lt;/dd&gt;
&lt;dt&gt;&lt;a name=&#34;gls-11&#34;&gt;Mode-line&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;This is the &amp;ldquo;status bar&amp;rdquo; at the bottom of Emacs windows.  There are dozens of Emacs packages that prettify the mode-line, adding widgets and status reports.  I&amp;rsquo;ve found many of these to be too aggressive in how often they update. [10 uses]&lt;/dd&gt;
&lt;dt&gt;&lt;a name=&#34;gls-8&#34;&gt;Push operations&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Slow elisp code that runs as a direct result of user input.  Example: an html preview of a markdown buffer that updates with each keystroke.  Less exreme examples: sending data to an LSP server when some code is yanked into a buffer, or a header-line update because the cursor moved into a new function.  So named because control of Emacs is &amp;ldquo;pushed&amp;rdquo; away as a result of the input action. [3 uses]&lt;/dd&gt;
&lt;dt&gt;&lt;a name=&#34;gls-9&#34;&gt;Pull operations&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Slow elisp code that runs independent of user input, although it might be interrupted by it.  So named because control of Emacs is &amp;ldquo;pulled&amp;rdquo; away by this code irrespective of user input.  Examples: any idle timer not tied to user input, like RefTeX&amp;rsquo;s periodic scans of the LaTeX buffer.  Of course, ultimately everything that happens in Emacs is user-driven and thus a &amp;ldquo;push operation&amp;rdquo;.  This distinction is only one of proximity to the user. [3 uses]&lt;/dd&gt;
&lt;dt&gt;&lt;a name=&#34;gls-10&#34;&gt;Redisplay&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;This is the process of redrawing the screen, or more often parts of it, in Emacs.  Considering Emacs&amp;rsquo; terminal user interface and support for every platform under the sun, displaying is a complicated affair. [1 uses]&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;details open style=&#34;font-size:0.8rem;margin-top:12px&#34;&gt;
&lt;summary&gt;Acknowledgments&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;Joseph Turner points out that &lt;code&gt;timerp&lt;/code&gt; handles the case when its argument is &lt;code&gt;nil&lt;/code&gt;, so there is no need to check explicitly, as in &lt;code&gt;(if (and debounce-timer (timerp debounce-timer)))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ihor Radchenko points out that timer attributes (such as the remaining time) can be modified in place with the &lt;code&gt;timer-set-*&lt;/code&gt; functions.  This completely fixes the problem of debounce timers generating a lot of garbage.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
</description>
    </item><item>
      <title>Persistent prefix keymaps in Emacs</title>
      <link>https://karthinks.com/software/persistent-prefix-keymaps-in-emacs/</link>
      <pubDate>Sun, 05 Mar 2023 15:22:00 -0800</pubDate>
      
      <guid>https://karthinks.com/software/persistent-prefix-keymaps-in-emacs/</guid>
      <description>&lt;p&gt;Or: Further Musings on the Tedium of Long Key-Chords.  In the past I&amp;rsquo;ve covered various bespoke approaches to the problem of repeating long key sequences: &lt;a href=&#34;https://github.com/magit/transient&#34;&gt;Transient&lt;/a&gt;, &lt;a href=&#34;https://github.com/abo-abo/hydra&#34;&gt;Hydra&lt;/a&gt;, &lt;a href=&#34;https://karthinks.com/software/it-bears-repeating/&#34;&gt;repeat-mode&lt;/a&gt; (and &lt;a href=&#34;https://tildegit.org/acdw/define-repeat-map.el&#34;&gt;repeat-mode&amp;rsquo;s helpers&lt;/a&gt;) require progressively less forethought and custom elisp chops to set up.  Today we continue our aggressive descent into laziness with the simplest way yet to use any Emacs key prefix as a springboard for one-key access to commands.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;A quick glossary&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;keymap&lt;/code&gt;: A &lt;em&gt;&amp;ldquo;keymap&amp;rdquo;&lt;/em&gt; is an Emacs data structure that maps a collection of keybindings (&lt;em&gt;i.e.&lt;/em&gt; keyboard shortcuts) to commands.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;key-chord&lt;/code&gt;: This is a sequence of keys, some or all of which can require modifier keys to be held down. Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;C-x C-f&lt;/code&gt; (&lt;code&gt;control + x&lt;/code&gt;, followed by &lt;code&gt;control + f&lt;/code&gt;), which runs the &lt;code&gt;find-file&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-c @ C-t&lt;/code&gt; (&lt;code&gt;control + c&lt;/code&gt;, &lt;code&gt;@&lt;/code&gt;, followed by &lt;code&gt;control + t&lt;/code&gt;), which runs the command &lt;code&gt;outline-hide-body&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Needless to say, these can get pretty tedious for repeated invocations, even if you avoid the modifiers by using Vim-style leader keys.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;prefix-key&lt;/code&gt;: Any &amp;ldquo;incomplete&amp;rdquo; part of a &lt;code&gt;key-chord&lt;/code&gt; that will cause Emacs to wait for further keyboard input. In the above examples, &lt;code&gt;C-x&lt;/code&gt;, &lt;code&gt;C-c&lt;/code&gt; and &lt;code&gt;C-c @&lt;/code&gt; are all prefix keys.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;&lt;code&gt;repeat-mode&lt;/code&gt;, Hydra, Hercules and Transient all enable variations of the following interaction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You (the user) define a special keymap &amp;ndash; a set of mappings from key bindings to commands,&lt;/li&gt;
&lt;li&gt;where the bindings are short and mnemonic/ergonomic,&lt;/li&gt;
&lt;li&gt;where the commands are related at some conceptual level in your mind,&lt;/li&gt;
&lt;li&gt;which are displayed in some kind of menu or table,&lt;/li&gt;
&lt;li&gt;and can be invoked in quick succession if required without exiting this menu.  Additionally,&lt;/li&gt;
&lt;li&gt;this menu (and associated editor state) can be enabled by using a dedicated keybinding, or&lt;/li&gt;
&lt;li&gt;(&lt;code&gt;repeat-mode&lt;/code&gt; only) by calling any one of these commands the long way.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The price you pay for this convenience is that you have to create this command group and specify the menu elements manually.  This is not a tall order if you only need a few such menus, and the results can be pretty neat.  In this situation these packages solve the tedium issue almost incidentally, since easing repetition is not even their primary purpose.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/repeat-help-toggle-transient.png&#34;
         alt=&#34;Figure 1: Pictured: A Transient for assorted tasks. Not pictured: Its long and messy definition.&#34; width=&#34;700px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Pictured: A Transient for assorted tasks. Not pictured: Its long and messy definition.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;As I&amp;rsquo;ve &lt;a href=&#34;https://karthinks.com/software/it-bears-repeating/&#34;&gt;written at length&lt;/a&gt; before, Emacs&amp;rsquo; built-in &lt;code&gt;repeat-mode&lt;/code&gt; straddles the divide between requiring a bespoke menu with associated elisp configuration and a minimally specified approach to repeating commands.&lt;/p&gt;
&lt;p&gt;But Emacs is full of prefix maps, and we still don&amp;rsquo;t have the ability to enter a persistent state &amp;ndash; on the fly and &lt;em&gt;without premeditation&lt;/em&gt; &amp;ndash; where an arbitrary keymap can be &amp;ldquo;activated&amp;rdquo; until we are done running or repeating commands in this map.&lt;/p&gt;
&lt;p&gt;As it turns out, a 90% solution for this is actually really straightforward, no &lt;code&gt;repeat-mode&lt;/code&gt; needed. With some inspiration from Embark:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;repeated-prefix-help-command&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;when-let*&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;keys&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;this-command-keys-vector&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;prefix&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;seq-take&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keys&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;1-&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keys&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;orig-keymap&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;key-binding&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prefix&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;accept-default&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;copy-keymap&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;orig-keymap&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;exit-func&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;set-transient-map&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;which-key-abort&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt; [&lt;span style=&#34;color:#963&#34;&gt;remap&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keyboard-quit&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;exit-func&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#963&#34;&gt;which-key--create-buffer-and-show&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;prefix-help-command&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;repeated-prefix-help-command&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s all of it.  Here&amp;rsquo;s how it works:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When you&amp;rsquo;ve typed &lt;em&gt;any&lt;/em&gt; prefix key (say &lt;code&gt;C-c @&lt;/code&gt;) and Emacs is waiting for further input, press &lt;code&gt;C-h&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Emacs now remembers whatever you&amp;rsquo;ve already typed, activates a &amp;ldquo;repeat state&amp;rdquo;
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
or &lt;code&gt;repeat-mode&lt;/code&gt;, as it were.  This is basically modal editing with bespoke modes.
&lt;/small&gt;&lt;/span&gt;
and a &lt;code&gt;which-key&lt;/code&gt; prompt/menu with available keybindings.&lt;/li&gt;
&lt;li&gt;You can now continue to call available commands in sequence without having to re-type the annoying prefix key.&lt;/li&gt;
&lt;li&gt;This state persists until you exit it with &lt;code&gt;C-g&lt;/code&gt; (bound to &lt;code&gt;keyboard-quit&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;details open&gt;
&lt;summary&gt;Note:&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;&lt;code&gt;which-key&lt;/code&gt; is only a visual aid here &amp;ndash; this works if you replace it with a different prompter or if you remove it from the code entirely.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Here is a demo of creating a &amp;ldquo;repeat state&amp;rdquo; on the fly, in this case for the ever annoying &lt;code&gt;outline-minor-mode&lt;/code&gt; commands on the &lt;code&gt;C-c @&lt;/code&gt; prefix. (The keypresses are shown at the top of the window.)&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/repeated-prefix-help-command.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/repeated-prefix-help-command.mp4&#34;&gt;[Repeated-prefix demo]&lt;/a&gt;&lt;/video&gt;
&lt;p&gt;In principle, &lt;code&gt;repeated-prefix-help-command&lt;/code&gt; functions similar to &lt;code&gt;repeat-mode&lt;/code&gt;, but with one difference.  The latter requires that you specify beforehand which prefix keymaps should automatically enter the &amp;ldquo;repeat state&amp;rdquo;, and define maps that group together related commands if they don&amp;rsquo;t exist already.  The above method lacks this automaticity, but is more flexible: you can enter this state at any time (and for any keymap) with an additional keypress (here &lt;code&gt;C-h&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;repeated-prefix-help-command&lt;/code&gt; also has an advantage over &lt;code&gt;repeat-mode&lt;/code&gt;: pressing keys that are not bound in the &amp;ldquo;repeat state&amp;rdquo; will cause &lt;code&gt;repeat-mode&lt;/code&gt; to end, and you will have to start over with the full, long key sequence to enter it again.
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Although this can be remedied with some monkey patching. See &lt;a href=&#34;https://github.com/karthink/repeat-help&#34;&gt;repeat-help&lt;/a&gt;.
&lt;/small&gt;&lt;/span&gt;
The keymap we activate above stays active until we call &lt;code&gt;keyboard-quit&lt;/code&gt;, so we can freely mix regular Emacs editing commands and the ones we have temporary one-key access to.&lt;/p&gt;
&lt;p&gt;We could, of course, use both approaches together.  We are approaching peak laziness, but I don&amp;rsquo;t think we&amp;rsquo;re there yet!&lt;/p&gt;
</description>
    </item><item>
      <title>Notmuch Ado About Nothing</title>
      <link>https://karthinks.com/software/notmuch-ado-about-nothing/</link>
      <pubDate>Wed, 27 Jul 2022 18:32:00 +0530</pubDate>
      
      <guid>https://karthinks.com/software/notmuch-ado-about-nothing/</guid>
      <description>&lt;p&gt;Addressing an &lt;a href=&#34;https://old.reddit.com/r/emacs/comments/w761d3/how_to_automatically_collapse_attachments_in/&#34;&gt;innocuous question&lt;/a&gt; about the Notmuch email client&amp;rsquo;s default behavior took me surprisingly deep into the bowels of the package code.  When the normal customization methods didn&amp;rsquo;t help, I realized it might be a good opportunity to live-code a solution.&lt;/p&gt;
&lt;p&gt;The hope was that it might outline a recipe for reaching into the elisp guts of any library and getting Emacs to do what you want &amp;ndash;  with no specific prior knowledge.  The reality is thirty minutes of fairly myopic yakshaving:&lt;/p&gt;
&lt;iframe width=&#34;700&#34; height=&#34;371&#34; src=&#34;https://www.youtube.com/embed/UP2dFk5_ytY&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;a href=&#34;https://www.youtube.com/embed/UP2dFk5_ytY&#34;&gt;[Video]&lt;/a&gt;&lt;/iframe&gt;</description>
    </item><item>
      <title>It Bears Repeating: Emacs 28 &amp; Repeat Mode</title>
      <link>https://karthinks.com/software/it-bears-repeating/</link>
      <pubDate>Tue, 05 Jul 2022 23:17:00 +0530</pubDate>
      
      <guid>https://karthinks.com/software/it-bears-repeating/</guid>
      <description>&lt;p&gt;Are you tired of pressing &lt;code&gt;C-x o&lt;/code&gt; repeatedly to switch to the window you want in Emacs? Or &lt;code&gt;M-g n&lt;/code&gt; and &lt;code&gt;M-g p&lt;/code&gt; to cycle through compile errors or grep matches? How about navigating outline headings with (yuck) &lt;code&gt;C-c @ C-n&lt;/code&gt; and &lt;code&gt;C-c @ C-p&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;The correct answer to the latter is that no one traverses headings this way, because these keybindings are atrocious. Even the shorter ones start to grate when you need to use them repeatedly in an editing session.&lt;/p&gt;
&lt;p&gt;Depending on their levels of comfort with Emacs, users typically deal with them in one of three ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;They aren&amp;rsquo;t aware of or don&amp;rsquo;t use these commands, or use the menu to access them.&lt;/li&gt;
&lt;li&gt;They rebind the ones they need elsewhere, to an easier to press but equally idiosyncratic location. After a few such short non-prefixed keybindings they run out of room on their keyboards.&lt;/li&gt;
&lt;li&gt;They use one of the many, many available helpers written with the &lt;a href=&#34;https://github.com/abo-abo/hydra&#34;&gt;Hydra&lt;/a&gt; or &lt;a href=&#34;https://github.com/magit/transient&#34;&gt;Transient&lt;/a&gt; packages for these.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But there&amp;rsquo;s a fourth option. Emacs 28 bundles a simple and hassle-free way to take the tedium out of these keybindings: Repeat Mode.&lt;/p&gt;
&lt;p&gt;Repeat Mode lets you call multiple commands in a keymap without repeating the prefix each time. So you can press&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;C-x o&lt;/code&gt;, &lt;code&gt;o&lt;/code&gt;, &lt;code&gt;o&lt;/code&gt;, &amp;hellip; to switch windows repeatedly. &lt;code&gt;O&lt;/code&gt; will cycle backwards.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-x u&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt;, &amp;hellip; to undo repeatedly,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-x @ C-n&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;f&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;,&amp;hellip; to traverse headings,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-g n&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;,&amp;hellip; to navigate errors or grep matches, and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With &lt;code&gt;repeat-mode&lt;/code&gt;  active, calling the prefix (&lt;code&gt;M-g&lt;/code&gt;) the first time &amp;ldquo;activates&amp;rdquo; the keymap, after which only the &amp;ldquo;base&amp;rdquo; key for a command (&lt;code&gt;n&lt;/code&gt; or &lt;code&gt;p&lt;/code&gt;)is needed.&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;Naming things is hard&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;In this write-up I&amp;rsquo;ll call all but the final part of a keybinding the &amp;ldquo;prefix&amp;rdquo;, and the final key or chord the &amp;ldquo;base&amp;rdquo; key.&lt;/p&gt;
&lt;p&gt;Example: &lt;code&gt;org-next-link&lt;/code&gt;, bound to  &lt;code&gt;C-c C-x C-n&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The prefix is &lt;code&gt;C-c C-x&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The base key is &lt;code&gt;C-n&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;details open&gt;
&lt;summary&gt;Repeating a single command&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;If you want to call a &lt;em&gt;single command&lt;/em&gt; repeatedly, &lt;code&gt;repeat-mode&lt;/code&gt; is not required. You can just call &lt;code&gt;M-x repeat&lt;/code&gt;, bound to &lt;code&gt;C-x z&lt;/code&gt; by default. This has been part of Emacs for ages. You can repeat invocations of the repeat command itself with just &lt;code&gt;z&lt;/code&gt;, so it&amp;rsquo;s &lt;code&gt;C-x z z z...&lt;/code&gt; to repeat the last command multiple times.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;In comparison to &lt;code&gt;M-x repeat&lt;/code&gt;, &lt;code&gt;repeat-mode&lt;/code&gt; shines when there&amp;rsquo;s a whole keymap of related commands with keys (like &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;f&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt; for outline navigation) under the same prefix (like &lt;code&gt;C-c @&lt;/code&gt; for &lt;code&gt;outline-minor-mode&lt;/code&gt;). In this video I switch windows, jump through Occur (grep) matches, navigate git-diff hunks
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
With &lt;code&gt;diff-hl-mode&lt;/code&gt;, which supports repeating commands out of the box.
&lt;/small&gt;&lt;/span&gt;
and call undo repeatedly with single key presses. The buffer on the right lists the keystrokes. Commands with the same prefix or repeated commands are single key presses:&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;1280&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/repeat-help-full-demo-gh.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/repeat-help-full-demo-gh.mp4&#34;&gt;[VIDEO]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;ul&gt;
&lt;li&gt;After the first invocation of &lt;code&gt;other-window&lt;/code&gt; (&lt;code&gt;C-x o&lt;/code&gt;), I switch windows with &lt;code&gt;o&lt;/code&gt; (and &lt;code&gt;O&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Next I find  &lt;code&gt;occur&lt;/code&gt; -ences  of the phrase &amp;ldquo;repeat-mode&amp;rdquo; in the buffer. The &lt;code&gt;next-error&lt;/code&gt; (&lt;code&gt;M-g n&lt;/code&gt;) and &lt;code&gt;previous-error&lt;/code&gt; (&lt;code&gt;M-g p&lt;/code&gt;) commands jump through the matches. I only need to type the prefix (&lt;code&gt;M-g&lt;/code&gt;) once.&lt;/li&gt;
&lt;li&gt;I call &lt;code&gt;diff-hl-previous-hunk&lt;/code&gt; from the end of the buffer to jump to modified hunks in this version-controlled document. This is provided by the &lt;code&gt;diff-hl&lt;/code&gt; package. Again, I only type in the prefix (&lt;code&gt;C-x v&lt;/code&gt;  in my configuration) once.&lt;/li&gt;
&lt;li&gt;I mark a modified hunk with &lt;code&gt;SPC&lt;/code&gt; &amp;ndash; corresponding to the full version  &lt;code&gt;C-x v SPC&lt;/code&gt;. Then I call &lt;code&gt;undo&lt;/code&gt; a few times. As a bonus, undo in Emacs is limited to the active region.&lt;/li&gt;
&lt;li&gt;After the first invocation of the &lt;code&gt;C-x&lt;/code&gt; prefix, undo is just &lt;code&gt;u&lt;/code&gt;. This is simpler than holding down Control to press &lt;code&gt;C-/&lt;/code&gt;, the other undo binding, a bunch of times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Repeat Mode comes with built-in support for a bunch of keymaps. There&amp;rsquo;s no learning curve, &lt;code&gt;M-x repeat-mode&lt;/code&gt; and you&amp;rsquo;re set. You&amp;rsquo;ll wonder how you lived without it.&lt;/p&gt;
&lt;h2 id=&#34;what-s-in-a-keymap&#34;&gt;What&amp;rsquo;s in a keymap&lt;/h2&gt;
&lt;p&gt;Before we dive into Repeat Mode proper, let&amp;rsquo;s address the issue of creating an easily repeatable command using Emacs&amp;rsquo; base API.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;&amp;ldquo;keymap&amp;rdquo;&lt;/em&gt; is a data structure that maps a collection of keybindings (&lt;em&gt;i.e.&lt;/em&gt; keyboard shortcuts) to commands. Let&amp;rsquo;s call each element of this map a &lt;em&gt;&amp;ldquo;binding&amp;rdquo;&lt;/em&gt;. Any number of keymaps can be &lt;em&gt;&amp;ldquo;active&amp;rdquo;&lt;/em&gt; at a time in Emacs, meaning that typing a keybinding will run some command that it&amp;rsquo;s mapped to in these keymaps. Which command runs is a question of which keymap is looked up first.&lt;/p&gt;
&lt;p&gt;For our purposes, a &lt;em&gt;&amp;ldquo;transient keymap&amp;rdquo;&lt;/em&gt; is one that&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;takes priority over all other keymaps, and&lt;/li&gt;
&lt;li&gt;disappears after a keypress unless unless you explicitly ask it to stick around.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we want to make a  key run a command no matter what other keymaps are active, we can use a transient keymap. If we want this keymap to stick around until some arbitrary condition is met, we can do that too. Putting these ideas together lets us add a &amp;ldquo;repeat&amp;rdquo; feature to any command.&lt;/p&gt;
&lt;p&gt;For example, I &lt;a href=&#34;../dealing-with-window-clutter-in-emacs&#34;&gt;cycle through popup buffers &lt;/a&gt; in Emacs with the key &lt;code&gt;C-M-`&lt;/code&gt;, or Control, Alt and the grave key chorded together. This calls the &lt;code&gt;popper-cycle&lt;/code&gt; command. Needless to say, this isn&amp;rsquo;t very conducive to repeated invocations. So I activate a transient-keymap after each call to &lt;code&gt;popper-cycle&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;popper-cycle&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:after&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/popper-cycle-repeated&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;_&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Continue to cycle popups with the grave key.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;set-transient-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;make-sparse-keymap&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;`&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;popper-cycle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This keymap binds &lt;code&gt;popper-cycle&lt;/code&gt; to the grave key, and it stays active for exactly one keypress. Typing the grave key thus calls &lt;code&gt;popper-cycle&lt;/code&gt; again, or I can break this chain by doing anything else. (Note: This is a terrible way to do it!&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;)&lt;/p&gt;
&lt;p&gt;The logic used by Repeat Mode is quite different, but the effect is similar. In its simplest form, binding a shared set of commands to a transient map is how you could add a &amp;ldquo;repeat&amp;rdquo; functionality to the set.&lt;/p&gt;
&lt;h2 id=&#34;adding-repeat-mode-support-to-keymaps&#34;&gt;Adding &lt;code&gt;repeat-mode&lt;/code&gt; support to keymaps&lt;/h2&gt;
&lt;p&gt;Repeat Mode supports a few keymaps out of the box, including all the ones in my demo above.&lt;/p&gt;
&lt;p&gt;To add Repeat Mode support to commands in a keymap, you add a &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Symbol-Properties.html&#34;&gt;symbol property&lt;/a&gt; to each command. Here&amp;rsquo;s support for the completely unpressable &lt;code&gt;smerge-mode&lt;/code&gt; commands:
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
See below for a demo.
&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;map-keymap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;_key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbolp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-map&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;smerge-basic-map&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#963&#34;&gt;smerge-basic-map&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is simple enough that we can shove it into a function that repeat-izes keymaps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;repeatize&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Add &lt;/span&gt;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;`repeat-mode&amp;#39;&lt;/span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt; support to a KEYMAP.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;map-keymap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;_key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbolp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-map&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbol-value&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &amp;ldquo;repeat&amp;rdquo; state is shared between commands that are (i) bound in a keymap, and (ii) have the keymap  as their  &lt;code&gt;repeat-map&lt;/code&gt; symbol property. But what if the commands you want to repeat aren&amp;rsquo;t defined on top of a prefix, unlike all the above examples? Or if the commands we want to group aren&amp;rsquo;t part of a single keymap to begin with? Then this is a two step process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Bind your commands of interest in some keymap,  to short keys if necessary.&lt;/li&gt;
&lt;li&gt;Attach the keymap name as a symbol property to all of them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For instance, suppose you&amp;rsquo;d  like to be able to Isearch repeatedly with just &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;r&lt;/code&gt; instead of hammering &lt;code&gt;C-s&lt;/code&gt; over and over. To do this you can bind them to short keys in a keymap, and attach the keymap name to the commands&amp;rsquo; &lt;code&gt;repeat-map&lt;/code&gt; symbol properties:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;isearch-repeat-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;make-sparse-keymap&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;s&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;isearch-repeat-forward&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;isearch-repeat-backward&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;isearch-repeat-forward&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;isearch-repeat-backward&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-map&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;isearch-repeat-map&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: You&amp;rsquo;re not going to have trouble typing &amp;ldquo;s&amp;rdquo; or &amp;ldquo;r&amp;rdquo; as part of the search string, even after you&amp;rsquo;ve begun the search with  &lt;code&gt;C-s&lt;/code&gt; &amp;ndash; it&amp;rsquo;s only the repeated invocations (isearch-&lt;em&gt;repeat&lt;/em&gt;-forward)  that are shortened!&lt;/p&gt;
&lt;p&gt;This is a somewhat low-level (though simple) operation and the recipe is fairly constant. So we could package it in a macro  for ease of use&amp;hellip; but we don&amp;rsquo;t have to. There are already multiple packages that let you specify commands to be repeated along with their short keys. Here are a few:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://tildegit.org/acdw/define-repeat-map.el&#34;&gt;define-repeat-map&lt;/a&gt; by &lt;a href=&#34;https://www.acdw.net/&#34;&gt;Case Duckworth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mmarshall540/repeaters&#34;&gt;repeaters&lt;/a&gt; by &lt;a href=&#34;https://github.com/mmarshall540&#34;&gt;mmarshall540&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/jjzmajic/hercules.el&#34;&gt;Hercules&lt;/a&gt; by &lt;a href=&#34;https://gitlab.com/jjzmajic&#34;&gt;jjzmajic&lt;/a&gt;, an external package that bypasses the whole &lt;code&gt;repeat-mode&lt;/code&gt; system and lets you define repeat functionality for any keymap.&lt;/li&gt;
&lt;/ol&gt;
&lt;details open&gt;
&lt;summary&gt;Making repeat-maps: Emacs 29 update&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;p&gt;Emacs 29 introduces &lt;code&gt;defvar-keymap&lt;/code&gt;, making it easier to define keymaps with the &lt;code&gt;repeat-map&lt;/code&gt; property attached:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;defvar-keymap&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;hl-todo-repeat-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#007020&#34;&gt;:repeat&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;hl-todo-next&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;hl-todo-previous&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;o&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;hl-todo-occur&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, for finer control over when the repeat-map is (de)activated,&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;defvar-keymap&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;hl-todo-repeat-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#007020&#34;&gt;:repeat&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;:enter&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;hl-todo-insert&lt;/span&gt;) &lt;span style=&#34;color:#007020&#34;&gt;:exit&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;hl-todo-occur&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;hl-todo-next&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;hl-todo-previous&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;o&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;hl-todo-occur&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which specifies that using &lt;code&gt;hl-=todo-insert&lt;/code&gt; should activate the repeat-map and  &lt;code&gt;hl-todo-occur&lt;/code&gt; should deactivate it.&lt;/p&gt;
&lt;p&gt;Note that turning an existing keymap into a repeat-map or adding this behavior to individual commands still requires one of the above helpers, like &lt;code&gt;repeatize&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;With any of these packages you could develop the above idea into a complete modal editing environment &amp;ndash; like &lt;a href=&#34;https://github.com/emacsorphanage/god-mode&#34;&gt;God Mode&lt;/a&gt;, but with custom modes for specialized editing tasks. Even at a more basic level, you can go wild here, placing all commands into repeat maps: Why delete words with &lt;code&gt;M-d&lt;/code&gt; or &lt;code&gt;M-DEL&lt;/code&gt; five times when you can just do &lt;code&gt;M-d d d d d&lt;/code&gt;? Why cycle through the kill-ring with &lt;code&gt;M-y&lt;/code&gt;  when you can just yank and cycle with &lt;code&gt;C-y y y y...&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure about taking it that far. For one, it&amp;rsquo;s simpler to use digit arguments: &lt;code&gt;M-5 M-d&lt;/code&gt; is shorter and possibly faster to type. Second, many commands that involve more than three levels of &amp;ldquo;cycling&amp;rdquo; are better served by a menu with choices, &lt;em&gt;i.e.&lt;/em&gt; a &lt;code&gt;completing-read&lt;/code&gt; interface or an &lt;a href=&#34;../avy-can-do-anything&#34;&gt;Avy selection&lt;/a&gt;. I&amp;rsquo;ve found that the returns diminish and the common issues with modality start to surface as the repeat maps become more  expansive.&lt;/p&gt;
&lt;p&gt;Repeat maps appear to be best suited for families of related commands that are usually invoked in succession and are cumbersome to invoke. Pretty much exactly what folks use Hydras or (more lately) Transients for, which brings us to&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;repeat-mode-vs-hydra-transient-and-hercules&#34;&gt;Repeat Mode vs Hydra, Transient and Hercules&lt;/h2&gt;
&lt;p&gt;Repeat Mode has a few advantages when compared to Hydras/Transients&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; for repeating commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There&amp;rsquo;s no special definition or code to write, maintain or copy: it just works.&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s only one set of keys defined for a command: You can use the same full keybinding with or without Repeat Mode active.&lt;/li&gt;
&lt;li&gt;You can rebind both the prefix and the base keys without losing the repeat behavior.&lt;/li&gt;
&lt;li&gt;Repeat Mode has support for many prefix maps out of the box, and adding support for new maps is easy, see below.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s built into Emacs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Hercules package shares many of these advantages, since it too uses existing keymaps as the basis for a repeat interface. However, Repeat Mode is more minimal in its configuration and presentation, does not depend on Which Key, and does not offer a fancy key hinting system out of the box.&lt;/p&gt;
&lt;p&gt;With all of the above alternatives, you still need to invoke the mode somehow. With &lt;code&gt;repeat-mode&lt;/code&gt; this requires pressing the unwieldy prefix key &lt;em&gt;once&lt;/em&gt;: &lt;code&gt;C-c @&lt;/code&gt; for &lt;code&gt;outline-minor-mode&lt;/code&gt;, &lt;code&gt;C-c ^&lt;/code&gt; for &lt;code&gt;smerge-mode&lt;/code&gt;, and so on. This is cause enough for rebinding them somewhere convenient, perhaps to the &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Key-Binding-Conventions.html&#34;&gt;user-reserved&lt;/a&gt; &lt;code&gt;C-c o&lt;/code&gt; (for outline) and &lt;code&gt;C-c m&lt;/code&gt; (for merge). Or under a leader key if you use &lt;code&gt;evil-mode&lt;/code&gt;. &lt;strong&gt;Note that you have to do this with a Hydra/Transient as well.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are disadvantages to Repeat Mode too. First, Hydras/Transients are incredibly versatile, and repeating commands isn&amp;rsquo;t even in the top three problems they solve. Using them for repeating commands is like using an elephant gun to hunt a mouse.&lt;/p&gt;
&lt;p&gt;They can be full fledged suites combining settings and bespoke commands that don&amp;rsquo;t have much in common. For example, here&amp;rsquo;s a Transient I use to toggle minor-modes in Emacs:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/repeat-help-toggle-transient.png&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;And another to resize or clip a video with &lt;code&gt;ffmpeg&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/repeat-help-transient-2.png&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Basically, Transients have &lt;em&gt;state&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In contrast, Repeat Mode only aims to save your fingers some work. You &lt;em&gt;can&lt;/em&gt; gather disparate commands under the same umbrella map for use with &lt;code&gt;repeat mode&lt;/code&gt;, but it gets out of hand rather quickly. So we will limit ourselves to the intended patterns of Repeat Mode usage in this write-up.&lt;/p&gt;
&lt;p&gt;Second, Hydras can stay alive while you press keys not in the keymap. This means you can (usually) move the cursor around to where you next want to call a Hydra command.  You can add this behavior to Repeat Mode with some creative use of &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Inheritance-and-Keymaps.html&#34;&gt;composed keymaps&lt;/a&gt;, but by default the prefix map does not stay active if you call a non-keymap command. Again, I&amp;rsquo;m going to hew to the default scope of Repeat Mode here.&lt;/p&gt;
&lt;p&gt;Finally, &lt;code&gt;repeat-mode&lt;/code&gt; prompts you with available keys in the echo area, but not what commands they&amp;rsquo;re bound to:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/repeat-help-basic-auto.png&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is generally sufficient, but I could use a Which Key style menu for rarely used keymaps with lots of keys (like &lt;code&gt;smerge-mode&lt;/code&gt;). As it turns out, this is quite straightforward to add.&lt;/p&gt;
&lt;h2 id=&#34;adding-a-hydra-like-prompt-to-repeat-mode&#34;&gt;Adding a Hydra-like prompt to Repeat Mode&lt;/h2&gt;
&lt;p&gt;If you prefer an explicit and persistent menu of available keys/commands &amp;ndash; like a Hydra or Transient menu &amp;ndash; you can produce a menu using Which Key or an Embark prompter when calling a relevant command:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/repeat-help-which-key-auto.png&#34; width=&#34;1000px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Doing this is quite simple: we disable the built-in hint display and advise the function that sets the transient keymap after a &amp;ldquo;repeatable key&amp;rdquo; is pressed. Here&amp;rsquo;s the Which Key version:
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
This code creates a closure, so remember to &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Using-Lexical-Binding.html&#34;&gt;enable lexical-binding&lt;/a&gt; where it&amp;rsquo;s placed.
&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; Disable the built-in repeat-mode hinting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;custom-set-variables&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;repeat-echo-function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;ignore&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; Spawn or hide a which-key popup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-post-hook&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:after&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;repeat-help--which-key-popup&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#963&#34;&gt;if-let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;this-command&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;real-this-command&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;repeat-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   (&lt;span style=&#34;color:#963&#34;&gt;repeat--command-property&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-map&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;run-at-time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#963&#34;&gt;which-key--create-buffer-and-show&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbol-value&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;which-key--hide-popup&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Specifically, we schedule the which-key popup on the main event loop. (&lt;strong&gt;Emacs&lt;/strong&gt;: Making things happen when other things happen™.)&lt;/p&gt;
&lt;p&gt;In action, applied to the &lt;code&gt;smerge-mode&lt;/code&gt; keymap when performing a Git merge:&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;1000&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/repeat-help-smerge-which-key-demo.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/repeat-help-smerge-which-key-demo.mp4&#34;&gt;[VIDEO]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;ul&gt;
&lt;li&gt;Open a file with merge conflicts.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;smerge-previous&lt;/code&gt; (&lt;code&gt;C-c m p&lt;/code&gt; in my configuration) to go to the beginning of a hunk. This &amp;ldquo;activates&amp;rdquo; the keymap and the Which Key pop up.&lt;/li&gt;
&lt;li&gt;Jump through conflict regions with &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Resolve conflicts by picking the upper (&lt;code&gt;u&lt;/code&gt;) or lower (&lt;code&gt;l&lt;/code&gt;) regions.&lt;/li&gt;
&lt;li&gt;Save the buffer. This quits the repeat map and the popup.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;The code to produce a suitable Embark indicator involves a little more book-keeping, but the idea is the same: Schedule a keymap display when a repeatable command is invoked and remove it once it&amp;rsquo;s not relevant any more.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; Disable the built-in repeat-mode hinting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;custom-set-variables&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;repeat-echo-function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;ignore&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;repeat-help--embark-indicate&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;if-let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;this-command&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;real-this-command&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;repeat-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#963&#34;&gt;repeat--command-property&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-map&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;run-at-time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#007020&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;bufname&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;*Repeat Commands*&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;embark-verbose-indicator-buffer-sections&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;bindings&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;embark--verbose-indicator-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;bufname&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#963&#34;&gt;embark-verbose-indicator-display-action&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;display-buffer-at-bottom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#963&#34;&gt;window-height&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;fit-window-to-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;window-parameters&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;no-other-window&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                         (&lt;span style=&#34;color:#963&#34;&gt;mode-line-format&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;funcall&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#963&#34;&gt;embark-verbose-indicator&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbol-value&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;keymap&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;other-window-scroll-buffer&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;bufname&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#963&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;win&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-buffer-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;*Repeat Commands*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;visible&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;kill-buffer&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;window-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;win&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;delete-window&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;win&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-post-hook&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;repeat-help--embark-indicate&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s what it produces:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/repeat-help-embark-auto.png&#34; width=&#34;1000px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;If these are too busy, you might prefer to toggle the prompter on demand. There are only a few keymaps I need hints to use, so I bind the popup key to &lt;code&gt;C-h&lt;/code&gt;. Here I jump between modified hunks in a version controlled document and examine and stage them for committing using the Embark popup/indicator as a guide. Keep an eye on the key/command description at the top of the window:&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;600&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/repeat-help-embark-manual.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=https://karthinks.com/img/repeat-help-embark-manual.mp4&#34;&gt;[VIDEO]&lt;/a&gt;&lt;/video&gt;
&lt;details&gt;
&lt;summary&gt;Play by play&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;ul&gt;
&lt;li&gt;Call &lt;code&gt;diff-hl-next-hunk&lt;/code&gt;, which I&amp;rsquo;ve bound to &lt;code&gt;C-x v n&lt;/code&gt; . This is the only time I type the prefix &lt;code&gt;C-x v&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Jump between modified hunks in the document with &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt;, which would be &lt;code&gt;C-x v n&lt;/code&gt; and &lt;code&gt;C-x v p&lt;/code&gt; without &lt;code&gt;repeat-mode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bring up the Embark key description popup with &lt;code&gt;C-h&lt;/code&gt;. I toggle it a couple of times.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;diff-hl-show-hunk&lt;/code&gt; with &lt;code&gt;*&lt;/code&gt;, and stage the previous hunk with &lt;code&gt;S&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Perform an action that ends the &lt;code&gt;repeat-mode&lt;/code&gt; chain, in this case by yanking some text into the buffer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;The key description popup does not need to be cancelled: it automatically disappears when you run any command that&amp;rsquo;s not in the keymap, such as inserting text. (This is regular  behavior for transient keymaps in Emacs.)&lt;/p&gt;
&lt;p&gt;Both indicators (Embark and Which Key) and both kinds of behavior (auto-popup or toggle on demand) are available in &lt;a href=&#34;https://github.com/karthink/repeat-help&#34;&gt;Repeat Help&lt;/a&gt;, a package I wrote to get a simplified Hydra-like prompt for repeat maps. The prompt interface is basic but generic, so any function that can list a keymap&amp;rsquo;s entries can be plugged in.&lt;/p&gt;
&lt;h2 id=&#34;command-smells&#34;&gt;Command smells&lt;/h2&gt;
&lt;p&gt;To find  other commands or keymaps that could use repeat-izing, we can look for a code smell:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Any command that has &amp;ldquo;next&amp;rdquo;, &amp;ldquo;forward&amp;rdquo;, &amp;ldquo;previous&amp;rdquo; or &amp;ldquo;backward&amp;rdquo; in the name is fair game. For reasons alluded to above, this excludes common commands like &lt;code&gt;next-line&lt;/code&gt; or &lt;code&gt;forward-word&lt;/code&gt;: jumping across text is better solved by Isearch or Avy.
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
These do other useful things besides, like pushing the mark and letting you act on the region you jumped across.
&lt;/small&gt;&lt;/span&gt;
But something contextual like &lt;code&gt;org-next-link&lt;/code&gt; is fair game:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;org-link-repeat-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;make-sparse-keymap&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-next-link&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-previous-link&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#963&#34;&gt;org-next-link&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;org-previous-link&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-map&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-link-repeat-map&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s surprising that link navigation isn&amp;rsquo;t already part of &lt;a href=&#34;https://orgmode.org/manual/Speed-Keys.html&#34;&gt;Org Speed Keys&lt;/a&gt;, which is included in Org Mode.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Any predictable sequence of actions that forms a &amp;ldquo;task&amp;rdquo; is a good candidate. Smerge Mode is a good example. In its most basic usage you jump to each merge conflict, pick one of three choices and repeat. Critically, it has to be a sequence of actions carried out in (or across) an editable buffer. In &lt;code&gt;read-only-mode&lt;/code&gt; buffers like help windows or mail clients, most relevant commands are already bound to single key presses at the top level.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Any command that tweaks an analog setting will need to be repeated. Setting the text scale (&lt;code&gt;C-x C-=&lt;/code&gt; ) or  window width (&lt;code&gt;C-x {&lt;/code&gt;), for instance. Fortunately these are already handled by Repeat Mode.&lt;/p&gt;
&lt;p&gt;But other built-in libraries like Windmove, for which Hydras are usually written, can be repeat-ized instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;windmove-repeat-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;make-sparse-keymap&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;left&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-left&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;S-&amp;lt;left&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-swap-states-left&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;right&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-right&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;S-&amp;lt;right&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-swap-states-right&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;up&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-up&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;S-&amp;lt;up&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-swap-states-up&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;down&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-down&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;S-&amp;lt;down&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-swap-states-down&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#963&#34;&gt;map&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;map-keymap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;_key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#007020&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;symbolp&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;cmd&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;repeat-map&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;windmove-repeat-map&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#963&#34;&gt;windmove-repeat-map&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now you can continue to move across or rearrange windows with the arrow keys after calling any Windmove command.&lt;/p&gt;
&lt;h2 id=&#34;dot-dot-dot-but-i-repeat-myself&#34;&gt;&amp;hellip;but I repeat myself&lt;/h2&gt;
&lt;p&gt;Keybindings are typically where modal editing paradigms have an advantage. Indeed, most repeated invocations in Vim &amp;ndash; like searching forward with &lt;code&gt;n&lt;/code&gt; , &lt;code&gt;f&lt;/code&gt; or &lt;code&gt;;&lt;/code&gt;&amp;ndash; are single key presses. But here too I had to rebind keys to switch windows (&lt;code&gt;C-w j&lt;/code&gt;  etc) to use it comfortably over a long editing session.&lt;/p&gt;
&lt;p&gt;The question remained: Why do I need to press so many keys to do the same few things? After failing to gel with the Hydra paradigm, I had been manually setting up transient keymaps (with &lt;code&gt;set-transient-map&lt;/code&gt;) to speed up consecutive calls for a bunch of commands. Placing them behind a uniform interface is a welcome addition. Repeat Mode is a small feature that solves a small problem, but with a big cumulative impact on my experience of using Emacs.&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;Technically there&amp;rsquo;s one more approach: Use bespoke solutions like &lt;code&gt;ace-window&lt;/code&gt; to switch windows. But in terms of a general approach it&amp;rsquo;s just these three.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;Setting a new transient keymap on each call is actually a wasteful way of producing this effect! Instead, you can set a transient keymap just once but instruct it to stay active as long as the only key pressed is grave.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;It makes sense that the Transient package is called that, since Transients (the menus Magit uses) are &amp;ldquo;just&amp;rdquo; souped-up transient maps, the way a Komodo dragon is just a lizard. But it causes no end of confusion when talking about them. Here I refer to a regular Emacs transient map in lowercase and the Magit-style popup-menu variety in uppercase.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item><item>
      <title>Scaling Latex previews in Emacs</title>
      <link>https://karthinks.com/software/scaling-latex-previews-in-emacs/</link>
      <pubDate>Fri, 25 Feb 2022 02:39:00 +0530</pubDate>
      
      <guid>https://karthinks.com/software/scaling-latex-previews-in-emacs/</guid>
      <description>&lt;p&gt;This is a post in my &lt;a href=&#34;https://karthinks.com/tags/latex&#34;&gt;Latex editing series&lt;/a&gt;, an awkward solution to a tiny problem.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;A common issue with &lt;a href=&#34;https://karthinks.com/software/latex-input-for-impatient-scholars/#in-buffer-previews--m-x-preview-buffer&#34;&gt;Latex previews in Emacs&lt;/a&gt;: The preview images don&amp;rsquo;t scale when you rescale text in &lt;code&gt;latex-mode&lt;/code&gt; or &lt;code&gt;org-mode&lt;/code&gt;:&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/org-scale-latex-demo-pre.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=&#34;https://karthinks.com/img/org-scale-latex-demo-pre.mp4&#34;&gt;[VIDEO]&lt;/a&gt;
&lt;/video&gt;
&lt;p&gt;&lt;small&gt;&lt;a href=&#34;https://karthinks.com/img/org-scale-latex-demo-pre.mp4&#34;&gt;Direct link to video&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;This makes it cumbersome to work with Latex math in Emacs when dealing with different sized monitors or when presenting from Emacs with &lt;a href=&#34;https://github.com/takaxp/org-tree-slide&#34;&gt;Org Tree Slide&lt;/a&gt;, for example.&lt;/p&gt;
&lt;p&gt;A good solution would be to re-render these fragment images at a higher resolution when applying text scaling. The current version of org-mode (9.52 as of this writing) is very slow to render Latex previews and locks up Emacs for a while, this is not a workable solution.&lt;/p&gt;
&lt;p&gt;There are a couple of ways this could be improved: For Org, call an async process to render Latex fragments, or better yet, reuse AucTeX&amp;rsquo;s &lt;code&gt;preview-latex&lt;/code&gt; library for fast, near instant updates.
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Instant Org previews with preview-latex are now feasible, see the &lt;a href=&#34;https://karthinks.com/software/fast-latex-previews-in-org-mode/&#34;&gt;next post&lt;/a&gt; in this series.
&lt;/small&gt;&lt;/span&gt;
For Latex, adjust the &lt;code&gt;preview-scale&lt;/code&gt; variable and regenerate the fragments at each new text scale. These are projects for another day, or for someone more proficient.&lt;/p&gt;
&lt;h2 id=&#34;the-hack&#34;&gt;The Hack&lt;/h2&gt;
&lt;p&gt;After asking around for an alternative, I settled on writing a big ol&amp;rsquo; hack: Just zoom in on the preview images when increasing the text scale:&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/org-scale-latex-demo.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;a href=&#34;https://karthinks.com/img/org-scale-latex-demo.mp4&#34;&gt;[VIDEO]&lt;/a&gt;
&lt;/video&gt;
&lt;p&gt;&lt;small&gt;&lt;a href=&#34;https://karthinks.com/img/org-scale-latex-demo.mp4&#34;&gt;Direct link to video&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;This is fast and cheap, but the downside is that the images get blurry:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://karthinks.com/img/org-scale-latex-blur.png&#34; width=&#34;700px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Using SVG fragments can mitigate this problem, at least for Org previews:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;org-preview-latex-default-process&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;dvisvgm&lt;/span&gt;) &lt;span style=&#34;color:#888&#34;&gt;;No blur when scaling&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-recipe&#34;&gt;The Recipe&lt;/h2&gt;
&lt;p&gt;Preview images are handled using &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Overlays.html&#34;&gt;overlays&lt;/a&gt;, so the image scaling is done by scanning for and adjusting appropriate overlay properties when changing the text scale:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/text-scale-adjust-latex-previews&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Adjust the size of latex preview fragments when changing the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;buffer&amp;#39;s text scale.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;major-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;latex-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#007020&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;overlays-in&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point-min&lt;/span&gt;) (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point-max&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;overlay-get&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;category&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;preview-overlay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;my/text-scale--resize-fragment&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#007020&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;overlays-in&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point-min&lt;/span&gt;) (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;point-max&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;overlay-get&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-overlay-type&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;org-latex-overlay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#963&#34;&gt;my/text-scale--resize-fragment&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;my/text-scale--resize-fragment&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;overlay-put&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;display&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;plist-put&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;cdr&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;overlay-get&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;ov&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;display&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#007020&#34;&gt;:scale&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;1.0&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.25&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;text-scale-mode-amount&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;text-scale-mode-hook&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;my/text-scale-adjust-latex-previews&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item><item>
      <title>Dired history in Emacs</title>
      <link>https://karthinks.com/software/dired-history-in-emacs/</link>
      <pubDate>Thu, 24 Feb 2022 01:33:00 -0800</pubDate>
      
      <guid>https://karthinks.com/software/dired-history-in-emacs/</guid>
      <description>&lt;p&gt;Emacs is reasonably consistent across its major-modes in its common usage patterns and keybindings. For example, &lt;code&gt;C-M-a&lt;/code&gt; and &lt;code&gt;C-M-e&lt;/code&gt; consistently move you to the beginnings and ends of functions in various language modes, and &lt;code&gt;C-c C-z&lt;/code&gt; moves the focus to REPLs and back. In read-only modes &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt; move the cursor up and down, and &lt;code&gt;w&lt;/code&gt; generally copies the path, address or URL of the buffer to the kill ring.&lt;/p&gt;
&lt;p&gt;One of these consistent (but less well known) keybindings is for going back and forward across nodes in a tree, arranged into a list: &lt;code&gt;l&lt;/code&gt; and &lt;code&gt;r&lt;/code&gt; traverse your history and &amp;ldquo;forward&amp;rdquo; history of visited help pages in &lt;code&gt;help-mode&lt;/code&gt;, info nodes in &lt;code&gt;Info-mode&lt;/code&gt;
&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;
Info mode takes this further. &lt;code&gt;L&lt;/code&gt; gives you an index of your visited nodes, which is itself placed into history!
&lt;/small&gt;&lt;/span&gt;
, web pages in &lt;code&gt;eww&lt;/code&gt;, locations in &lt;code&gt;pdf-tools&lt;/code&gt; and probably others. I think of this as moving [l]eft or [r]ight across a traversal path.&lt;/p&gt;
&lt;p&gt;But there are some omissions. I frequently find myself using &lt;code&gt;l&lt;/code&gt; and &lt;code&gt;r&lt;/code&gt; in dired buffers to navigate my history of visited dired buffers, where it annoyingly does nothing. I assumed this feature would be part of one of the many, many Emacs packages that extend dired, but while there are big total makeovers (like &lt;a href=&#34;https://github.com/ralesi/ranger.el&#34;&gt;ranger.el&lt;/a&gt;) for dired that include it, there wasn&amp;rsquo;t anything simple.&lt;/p&gt;
&lt;p&gt;So I wrote a helper: &lt;a href=&#34;https://github.com/karthink/dired-hist&#34;&gt;dired-hist&lt;/a&gt;. It&amp;rsquo;s very basic (&amp;lt; 50 LOC) and will remain so, although I might add some customization options in time.&lt;/p&gt;
</description>
    </item><item>
      <title>An Elisp Editing Tip</title>
      <link>https://karthinks.com/software/an-elisp-editing-tip/</link>
      <pubDate>Sun, 24 Oct 2021 14:00:00 +0530</pubDate>
      
      <guid>https://karthinks.com/software/an-elisp-editing-tip/</guid>
      <description>&lt;p&gt;One of the first things new Emacs users learn is the &lt;code&gt;eval-last-sexp&lt;/code&gt; (&lt;code&gt;C-x C-e&lt;/code&gt;) command and that Emacs can interpret elisp &lt;em&gt;anywhere&lt;/em&gt; it appears. Here&amp;rsquo;s a quick tip about using this command when writing elisp that you may not have discovered.&lt;/p&gt;
&lt;p&gt;If you call it with a prefix (&lt;code&gt;C-u&lt;/code&gt;) argument, it prints (or attempts to print) the result in place in the buffer. Better yet, call it with an argument of &lt;code&gt;0&lt;/code&gt; (&lt;code&gt;C-0 C-x C-e&lt;/code&gt;) to avoid truncating longer results.&lt;/p&gt;
&lt;p&gt;Variables evaluate to their values, so here it prints the current values of these variables:&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/eval-last-sexp-demo-3.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://karthinks.com/img/eval-last-sexp-demo-3.mp4&#34;&gt;[VIDEO]&lt;/a&gt;&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;This is handy when writing elisp, for example if you want to tweak the current value of a variable:&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/eval-last-sexp-demo-1.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://karthinks.com/img/eval-last-sexp-demo-1.mp4&#34;&gt;[VIDEO]&lt;/a&gt;&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;I replace &lt;code&gt;eval-last-sexp&lt;/code&gt; everywhere with &lt;code&gt;pp-eval-last-sexp&lt;/code&gt;, which produces a cleaner result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;global-set-key&lt;/span&gt; [&lt;span style=&#34;color:#963&#34;&gt;remap&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;eval-last-sexp&lt;/span&gt;] &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;pp-eval-last-sexp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;video style=&#34;center&#34; width=&#34;700&#34; controls&gt;
&lt;source src=&#34;https://karthinks.com/img/eval-last-sexp-demo-2.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://karthinks.com/img/eval-last-sexp-demo-2.mp4&#34;&gt;[VIDEO]&lt;/a&gt;&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;That is all.&lt;/p&gt;
</description>
    </item><item>
      <title>Declickbait Elfeed</title>
      <link>https://karthinks.com/software/declickbait-elfeed/</link>
      <pubDate>Mon, 11 Oct 2021 05:27:00 -0700</pubDate>
      
      <guid>https://karthinks.com/software/declickbait-elfeed/</guid>
      <description>&lt;p&gt;Using an RSS reader instead of visiting Youtube or other social media has many advantages, including that you have to deal with much less energy-sapping, will-eroding clickbait. Unfortunately feed entries can still have clickbaity titles that can DESTROY your patience! So I wrote a dumb-as-rocks declickbaiter for Elfeed. You WON&amp;rsquo;T BELIEVE the results!&lt;/p&gt;
&lt;p&gt;The Before (The After will SHOCK you!):
&lt;img src=&#34;https://karthinks.com/img/declickbait-before-extra.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The After:
&lt;img src=&#34;https://karthinks.com/img/declickbait-after-extra.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The Code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#963&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;elfeed-new-entry-hook&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;elfeed-declickbait-entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-declickbait-entry&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;title&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;elfeed-entry-title&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;entry&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;elfeed-meta&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;entry&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;:title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#963&#34;&gt;elfeed-title-transform&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;title&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-title-transform&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Declickbait string TITLE.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;trim&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;\\(?:\\(?:\\.\\.\\.\\|[!?]\\)+\\)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#963&#34;&gt;arr&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;trim&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#963&#34;&gt;s-table&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;copy-syntax-table&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;modify-syntax-entry&lt;/span&gt; &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;?\&amp;#39;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;s-table&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;with-syntax-table&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;s-table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;mapconcat&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;word&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#007020&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ((&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;word&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;AND&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;OR&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;IF&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;ON&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;IT&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;TO&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;OF&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;VS&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;IN&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;FOR&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;WAS&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;IS&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;BE&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;downcase&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;word&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ((&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;word&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;WE&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;DAY&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;HOW&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;WHY&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;NOW&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;OLD&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;NEW&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;MY&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;TOO&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;GOT&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;THE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;ONE&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;DO&amp;#34;&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;YOU&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;capitalize&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;word&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ((&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;word&lt;/span&gt;) &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3&lt;/span&gt;) (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;capitalize&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;word&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;word&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#963&#34;&gt;arr&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;elfeed-title-transform&lt;/code&gt; can be replaced with something much better, like a grammar aware title formatter (AI or otherwise), or with information extracted from the content or video description of the entry. But I&amp;rsquo;ll settle for this pareto solution for what was &lt;a href=&#34;https://youtube.com/watch?v=tF4OdtSuXMg&#34;&gt;half an hour of live coding&lt;/a&gt; in the dark:&lt;/p&gt;
&lt;iframe width=&#34;704&#34; height=&#34;396&#34; src=&#34;https://www.youtube.com/embed/tF4OdtSuXMg&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;Okay, the above screenshots were chosen as a joke. Here&amp;rsquo;s a more representative version of the declickbait effect:&lt;/p&gt;
&lt;p&gt;Before:
&lt;img src=&#34;https://karthinks.com/img/declickbait-before.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;After:
&lt;img src=&#34;https://karthinks.com/img/declickbait-after.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
</description>
    </item><item>
      <title>Jumping directories in eshell</title>
      <link>https://karthinks.com/software/jumping-directories-in-eshell/</link>
      <pubDate>Fri, 08 Oct 2021 17:33:00 -0700</pubDate>
      
      <guid>https://karthinks.com/software/jumping-directories-in-eshell/</guid>
      <description>&lt;p&gt;A quick note that I thought might be interesting to document.&lt;/p&gt;
&lt;p&gt;As befits a shell written in elisp, eshell is extremely easy to modify to your use.  There are a few packages floating around that add autojump/fasd/z type functionality to eshell. These let you jump quickly to any previously visited directory. As it turns out it&amp;rsquo;s very easy to implement a more powerful version of this by piggybacking off of &lt;a href=&#34;https://github.com/karthink/consult-dir&#34;&gt;consult-dir&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a &lt;strong&gt;z&lt;/strong&gt; command that lets you jump to any previously visited directory, as well as any bookmark, project or emacs-wide recent directory:&lt;/p&gt;
&lt;video style=&#34;center&#34; width=&#34;700&#34; controls loop&gt;
&lt;source src=&#34;https://karthinks.com/img/eshell-z.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;It&amp;rsquo;s a single function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;eshell/z&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;regexp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Navigate to a previously visited directory in eshell, or to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;any directory proferred by &lt;/span&gt;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;`consult-dir&amp;#39;&lt;/span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;eshell-dirs&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;delete-dups&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;mapcar&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;abbreviate-file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;color:#963&#34;&gt;ring-elements&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;eshell-last-dir-ring&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ((&lt;span style=&#34;color:#007020&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;regexp&lt;/span&gt;) (&lt;span style=&#34;color:#007020&#34;&gt;featurep&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;consult-dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;consult-dir--source-eshell&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Eshell&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                             &lt;span style=&#34;color:#007020&#34;&gt;:narrow&lt;/span&gt; &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;?e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                             &lt;span style=&#34;color:#007020&#34;&gt;:category&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                             &lt;span style=&#34;color:#007020&#34;&gt;:face&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;consult-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                             &lt;span style=&#34;color:#007020&#34;&gt;:items&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;eshell-dirs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#963&#34;&gt;consult-dir-sources&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;consult-dir--source-eshell&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                          &lt;span style=&#34;color:#963&#34;&gt;consult-dir-sources&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#963&#34;&gt;eshell/cd&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;substring-no-properties&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#963&#34;&gt;consult-dir--pick&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Switch directory: &amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;eshell/cd&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;regexp&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;eshell-find-previous-directory&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;regexp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;completing-read&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;cd: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;eshell-dirs&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Plus &lt;code&gt;consult-dir&lt;/code&gt;, of course.&lt;/p&gt;
&lt;p&gt;Note that if you provide input to the command instead, &lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;z doc&lt;/code&gt;, it will jump directly to the last matching directory you visited in eshell, &lt;em&gt;i.e.&lt;/em&gt; &lt;code&gt;~/Documents/&lt;/code&gt; or something like it.&lt;/p&gt;
&lt;p&gt;The idea is simple, and it should be trivial to write something similar if you&amp;rsquo;re a Helm or Ivy user, as well as to write one for the comint mode &lt;code&gt;M-x shell&lt;/code&gt;.&lt;/p&gt;
</description>
    </item><item>
      <title>Lazy Elfeed</title>
      <link>https://karthinks.com/software/lazy-elfeed/</link>
      <pubDate>Fri, 22 May 2020 03:20:00 +0530</pubDate>
      
      <guid>https://karthinks.com/software/lazy-elfeed/</guid>
      <description>&lt;p&gt;Elfeed, the feed reader for Emacs, is built on several clever ideas. The basic mode of interaction in Elfeed is through search, specifying what kinds of feeds you want to peruse at the moment. This removes the distinction between an inbox and a search result, which works surprisingly well with the expressive search syntax. The second is integration: search results can be stored as regular bookmarks, and jumping to the bookmark from anywhere in Emacs will run the corresponding query and present you with fresh results. The third is organizing by tags instead of folders. Web services like Gmail use some of these concepts (and probably pioneered them too), but the difference between web-based readers and Emacs in speed, customizability, general hackability and use is night and day.&lt;/p&gt;
&lt;p&gt;Elfeed&amp;rsquo;s default interface has all the right pieces, but I found it needed just a &lt;em&gt;little tweaking&lt;/em&gt; to fit what I expect from a feed reader.&lt;/p&gt;
&lt;h2 id=&#34;display-the-feed-list-and-current-entry-in-a-split-pane-setup&#34;&gt;Display the feed list and current entry in a split pane setup &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/h2&gt;
&lt;p&gt;Elfeed has two kinds of views: The &lt;code&gt;search&lt;/code&gt; view which shows feed entries matching a search query, and the &lt;code&gt;show&lt;/code&gt; view to read a specific entry. By default only one of these is active at a time, but a more useful split-pane setup is a few tweaks away:&lt;/p&gt;
&lt;video width=&#34;700&#34; style=&#34;display:block; margin: 0 auto;&#34; autoplay controls loop&gt;
&lt;source src=&#34;https://karthinks.com/img/elfeed-split-pane-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;p&gt;Your browser does not support the video tag.&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;Stay in the search view and preview entries.&lt;/p&gt;
&lt;p&gt;There are only two pieces to this. The first is to specify the function we want Elfeed to use to display the buffer with the current entry. In this case write our own &lt;code&gt;elfeed-display-buffer&lt;/code&gt; to set the height.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-show-entry-switch&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;elfeed-display-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-display-buffer&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;act&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;pop-to-buffer&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;buf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#963&#34;&gt;set-window-text-height&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;get-buffer-window&lt;/span&gt;) (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;round&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#60e;font-weight:bold&#34;&gt;0.7&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;frame-height&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A different but less self-contained way would be to set it to use the built in &lt;code&gt;pop-to-buffer&lt;/code&gt; but add an entry to &lt;code&gt;display-buffer-alist&lt;/code&gt; as an instruction on what to do with elfeed entry buffers.&lt;/p&gt;
&lt;p&gt;The second is to set up a keybinding to advance to the next or previous feed in the search window, with a little  elbow grease. &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;;; -*- lexical-binding: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-show-entry-pre&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;lines&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Returns a function to scroll forward or back in the Elfeed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;  search results, displaying entries without switching to them.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;times&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;forward-line&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;times&lt;/span&gt; (&lt;span style=&#34;color:#007020&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;lines&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;recenter&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;call-interactively&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;elfeed-search-show-entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;select-window&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;previous-window&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#007020&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-remain-on-entry&lt;/span&gt; (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;forward-line&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;-1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-mode-map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#963&#34;&gt;elfeed-search-show-entry-pre&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;+1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-mode-map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#963&#34;&gt;elfeed-search-show-entry-pre&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;-1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-mode-map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;M-RET&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#963&#34;&gt;elfeed-search-show-entry-pre&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;navigate-the-entire-database-with-the-space-bar&#34;&gt;Navigate the entire database with the space bar&lt;/h2&gt;
&lt;p&gt;Alternatively, you might prefer to stay in the &amp;ldquo;show&amp;rdquo; window and just go through each entry by content instead of header. You can use the space bar to scroll the view or move to the next entry as appropriate.&lt;/p&gt;
&lt;video width=&#34;700&#34; style=&#34;display:block; margin: 0 auto;&#34; autoplay controls loop&gt;
&lt;source src=&#34;https://karthinks.com/img/elfeed-space-nav-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;p&gt;Your browser does not support the video tag.&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;Go forward (scroll or next entry) with &lt;code&gt;SPC&lt;/code&gt;, back with &lt;code&gt;S-SPC&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Google Reader had one button navigation, and it is a level of laziness I have aspired to since.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-scroll-up-command&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Scroll up or go to next feed item in Elfeed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;^P&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;scroll-error-top-bottom&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;condition-case-unless-debug&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;scroll-up-command&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#f00;font-weight:bold&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;elfeed-show-next&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-scroll-down-command&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Scroll up or go to next feed item in Elfeed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;^P&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;scroll-error-top-bottom&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;condition-case-unless-debug&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#963&#34;&gt;scroll-down-command&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#f00;font-weight:bold&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;elfeed-show-prev&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-show-mode-map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;SPC&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;elfeed-scroll-up-command&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-show-mode-map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;S-SPC&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;elfeed-scroll-down-command&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;easier-tagging&#34;&gt;Easier tagging&lt;/h2&gt;
&lt;p&gt;By default you can tag an entry from the search results by typing &amp;ldquo;&lt;code&gt;+&lt;/code&gt;&amp;rdquo; followed by the tag name. This is too much work for a central organizational feature, so a little helper sorts things out.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-tag-selection-as&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;mytag&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Returns a function that tags an elfeed entry or selection as
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;background-color:#fff0f0&#34;&gt;MYTAG&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#007020&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;Toggle a tag on an Elfeed search selection&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#963&#34;&gt;elfeed-search-toggle-all&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;mytag&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tag with a single letter keybind:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-mode-map&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;l&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;elfeed-tag-selection-as&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;readlater&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-mode-map&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;elfeed-tag-selection-as&lt;/span&gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;junk&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;open-feeds-in-emacs&#34;&gt;Open feeds in Emacs&lt;/h2&gt;
&lt;p&gt;Elfeed will open links to feeds in your default browser with &amp;ldquo;&lt;code&gt;b&lt;/code&gt;&amp;rdquo;. But for text heavy posts or to look up something specific I often want to open them in place in Emacs:&lt;/p&gt;
&lt;video style=&#34;center&#34; style=&#34;center&#34; width=&#34;700&#34; autoplay controls loop&gt;
&lt;source src=&#34;https://karthinks.com/img/elfeed-open-eww-small.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;p&gt;Your browser does not support the video tag.&lt;/p&gt;
&lt;/video&gt;
&lt;p&gt;Quick-preview links in &lt;code&gt;eww&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead of writing a function to do this from scratch, we set &lt;code&gt;eww&lt;/code&gt; (Emacs&amp;rsquo; built in web browser) as the default in a short-lived &lt;code&gt;let&lt;/code&gt; binding and let the usual &lt;code&gt;browse-url&lt;/code&gt; functions handle the rest:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-show-eww-open&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;use-generic-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;open with eww&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;P&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;browse-url-browser-function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;eww-browse-url&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#963&#34;&gt;elfeed-show-visit&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;use-generic-p&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-eww-open&lt;/span&gt; (&lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;use-generic-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;open with eww&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;P&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#007020&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#963&#34;&gt;browse-url-browser-function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#963&#34;&gt;eww-browse-url&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#963&#34;&gt;elfeed-search-browse-url&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;use-generic-p&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-show-mode-map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;efleed-show-eww-open&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;define-key&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;elfeed-search-mode-map&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;&amp;#39;efleed-search-eww-open&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can take this idea further. The following snippet will ensure that Emacs (and thus Elfeed) defaults to opening Youtube links in &lt;code&gt;mpv&lt;/code&gt; (or the video player of your choice), cutting the browser out of the loop entirely. &lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;browse-url-browser-function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#333&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;https:\\/\\/www\\.youtu\\.*be.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;browse-url-mpv&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#333&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;browse-url-generic&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;browse-url-mpv&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#038;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;single&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;mpv&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;background-color:#fff0f0&#34;&gt;&amp;#34;mpv&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#963&#34;&gt;shell-quote-argument&lt;/span&gt; &lt;span style=&#34;color:#963&#34;&gt;url&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;There is &lt;a href=&#34;https://github.com/algernon/elfeed-goodies&#34;&gt;Elfeed Goodies&lt;/a&gt;, a package on github that provides a split pane setup to Elfeed. But it&amp;rsquo;s rather large for what it does, has a dependency I don&amp;rsquo;t need (&lt;code&gt;popwin.el&lt;/code&gt;) for a single function and provides much else that I have no use for.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;A previous version of this write-up used macros instead of closures for the helpers. This simpler solution was suggested by &lt;a href=&#34;https://old.reddit.com/r/emacs/comments/goh2nw/lazy_elfeed/frgbn1h/&#34;&gt;&lt;code&gt;/u/nv-elisp&lt;/code&gt; on Reddit&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;code&gt;mpv&lt;/code&gt; requires &lt;a href=&#34;https://github.com/ytdl-org/youtube-dl&#34;&gt;Youtube-dl&lt;/a&gt; to play youtube videos.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
  </channel>
</rss>
