<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Emacs on camdez</title><link>https://camdez.com/tags/emacs/</link><description>Recent content in Emacs on camdez</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 12 Feb 2024 21:22:33 -0600</lastBuildDate><atom:link href="https://camdez.com/tags/emacs/index.xml" rel="self" type="application/rss+xml"/><item><title>Chinese Zodiac Time for Emacs</title><link>https://camdez.com/blog/2024/02/12/chinese-zodiac-time-for-emacs/</link><pubDate>Mon, 12 Feb 2024 21:22:33 -0600</pubDate><guid>https://camdez.com/blog/2024/02/12/chinese-zodiac-time-for-emacs/</guid><description>&lt;p>In the spirit of Chinese New Year, I hacked up a small extension for
Emacs to render the current time of day using emoji and Chinese
characters:&lt;/p>
&lt;figure>&lt;img src="https://camdez.com/images/blog/chinese-zodiac-time-for-emacs/demo.jpg"
alt="Various screenshots of Emacs showing the time displayed with Chinese characters and emoji."/>&lt;figcaption>
&lt;p>Various configurations for your mode line.&lt;/p>
&lt;/figcaption>
&lt;/figure></description><content:encoded>&lt;p>In the spirit of Chinese New Year, I hacked up a small extension for
Emacs to render the current time of day using emoji and Chinese
characters:&lt;/p>
&lt;figure>&lt;img src="https://camdez.com/images/blog/chinese-zodiac-time-for-emacs/demo.jpg"
alt="Various screenshots of Emacs showing the time displayed with Chinese characters and emoji."/>&lt;figcaption>
&lt;p>Various configurations for your mode line.&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>It&amp;rsquo;s just a silly project that I&amp;rsquo;ll consider a success if it puts a
smile on someone&amp;rsquo;s face, but it is loosely based on &lt;a href="ming-system">a system used to
measure time in the Ming dynasty&lt;/a> which divided the day
into 12 equal periods (時&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>), named after &lt;a href="https://en.wikipedia.org/wiki/Earthly_Branches">the 12 earthly
branches&lt;/a> (地支).&lt;/p>
&lt;p>Because the animals of the Chinese zodiac map 1-to-1 with the earthly
branches, it is equally possible to indicate the time with the zodiac
animals!&lt;/p>
&lt;figure>&lt;img src="https://camdez.com/images/blog/chinese-zodiac-time-for-emacs/earthly-branches.jpg"
alt="Chart of correspondence between the earthly branches, zodiac animals, and times of day from Wikipedia. Apologies on this being in Spanish."/>&lt;figcaption>
&lt;p>Chart of correspondence between the earthly branches, zodiac animals, and times of day from Wikipedia. Apologies on this being in Spanish.&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>Given that a modern user probably wants to know which of our &lt;em>24&lt;/em>
hours they&amp;rsquo;re in, rather than which two hour period (時), I decided to
differentiate the two halves as either 小 (small) or 大 (large).&lt;/p>
&lt;p>Hence, in the image above showing the time as 「大🐲 四十二分」, the
current time is 8:42am, by our modern reckoning (7:42am would be the
&lt;em>little&lt;/em> dragon!).&lt;/p>
&lt;p>I won&amp;rsquo;t go into a ton of detail here because I explain it in some
detail on &lt;a href="https://github.com/camdez/cn-zodiac-time.el">the project&amp;rsquo;s GitHub page&lt;/a>.&lt;/p>
&lt;p>The most amusing part of the project was, perhaps, deciding exactly
which emoji to use! In the end, I implemented two sets of emoji you
can choose from:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Set&lt;/th>
&lt;th>Emoji&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>'cute&lt;/code>&lt;/td>
&lt;td>🐭🐮🐯🐰🐲🐍🐴🐏🐵🐔🐶🐷&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>'emoji&lt;/code>&lt;/td>
&lt;td>🐀🐄🐅🐇🐉🐍🐎🐑🐒🐓🐕🐖&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;em>Rather disappointing that we don&amp;rsquo;t quite have a complete set of
animal faces. At least not in Apple&amp;rsquo;s emoji.&lt;/em>&lt;/p>
&lt;p>If you&amp;rsquo;re wondering why I chose the COW (🐄) emoji in the second set
rather than the OX (🐂), it&amp;rsquo;s because it looked too similar to the
neighboring TIGER (🐅), making it easy to confuse the time.&lt;/p>
&lt;p>If you don&amp;rsquo;t like my choices, the library also makes it extremely easy
to bring your own set of emoji, so you can make your own decisions
between:&lt;/p>
&lt;ul>
&lt;li>RAT (🐀), MOUSE (🐁), and MOUSE FACE (🐭)&lt;/li>
&lt;li>SHEEP (🐑), GOAT (🐐), and RAM (🐏)&lt;/li>
&lt;li>HORSE (🐎) and HORSE FACE (🐴)&lt;/li>
&lt;li>CHICKEN (🐔) and ROOSTER (🐓)&lt;/li>
&lt;li>Or maybe even pretend FROG (🐸) is a snake face&lt;/li>
&lt;li>Or spice up your horse with UNICORN (🦄)&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Clearly the sky&amp;rsquo;s the limit.&lt;/em>&lt;/p>
&lt;p>For Chinese learners or traditionalists, it can also display the time
with:&lt;/p>
&lt;ul>
&lt;li>Traditional characters: 「大龍 四十二分」&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/li>
&lt;li>Simplified characters: 「大龙 四十二分」&lt;/li>
&lt;li>Or earthly branches: 「辰正 四十二分」&lt;/li>
&lt;/ul>
&lt;p>(&lt;em>n.b.&lt;/em> the earthly branches are displayed using the proper,
traditional system of 初 and 正 suffixes, not my invented prefixes for
animals.)&lt;/p>
&lt;p>It&amp;rsquo;s a lot of fun telling time with cute animals, and might even help
you learn a few things if you&amp;rsquo;re a beginner in Chinese, so &lt;a href="https://github.com/camdez/cn-zodiac-time.el">check it out
on GitHub!&lt;/a>&lt;/p>
&lt;p>龍年快樂！恭喜發財！ 🐉🧧&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Students of the Chinese language may find it interesting to know
that these &lt;em>two&lt;/em> hour periods are the reason we call (single) hours
&lt;strong>小&lt;/strong>時 in modern Chinese (I know I did!).&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>It&amp;rsquo;s not 100% clear to me if these characters will render the
same regardless of locale, so I apologize if they do not appear as I
have described&amp;mdash;I&amp;rsquo;m still trying to get my head around &lt;a href="https://en.wikipedia.org/wiki/CJK_Unified_Ideographs">CJK
unification&lt;/a> in Unicode.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Fix clj-refactor Libspec Stealing</title><link>https://camdez.com/blog/2024/02/06/fix-clj-refactor-libspec-stealing/</link><pubDate>Tue, 06 Feb 2024 22:59:28 -0600</pubDate><guid>https://camdez.com/blog/2024/02/06/fix-clj-refactor-libspec-stealing/</guid><description>&lt;p>(This post is regarding a very particular issue at the intersection of
Emacs, Clojure, and &lt;a href="https://github.com/clojure-emacs/cider">CIDER&lt;/a>, so most readers can probably skip it,
but I figured the solution deserved to be somewhere on the internet.)&lt;/p>
&lt;p>CIDER has this awesome feature via &lt;a href="https://github.com/clojure-emacs/clj-refactor.el">clj-refactor&lt;/a> where it can
automatically add missing libspecs to your &lt;code>ns&lt;/code> form as soon as you
type an aliased var name using an &lt;code>:as&lt;/code> alias you have previously used
for that namespace:&lt;/p>
&lt;figure>&lt;img src="https://camdez.com/images/blog/2024-02-06-fix-clj-refactor-libspec-stealing/clj-refactor-magic-namespaces.gif"
alt="Screen recording showing how CIDER and clj-refactor can add missing libspecs."/>&lt;figcaption>
&lt;p>Screen recording showing how CIDER and clj-refactor can add missing libspecs.&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>You can define a preferred set of (&lt;code>:as&lt;/code>) aliases via
&lt;code>cljr-magic-require-namespaces&lt;/code> in your Emacs config, and, whether
you&amp;rsquo;ve done that or not, CIDER tries hard to be smart, offering you
choices if you&amp;rsquo;ve previously used the same alias for different
namespaces in different places in your project (&lt;em>e.g.&lt;/em> &lt;code>s/&lt;/code> for
&lt;code>clojure.spec&lt;/code> some places and the same for &lt;code>clojure.string&lt;/code> in other
places).&lt;/p>
&lt;p>Moreover, CIDER &lt;em>evaluates&lt;/em> the namespace form, bringing in the new
requires, allowing you to just keep typing and coding, without
breaking your flow.&lt;/p>
&lt;p>This is all fantastic, but I ran across one particular scenario where
this kept biting me: my &lt;code>user&lt;/code> namespace.&lt;/p></description><content:encoded>&lt;p>(This post is regarding a very particular issue at the intersection of
Emacs, Clojure, and &lt;a href="https://github.com/clojure-emacs/cider">CIDER&lt;/a>, so most readers can probably skip it,
but I figured the solution deserved to be somewhere on the internet.)&lt;/p>
&lt;p>CIDER has this awesome feature via &lt;a href="https://github.com/clojure-emacs/clj-refactor.el">clj-refactor&lt;/a> where it can
automatically add missing libspecs to your &lt;code>ns&lt;/code> form as soon as you
type an aliased var name using an &lt;code>:as&lt;/code> alias you have previously used
for that namespace:&lt;/p>
&lt;figure>&lt;img src="https://camdez.com/images/blog/2024-02-06-fix-clj-refactor-libspec-stealing/clj-refactor-magic-namespaces.gif"
alt="Screen recording showing how CIDER and clj-refactor can add missing libspecs."/>&lt;figcaption>
&lt;p>Screen recording showing how CIDER and clj-refactor can add missing libspecs.&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>You can define a preferred set of (&lt;code>:as&lt;/code>) aliases via
&lt;code>cljr-magic-require-namespaces&lt;/code> in your Emacs config, and, whether
you&amp;rsquo;ve done that or not, CIDER tries hard to be smart, offering you
choices if you&amp;rsquo;ve previously used the same alias for different
namespaces in different places in your project (&lt;em>e.g.&lt;/em> &lt;code>s/&lt;/code> for
&lt;code>clojure.spec&lt;/code> some places and the same for &lt;code>clojure.string&lt;/code> in other
places).&lt;/p>
&lt;p>Moreover, CIDER &lt;em>evaluates&lt;/em> the namespace form, bringing in the new
requires, allowing you to just keep typing and coding, without
breaking your flow.&lt;/p>
&lt;p>This is all fantastic, but I ran across one particular scenario where
this kept biting me: my &lt;code>user&lt;/code> namespace.&lt;/p>
&lt;p>In my &lt;code>dev/user.clj&lt;/code> file, I had a number of commands for managing the
state of my program during development (&lt;em>viz.&lt;/em> &lt;a href="https://github.com/weavejester/reloaded.repl">reloaded.repl&lt;/a> and
friends) that I used constantly, including while testing out various
functions I&amp;rsquo;d just written in the current namespace (&lt;em>e.g.&lt;/em>
&lt;code>(new-db-query (user/db))&lt;/code>). But I also happen to have another
(rarely-used) namespace in my app which was, somewhere, aliased as
&lt;code>user&lt;/code>. Something like &lt;code>app.ui.views.user&lt;/code>.&lt;/p>
&lt;p>Since references to the (top-level) &lt;code>user&lt;/code> namespace &lt;em>never&lt;/em> occur in
the (production-shared) broader codebase, every time I typed &lt;code>user/&lt;/code>,
CIDER immediately added a require for the namespace I &lt;em>didn&amp;rsquo;t&lt;/em> want
(the only usage of the alias in the codebase) &lt;em>and loaded it&lt;/em>.
Meaning I not only had to remove it, but also undefine the alias (&lt;code>C-c C-u&lt;/code>)&amp;mdash;and hopefully not accidentally trigger the same thing yet
again though muscle memory&amp;hellip;.&lt;/p>
&lt;p>I tried everything I could think of to fix this, including just
specifying via &lt;code>cljr-magic-require-namespaces&lt;/code> that &lt;code>user&lt;/code> should
expand to &lt;code>user&lt;/code>, but nothing worked, so I suspect a proper solution
is going to require an upstream patch.&lt;/p>
&lt;p>In the meantime, a quick and dirty solution is just to use &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html">advice in
Emacs&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-emacs-lisp" data-lang="emacs-lisp">&lt;span style="display:flex;">&lt;span>(use-package clj-refactor
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> :defer &lt;span style="color:#66d9ef">t&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> :config
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">;; Don&amp;#39;t auto add `require&amp;#39; form for `user&amp;#39; namespace.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (defun cljr--unresolved-alias-ref--unless-user (alias-ref)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (unless (string= &lt;span style="color:#e6db74">&amp;#34;user&amp;#34;&lt;/span> alias-ref)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> alias-ref))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (advice-add &lt;span style="color:#e6db74">&amp;#39;cljr--unresolved-alias-ref&lt;/span> :before-while
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">#&amp;#39;&lt;/span>cljr--unresolved-alias-ref--unless-user))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If the advice function here
(&lt;code>cljr--unresolved-alias-ref--unless-user&lt;/code>) returns &lt;code>nil&lt;/code>, it
essentially tells clj-refactor that an alias is already handled and it
doesn&amp;rsquo;t need to worry about adding an import for it.&lt;/p>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs: Running Shell Commands on the Current File</title><link>https://camdez.com/blog/2022/07/29/emacs-running-shell-commands-on-the-current-file/</link><pubDate>Fri, 29 Jul 2022 07:48:44 -0500</pubDate><guid>https://camdez.com/blog/2022/07/29/emacs-running-shell-commands-on-the-current-file/</guid><description>&lt;p>I&amp;rsquo;ve long thought it was a little funny that Emacs doesn&amp;rsquo;t provide an
easy way to run a shell command on the current file. It turns out it
does, but it&amp;rsquo;s not as obvious as you might expect.&lt;/p></description><content:encoded>&lt;p>I&amp;rsquo;ve long thought it was a little funny that Emacs doesn&amp;rsquo;t provide an
easy way to run a shell command on the current file. It turns out it
does, but it&amp;rsquo;s not as obvious as you might expect.&lt;/p>
&lt;p>Emacs provides lots of great commands for conveniently running shell
commands:&lt;/p>
&lt;ul>
&lt;li>&lt;code>M-!&lt;/code> (&lt;code>shell-command&lt;/code>): executes the given shell command, displays
output in a new buffer or the echo area (depending on output
length). Optionally inserts the output into the current buffer when
given a prefix argument.&lt;/li>
&lt;li>&lt;code>M-&amp;amp;&lt;/code> (&lt;code>async-shell-command&lt;/code>): as above, but executed
asynchronously.&lt;/li>
&lt;li>&lt;code>M-|&lt;/code> (&lt;code>shell-command-on-region&lt;/code>): pass the current region as input
to a shell command and display output. Optionally replaces the
region when given a prefix argument.&lt;/li>
&lt;/ul>
&lt;p>Of course we can also run a shell &lt;em>within&lt;/em> Emacs, via &lt;code>shell&lt;/code> (the
basic option), &lt;code>eshell&lt;/code> (a shell implemented in Emacs Lisp, with
access to Emacs Lisp functions), and &lt;code>term&lt;/code> (a more fully-featured
terminal emulator).&lt;/p>
&lt;p>We also have &lt;code>compile&lt;/code>, which will run a shell command (often &lt;code>make&lt;/code>),
streaming in the output and overlaying functionality to easily jump to
files referenced in the output (compilation warnings, &lt;code>grep&lt;/code> results,
etc.).&lt;/p>
&lt;p>But what has always been notably missing for me, is a quick way to run
a shell command on the current &lt;em>file&lt;/em>. Not &lt;em>buffer&lt;/em> / file contents,
not &lt;em>region&lt;/em>, but &lt;em>file&lt;/em>.&lt;/p>
&lt;p>From &lt;code>dired-mode&lt;/code>, we can easily do this with &lt;code>!&lt;/code>, but invoking Dired
just to run a shell command is more disruptive to my workflow than it
needs to be when I just want to run &lt;code>open &amp;lt;current-file&amp;gt;&lt;/code> or similar.&lt;/p>
&lt;p>It turns out there is a built-in two-keystroke solution via the
&amp;ldquo;future history&amp;rdquo; mechanism &lt;a href="https://engineering.collbox.co/post/working-faster-in-emacs-by-reading-the-future/">I wrote about on the CollBox Engineering
blog&lt;/a>:&lt;/p>
&lt;p>If you use &lt;code>M-!&lt;/code> (&lt;code>shell-command&lt;/code>) and then press &lt;code>M-n&lt;/code>
(&lt;code>next-history-element&lt;/code>), the current file name will be inserted into
the minibuffer with point before it. Then you just need to type the
command you want to run and hit return.&lt;/p>
&lt;p>It&amp;rsquo;s a good reminder that with 46 years of history behind it, if
something obvious appears to be missing from Emacs, there&amp;rsquo;s probably a
good reason why.&lt;/p>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Regex Optimization in Clojure</title><link>https://camdez.com/blog/2021/08/14/regex-optimization-in-clojure/</link><pubDate>Sat, 14 Aug 2021 15:28:31 -0700</pubDate><guid>https://camdez.com/blog/2021/08/14/regex-optimization-in-clojure/</guid><description>&lt;p>Earlier this week, after responding to &lt;a href="https://clojureverse.org/t/an-acronym-capitalization-checker-with-regex/8013/4">a post on
ClojureVerse&lt;/a>, I got curious about re-implementing the basics
of Emacs&amp;rsquo;s &lt;code>regexp-opt&lt;/code> function in Clojure. I thought it would be a
fun little coding exercise so I decided to take a stab at it during a
few spare minutes in my day and was very pleased with the concision
and clarity of the result.&lt;/p></description><content:encoded>&lt;p>Earlier this week, after responding to &lt;a href="https://clojureverse.org/t/an-acronym-capitalization-checker-with-regex/8013/4">a post on
ClojureVerse&lt;/a>, I got curious about re-implementing the basics
of Emacs&amp;rsquo;s &lt;code>regexp-opt&lt;/code> function in Clojure. I thought it would be a
fun little coding exercise so I decided to take a stab at it during a
few spare minutes in my day and was very pleased with the concision
and clarity of the result.&lt;/p>
&lt;p>Emacs&amp;rsquo;s &lt;code>regexp-opt&lt;/code> takes a list of strings and produces an optimized
regular expression matching all of the passed strings. A
&lt;em>non&lt;/em>-optimized solution to this problem would be to simply combine
all of the possibilities into a regex alternation:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-clj" data-lang="clj">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#66d9ef">def &lt;/span>sample-opts [&lt;span style="color:#e6db74">&amp;#34;AB&amp;#34;&lt;/span> &lt;span style="color:#e6db74">&amp;#34;ABOUT&amp;#34;&lt;/span> &lt;span style="color:#e6db74">&amp;#34;APPLE&amp;#34;&lt;/span> &lt;span style="color:#e6db74">&amp;#34;BOTTLE&amp;#34;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#66d9ef">defn- &lt;/span>re-alt-str
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Build a string representing regex alternation.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> [opts]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if &lt;/span>(next opts)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (str &lt;span style="color:#e6db74">&amp;#34;(?:&amp;#34;&lt;/span> (&lt;span style="color:#a6e22e">str/join&lt;/span> &lt;span style="color:#e6db74">&amp;#34;|&amp;#34;&lt;/span> opts) &lt;span style="color:#e6db74">&amp;#34;)&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (first opts)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#66d9ef">defn &lt;/span>naive-re-opt [opts]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (re-pattern (&lt;span style="color:#a6e22e">re-alt-str&lt;/span> opts)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#a6e22e">naive-re-opt&lt;/span> sample-opts)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">;; =&amp;gt; #&amp;#34;(?:AB|ABOUT|APPLE|BOTTLE)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(re-find (&lt;span style="color:#a6e22e">naive-re-opt&lt;/span> sample-opts)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;PLEASE GIVE ME AN APPLE&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">;; =&amp;gt; &amp;#34;APPLE&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This approach works perfectly fine, but isn&amp;rsquo;t optimal because in
searching for a string like &amp;ldquo;APPLE&amp;rdquo;, the regex engine initially finds
a match against the A in &amp;ldquo;AB&amp;rdquo;, then realizes the B doesn&amp;rsquo;t match
before moving on to &amp;ldquo;ABOUT&amp;rdquo; and doing the same partial match dance
again before trying &amp;ldquo;APPLE&amp;rdquo;&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>.&lt;/p>
&lt;p>Instead, we can compute an optimized regular expression where the A is
only matched &lt;em>once&lt;/em> and only then do we continue on to explore the
possible suffixes following A (&lt;em>viz.&lt;/em> &amp;ldquo;B&amp;rdquo;, &amp;ldquo;BOUT&amp;rdquo;, &amp;ldquo;PPLE&amp;rdquo;). We also
want to repeat this logic through the rest of the pattern text, only
matching the B &lt;em>once&lt;/em>.&lt;/p>
&lt;p>How can we use Clojure to tackle this problem?&lt;/p>
&lt;p>The algorithm is actually quite simple:&lt;/p>
&lt;p>First we build a graph (tree) where each edge represents successive
letters in the strings of &lt;code>opts&lt;/code>:&lt;/p>
&lt;p>&lt;img src="https://camdez.com/images/blog/2021-08-14-regex-optimization-in-clojure/regex-railroad-diagram.svg" alt="Regular expression railroad diagram">&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>&lt;em>Note: terminators need to be explicitly modeled in the graph so that
&amp;ldquo;AB&amp;rdquo; is considered a match and not just a prefix on the way to
matching &amp;ldquo;ABOUT&amp;rdquo;.&lt;/em>&lt;/p>
&lt;p>Then we simply collapse the tails into literal strings, and the
branches into alternations:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-clj" data-lang="clj">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#66d9ef">defn &lt;/span>better-re-opt [opts]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">-&amp;gt;&amp;gt;&lt;/span> opts
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">;; Build graph&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (reduce (&lt;span style="color:#66d9ef">fn &lt;/span>[graph s]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">assoc-in&lt;/span> graph (conj (&lt;span style="color:#a6e22e">vec&lt;/span> s) nil) nil))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">;; Reduce graph to string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">walk/postwalk&lt;/span> (&lt;span style="color:#66d9ef">fn &lt;/span>[x]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if &lt;/span>(map? x)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">re-alt-str&lt;/span> (map &lt;span style="color:#f92672">#&lt;/span>(apply str %) x))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> re-pattern))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#a6e22e">better-re-opt&lt;/span> sample-opts)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">;; =&amp;gt; #&amp;#34;(?:A(?:B(?:|OUT)|PPLE)|BOTTLE)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>(Excuse the dense indentation, I&amp;rsquo;m trying to squeeze this into 70
columns to avoid horizontal scrolling.)&lt;/em>&lt;/p>
&lt;p>That&amp;rsquo;s it! About ten lines of code to solve this whole problem, and
maybe 20 minutes of work for me from idea to finished feature.&lt;/p>
&lt;p>My favorite thing about this implementation is how easy Clojure makes
it to build the graph. I initially went into this thinking of
manually &lt;code>cons&lt;/code>ing up the graph before realizing &lt;code>assoc-in&lt;/code> could do
all of the work for me. Essentially we&amp;rsquo;re just doing something like
this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-clj" data-lang="clj">&lt;span style="display:flex;">&lt;span>(-&amp;gt; {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">assoc-in&lt;/span> [&lt;span style="color:#e6db74">\A&lt;/span> &lt;span style="color:#e6db74">\B&lt;/span> nil] nil)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">assoc-in&lt;/span> [&lt;span style="color:#e6db74">\A&lt;/span> &lt;span style="color:#e6db74">\B&lt;/span> &lt;span style="color:#e6db74">\O&lt;/span> &lt;span style="color:#e6db74">\U&lt;/span> &lt;span style="color:#e6db74">\T&lt;/span> nil] nil)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">assoc-in&lt;/span> [&lt;span style="color:#e6db74">\A&lt;/span> &lt;span style="color:#e6db74">\P&lt;/span> &lt;span style="color:#e6db74">\P&lt;/span> &lt;span style="color:#e6db74">\L&lt;/span> &lt;span style="color:#e6db74">\E&lt;/span> nil] nil)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">assoc-in&lt;/span> [&lt;span style="color:#e6db74">\B&lt;/span> &lt;span style="color:#e6db74">\O&lt;/span> &lt;span style="color:#e6db74">\T&lt;/span> &lt;span style="color:#e6db74">\T&lt;/span> &lt;span style="color:#e6db74">\L&lt;/span> &lt;span style="color:#e6db74">\E&lt;/span> nil] nil))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">;; =&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{&lt;span style="color:#e6db74">\A&lt;/span> {&lt;span style="color:#e6db74">\B&lt;/span> {nil nil,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">\O&lt;/span> {&lt;span style="color:#e6db74">\U&lt;/span> {&lt;span style="color:#e6db74">\T&lt;/span> {nil nil}}}},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">\P&lt;/span> {&lt;span style="color:#e6db74">\P&lt;/span> {&lt;span style="color:#e6db74">\L&lt;/span> {&lt;span style="color:#e6db74">\E&lt;/span> {nil nil}}}}},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">\B&lt;/span> {&lt;span style="color:#e6db74">\O&lt;/span> {&lt;span style="color:#e6db74">\T&lt;/span> {&lt;span style="color:#e6db74">\T&lt;/span> {&lt;span style="color:#e6db74">\L&lt;/span> {&lt;span style="color:#e6db74">\E&lt;/span> {nil nil}}}}}}}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>Notice the similarity to the graph we drew above?&lt;/em>&lt;/p>
&lt;p>Those &lt;code>nil&lt;/code> terminators may look funky, but I chose that approach
intentionally because &lt;code>(str nil) ;=&amp;gt; &amp;quot;&amp;quot;&lt;/code>, which makes the code to
reduce the graph to a string very compact.&lt;/p>
&lt;p>To do that reduction, we perform a post-order traversal of the nodes
of the graph (convenient as all get-out with &lt;code>clojure.walk/postwalk&lt;/code>),
returning non-map values unchanged and only operating when we&amp;rsquo;re
looking at a map. For maps with a single key-value pair, we use &lt;code>str&lt;/code>
to concatenate the key (the head character) and the value (the reduced
tail string). Referring to this operation as &lt;code>f&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-clj" data-lang="clj">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#a6e22e">f&lt;/span> {nil nil}) &lt;span style="color:#75715e">; &amp;lt;=&amp;gt; (str nil nil) =&amp;gt; &amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#a6e22e">f&lt;/span> {&lt;span style="color:#e6db74">\A&lt;/span> &lt;span style="color:#e6db74">&amp;#34;BC&amp;#34;&lt;/span>}) &lt;span style="color:#75715e">; &amp;lt;=&amp;gt; (str \A &amp;#34;BC&amp;#34;) =&amp;gt; &amp;#34;ABC&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>When we have multiple key-value pairs, we reduce each pair in the same
fashion and then combine them into a regex alternation just like in
the naive version.&lt;/p>
&lt;p>The reduction (here, for a smaller graph), proceeds something like
this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-clj" data-lang="clj">&lt;span style="display:flex;">&lt;span>{&lt;span style="color:#e6db74">\A&lt;/span> {&lt;span style="color:#e6db74">\B&lt;/span> {&lt;span style="color:#e6db74">\C&lt;/span> {nil nil},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">\U&lt;/span> {&lt;span style="color:#e6db74">\T&lt;/span> {nil nil}}}}}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{&lt;span style="color:#e6db74">\A&lt;/span> {&lt;span style="color:#e6db74">\B&lt;/span> {&lt;span style="color:#e6db74">\C&lt;/span> {nil nil},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">\U&lt;/span> {&lt;span style="color:#e6db74">\T&lt;/span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>}}}}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{&lt;span style="color:#e6db74">\A&lt;/span> {&lt;span style="color:#e6db74">\B&lt;/span> {&lt;span style="color:#e6db74">\C&lt;/span> {nil nil},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">\U&lt;/span> &lt;span style="color:#e6db74">&amp;#34;T&amp;#34;&lt;/span>}}}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{&lt;span style="color:#e6db74">\A&lt;/span> {&lt;span style="color:#e6db74">\B&lt;/span> {&lt;span style="color:#e6db74">\C&lt;/span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">\U&lt;/span> &lt;span style="color:#e6db74">&amp;#34;T&amp;#34;&lt;/span>}}}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{&lt;span style="color:#e6db74">\A&lt;/span> {&lt;span style="color:#e6db74">\B&lt;/span> &lt;span style="color:#e6db74">&amp;#34;(?:C|UT)&amp;#34;&lt;/span>}}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{&lt;span style="color:#e6db74">\A&lt;/span> &lt;span style="color:#e6db74">&amp;#34;B(?:C|UT)&amp;#34;&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;AB(?:C|UT)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is the kind of scenario where all the features of Clojure come
together so elegantly to make a succinct, beautiful solution.&lt;/p>
&lt;hr>
&lt;p>Full code listing for ease of copy / paste:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-clj" data-lang="clj">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#66d9ef">ns &lt;/span>camdez.re-opt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#e6db74">:require&lt;/span> [clojure.walk &lt;span style="color:#e6db74">:as&lt;/span> walk]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> [clojure.string &lt;span style="color:#e6db74">:as&lt;/span> str]))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#66d9ef">defn- &lt;/span>re-alt-str
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Build a string representing regex alternation.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> [opts]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if &lt;/span>(next opts)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (str &lt;span style="color:#e6db74">&amp;#34;(?:&amp;#34;&lt;/span> (&lt;span style="color:#a6e22e">str/join&lt;/span> &lt;span style="color:#e6db74">&amp;#34;|&amp;#34;&lt;/span> opts) &lt;span style="color:#e6db74">&amp;#34;)&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (first opts)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#66d9ef">defn &lt;/span>re-opt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Build an optimized regular expression to match any of the literal
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> strings in `opts` by unifying common prefixes.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> [opts]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">-&amp;gt;&amp;gt;&lt;/span> opts
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (reduce (&lt;span style="color:#66d9ef">fn &lt;/span>[graph s]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">assoc-in&lt;/span> graph (conj (&lt;span style="color:#a6e22e">vec&lt;/span> s) nil) nil))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">walk/postwalk&lt;/span> (&lt;span style="color:#66d9ef">fn &lt;/span>[x]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if &lt;/span>(map? x)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">re-alt-str&lt;/span> (map &lt;span style="color:#f92672">#&lt;/span>(apply str %) x))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> re-pattern))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>In practice, our regex engine may be smart enough to avoid these
operations through internal optimization, but that&amp;rsquo;s why this is
just a coding exercise.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Interactively Evaluating Clojure Code in Comments in Emacs</title><link>https://camdez.com/blog/2020/07/03/interactively-evaluating-clojure-code-in-comments-in-emacs/</link><pubDate>Fri, 03 Jul 2020 18:40:55 -0500</pubDate><guid>https://camdez.com/blog/2020/07/03/interactively-evaluating-clojure-code-in-comments-in-emacs/</guid><description>&lt;p>There&amp;rsquo;s a loose convention in Clojure of leaving top-level &lt;code>(comment ...)&lt;/code>-style comments in source files to give examples of how a
particular piece of code works or to provide a convenient means of
invoking functionality contained in the file. You can even see this
in &lt;a href="https://github.com/clojure/clojure/blob/30a36cbe0ef936e57ddba238b7fa6d58ee1cbdce/src/clj/clojure/set.clj#L158">the source files to Clojure proper&lt;/a>.&lt;/p>
&lt;p>Even though leaving commented out code can seem a bit messy, it has
also saved me a ton of time relearning how to invoke something, so I
have somewhat mixed feelings about the practice. But, regardless of
the merits of using this in production code, it&amp;rsquo;s unarguably useful in
development, and I use it extensively as I work to test out function
invocations with different arguments, and to store little bits of test
data.&lt;/p>
&lt;p>Frustratingly, this form does not play nicely with CIDER&amp;rsquo;s &lt;code>C-M-x&lt;/code>
(&lt;code>cider-eval-defun-at-point&lt;/code>) and &lt;code>C-c M-;&lt;/code>
(&lt;code>cider-eval-defun-to-comment&lt;/code>) commands, which expect the target form
to be at the top-level of the file. The containing &lt;code>(comment ...)&lt;/code>
form means that technically isn&amp;rsquo;t so, leading me to perpetually
evaluate the wrong form&amp;hellip;&lt;/p></description><content:encoded>&lt;p>There&amp;rsquo;s a loose convention in Clojure of leaving top-level &lt;code>(comment ...)&lt;/code>-style comments in source files to give examples of how a
particular piece of code works or to provide a convenient means of
invoking functionality contained in the file. You can even see this
in &lt;a href="https://github.com/clojure/clojure/blob/30a36cbe0ef936e57ddba238b7fa6d58ee1cbdce/src/clj/clojure/set.clj#L158">the source files to Clojure proper&lt;/a>.&lt;/p>
&lt;p>Even though leaving commented out code can seem a bit messy, it has
also saved me a ton of time relearning how to invoke something, so I
have somewhat mixed feelings about the practice. But, regardless of
the merits of using this in production code, it&amp;rsquo;s unarguably useful in
development, and I use it extensively as I work to test out function
invocations with different arguments, and to store little bits of test
data.&lt;/p>
&lt;p>Frustratingly, this form does not play nicely with CIDER&amp;rsquo;s &lt;code>C-M-x&lt;/code>
(&lt;code>cider-eval-defun-at-point&lt;/code>) and &lt;code>C-c M-;&lt;/code>
(&lt;code>cider-eval-defun-to-comment&lt;/code>) commands, which expect the target form
to be at the top-level of the file. The containing &lt;code>(comment ...)&lt;/code>
form means that technically isn&amp;rsquo;t so, leading me to perpetually
evaluate the wrong form&amp;hellip;&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-clj" data-lang="clj">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#a6e22e">comment&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (+ &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &amp;lt;point&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ) &lt;span style="color:#75715e">; =&amp;gt; nil&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;hellip;and be told for the millionth time that &lt;code>comment&lt;/code>s evaluate to
&lt;code>nil&lt;/code>.&lt;/p>
&lt;p>I finally discovered that there is an easy way to change this
behavior, with just a single settings tweak:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-elisp" data-lang="elisp">&lt;span style="display:flex;">&lt;span>(setq clojure-toplevel-inside-comment-form &lt;span style="color:#66d9ef">t&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now things will work as you (might) expect&amp;hellip;&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-clj" data-lang="clj">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#a6e22e">comment&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (+ &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &amp;lt;point&amp;gt; &lt;span style="color:#75715e">; =&amp;gt; 2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;hellip; which is certainly more useful, and destined to become a permanent
part of my Emacs config.&lt;/p>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Automatically Installing Your Emacs Packages</title><link>https://camdez.com/blog/2014/12/07/automatically-installing-your-emacs-packages/</link><pubDate>Sun, 07 Dec 2014 23:27:54 -0600</pubDate><guid>https://camdez.com/blog/2014/12/07/automatically-installing-your-emacs-packages/</guid><description>The interactive list-packages command in modern Emacsen is handy for finding and trying out new packages, but once we&amp;rsquo;ve found packages we want to use, how can we have them automatically installed on all machines where we use Emacs? There&amp;rsquo;s a decent Stack Overflow question on the topic, but I want to dig into the various answers a bit and provide a slightly cleaner (IMHO) code snippet.
First let&amp;rsquo;s define that list of packages we want installed by adding a defvar form to our .</description><content:encoded>&lt;p>The interactive &lt;code>list-packages&lt;/code> command in modern Emacsen is handy for
finding and trying out new packages, but once we&amp;rsquo;ve found packages we
want to use, how can we have them automatically installed on all
machines where we use Emacs? There&amp;rsquo;s
&lt;a href="http://stackoverflow.com/questions/10092322/how-to-automatically-install-emacs-packages-by-specifying-a-list-of-package-name">a decent Stack Overflow question on the topic&lt;/a>, but I
want to dig into the various answers a bit and provide a slightly
cleaner (IMHO) code snippet.&lt;/p>
&lt;p>First let&amp;rsquo;s define that list of packages we want installed by adding a
&lt;code>defvar&lt;/code> form to our &lt;code>.emacs&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defvar my/packages
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>(abc-mode
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">;; ⋮&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> zygospore))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Now, the obvious part of this problem is using &lt;code>package-installed-p&lt;/code>
to check if each named package is installed and then installing the
missing ones. The less obvious part is that we may need to call
&lt;code>package-refresh-contents&lt;/code> to get the package repository data
(especially on the first load) or else we&amp;rsquo;ll get errors. High-level,
there are four ways I know of to approach this problem:&lt;/p>
&lt;ol>
&lt;li>Always call &lt;code>package-refresh-contents&lt;/code>.&lt;/li>
&lt;li>Check if &lt;code>package-archive-contents&lt;/code> is non-nil.&lt;/li>
&lt;li>Test if &lt;code>package-user-dir&lt;/code> exists.&lt;/li>
&lt;li>Refresh if any packages are missing.&lt;/li>
&lt;/ol>
&lt;p>Number one works buts is extremely inefficient&amp;ndash;I don&amp;rsquo;t want to wait
for a package repo fetch every time I start Emacs.&lt;/p>
&lt;p>Two and three have a fatal flaw: just because we have &lt;em>some&lt;/em> package
data doesn&amp;rsquo;t mean that we have the &lt;em>latest&lt;/em> data. So it&amp;rsquo;s entirely
possible that we don&amp;rsquo;t know about a recent package that the user wants
to install&amp;ndash;&lt;em>errors again.&lt;/em>&lt;/p>
&lt;p>The fourth method is the way to go. Surprising no one&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>,
&lt;a href="https://twitter.com/bbatsov">@bbatsov&lt;/a> shows up with &lt;a href="http://stackoverflow.com/questions/10092322/how-to-automatically-install-emacs-packages-by-specifying-a-list-of-package-name#answer-10102154">the right answer&lt;/a>.
But I do think this code could be a hair cleaner, so here&amp;rsquo;s my take:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#a6e22e">require&lt;/span> &lt;span style="color:#e6db74">&amp;#39;cl-lib&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(defun my/install-packages ()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Ensure the packages I use are installed. See `my/packages&amp;#39;.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">let&lt;/span> ((missing-packages (cl-remove-if &lt;span style="color:#a6e22e">#&amp;#39;&lt;/span>package-installed-p my/packages)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (when missing-packages
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (message &lt;span style="color:#e6db74">&amp;#34;Installing %d missing package(s)&amp;#34;&lt;/span> (&lt;span style="color:#a6e22e">length&lt;/span> missing-packages))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (package-refresh-contents)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">mapc&lt;/span> &lt;span style="color:#a6e22e">#&amp;#39;&lt;/span>package-install missing-packages))))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(my/install-packages)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Closing notes:&lt;/p>
&lt;ul>
&lt;li>The function&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> exists so that you can invoke it manually (&lt;code>M-x my/install-packages RET&lt;/code>) if you&amp;rsquo;ve changed &lt;code>my/packages&lt;/code> at
runtime.&lt;/li>
&lt;li>Keep in mind that re-evaluating &lt;code>my/packages&lt;/code> after changing it will
not do anything because &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/eintr/defvar.html">that&amp;rsquo;s how &lt;code>defvar&lt;/code> works&lt;/a>. Temporarily change
&lt;code>defvar&lt;/code> to &lt;code>setq&lt;/code> and you&amp;rsquo;ll be good to go.&lt;/li>
&lt;li>&lt;code>cl-lib&lt;/code> is required for &lt;code>cl-remove-if&lt;/code>. How Elisp has made it this
far without a &lt;code>filter&lt;/code> function, I don&amp;rsquo;t know.&lt;/li>
&lt;li>I&amp;rsquo;m not entirely sure if &lt;code>nil&lt;/code> punning is idiomatic elisp or if
there&amp;rsquo;s a more appropriate way to check for empty lists. Anyone
know?&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Bozhidar Batsov is killing it in the Emacs community right now and you should probably be following him.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>Rather than including what is currently the function body at the top level of the &lt;code>.emacs&lt;/code> file.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div>
&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Switching to MELPA Stable: Why, How, What I Learned</title><link>https://camdez.com/blog/2014/12/02/switching-to-melpa-stable/</link><pubDate>Tue, 02 Dec 2014 09:23:59 -0600</pubDate><guid>https://camdez.com/blog/2014/12/02/switching-to-melpa-stable/</guid><description>&lt;h2 id="background">Background&lt;/h2>
&lt;p>Writing &lt;a href="http://camdez.com/blog/2014/11/17/uproject-checkbox-dot-el/">my first Emacs package&lt;/a> a couple months ago left me more cognizant of how &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Packaging.html">Emacs&amp;rsquo; packaging system&lt;/a> is put together and raised questions about how I use its capabilities. I had been installing all of my packages from &lt;a href="http://melpa.org">MELPA&lt;/a>, but now, as a fancy-schmancy &lt;em>package author&lt;/em> I&amp;rsquo;d become intensely aware that MELPA builds its packages based on the latest commit in a project&amp;rsquo;s repository&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>. Suddenly I&amp;rsquo;d become paranoid about exactly what I pushed to the master branch of my project and worried about leaving things in a broken state.&lt;/p>
&lt;p>Generally speaking, I keep the master branch on my projects in a functional state, and&amp;ndash;&lt;em>yes&lt;/em>&amp;ndash;I could adopt a development methodology whereby work is &lt;em>always&lt;/em> done on a development or feature branch and QA&amp;rsquo;d before being merged into master. But even if I have the inclination and discipline to manage my projects this way, all of my other Emacs packages are getting built from whatever happened to be pushed to master in their own project when the MELPA bot decided to make the rounds. I&amp;rsquo;ve run my fair share of beta software, but I don&amp;rsquo;t need every commit as it happens (&lt;em>cutting vs. bleeding edge&lt;/em>).&lt;/p>
&lt;p>As it turns out, there&amp;rsquo;s a new kid on the block&amp;ndash;&lt;a href="http://stable.melpa.org">MELPA Stable&lt;/a>&amp;ndash;and she&amp;rsquo;s come to solve this exact problem.&lt;/p></description><content:encoded>&lt;h2 id="background">Background&lt;/h2>
&lt;p>Writing &lt;a href="http://camdez.com/blog/2014/11/17/uproject-checkbox-dot-el/">my first Emacs package&lt;/a> a couple months ago left me more cognizant of how &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Packaging.html">Emacs&amp;rsquo; packaging system&lt;/a> is put together and raised questions about how I use its capabilities. I had been installing all of my packages from &lt;a href="http://melpa.org">MELPA&lt;/a>, but now, as a fancy-schmancy &lt;em>package author&lt;/em> I&amp;rsquo;d become intensely aware that MELPA builds its packages based on the latest commit in a project&amp;rsquo;s repository&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>. Suddenly I&amp;rsquo;d become paranoid about exactly what I pushed to the master branch of my project and worried about leaving things in a broken state.&lt;/p>
&lt;p>Generally speaking, I keep the master branch on my projects in a functional state, and&amp;ndash;&lt;em>yes&lt;/em>&amp;ndash;I could adopt a development methodology whereby work is &lt;em>always&lt;/em> done on a development or feature branch and QA&amp;rsquo;d before being merged into master. But even if I have the inclination and discipline to manage my projects this way, all of my other Emacs packages are getting built from whatever happened to be pushed to master in their own project when the MELPA bot decided to make the rounds. I&amp;rsquo;ve run my fair share of beta software, but I don&amp;rsquo;t need every commit as it happens (&lt;em>cutting vs. bleeding edge&lt;/em>).&lt;/p>
&lt;p>As it turns out, there&amp;rsquo;s a new kid on the block&amp;ndash;&lt;a href="http://stable.melpa.org">MELPA Stable&lt;/a>&amp;ndash;and she&amp;rsquo;s come to solve this exact problem.&lt;/p>
&lt;p>MELPA Stable contains only stable versions of packages&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>. This means we&amp;rsquo;re getting new versions of packages when their maintainers feel that the version is ready to ship, rather than any time they make a change to their code.&lt;/p>
&lt;p>Stable is also quite cleverly implemented, requiring only a single git tag in &lt;a href="http://semver.org">semver&lt;/a> format to define a release. This not only makes life easy for package maintainers, but promoting semver is good for everyone (&lt;em>even end users!&lt;/em>), because a consistent scheme for denoting version compatibility means that developers can write more reliable software.&lt;/p>
&lt;h2 id="how-to-switch-to-melpa-stable">How to Switch to MELPA Stable&lt;/h2>
&lt;p>If you&amp;rsquo;re interested in taking the plunge&amp;ndash;and don&amp;rsquo;t worry, it&amp;rsquo;s easy to switch back&amp;ndash;the first thing to know is that not every package on MELPA is available via MELPA Stable&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>. If the package creator has not yet defined a stable release, the package will not appear on Stable. Before switching, you&amp;rsquo;ll probably want to think through the packages you consider critical to your Emacs workflow and type their names into the filter box on the &lt;a href="http://stable.melpa.org">MELPA Stable site&lt;/a> to discover if they are available. It &lt;em>is&lt;/em> possible to pull packages from two repositories but it&amp;rsquo;s not trivial and I won&amp;rsquo;t be covering it here.&lt;/p>
&lt;p>Still with me? Let&amp;rsquo;s get started! The first step, naturally, is to open your &lt;code>.emacs&lt;/code> (or &lt;code>.emacs.d/init.el&lt;/code>) and change your &lt;code>package-archives&lt;/code> form to look like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(add-to-list &lt;span style="color:#e6db74">&amp;#39;package-archives&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;melpa-stable&amp;#34;&lt;/span> &lt;span style="color:#f92672">.&lt;/span> &lt;span style="color:#e6db74">&amp;#34;http://stable.melpa.org/packages/&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">t&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Now we&amp;rsquo;re set to fetch packages from MELPA Stable, but there are a few more steps to make sure your current set-up keeps on trucking:&lt;/p>
&lt;p>If you don&amp;rsquo;t already have one, I&amp;rsquo;d recommend creating a list in your &lt;code>.emacs&lt;/code> file of packages that you use / always want installed. We can kick-start this process by first adding the following to the file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defvar my/packages
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>With point after the &lt;code>'&lt;/code> character, type &lt;code>C-0 M-: package-activated-list RET&lt;/code> to insert a list of the currently activated packages:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defvar my/packages
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>(artbollocks-mode ace-jump-mode auto-complete checkbox)) &lt;span style="color:#75715e">; your list will vary&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>You may see a few items in your list that you&amp;rsquo;re not familiar with&amp;ndash;feel free to remove anything that you don&amp;rsquo;t recognize as something you use. These packages are likely to be dependencies of other packages that you use, and they will be automatically included as needed later on. Such packages might include things like &lt;code>queue&lt;/code>, &lt;code>dash&lt;/code>, &lt;code>pcache&lt;/code>, &lt;code>popup&lt;/code>, &lt;code>pkg-info&lt;/code>, etc.&lt;/p>
&lt;p>One &amp;ldquo;gotcha&amp;rdquo; of the upgrade process is that the faux version numbers MELPA generates (e.g. &lt;code>20141116.1658&lt;/code>) give the appearance of being higher versions than the proper version numbers from MELPA Stable (e.g. &lt;code>0.2.0&lt;/code>), thus if you have existing packages installed, the package system will never prefer the Stable version, believing that it&amp;rsquo;s outdated. To solve this you&amp;rsquo;ll want to delete all of your existing packages. This is easy:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>$ rm -rf ~/.emacs.d/elpa&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Next we will use our new &lt;code>my/packages&lt;/code> list to tell Emacs to install all of these packages when it starts (here I&amp;rsquo;m using the exact code I outlined in &lt;a href="http://camdez.com/blog/2014/12/07/automatically-installing-your-emacs-packages/">a previous blog post&lt;/a>), so add this to your Emacs config after the &lt;code>my/packages&lt;/code> definition:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#a6e22e">require&lt;/span> &lt;span style="color:#e6db74">&amp;#39;cl-lib&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(defun my/install-packages ()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Ensure the packages I use are installed. See `my/packages&amp;#39;.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">let&lt;/span> ((missing-packages (cl-remove-if &lt;span style="color:#a6e22e">#&amp;#39;&lt;/span>package-installed-p my/packages)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (when missing-packages
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (message &lt;span style="color:#e6db74">&amp;#34;Installing %d missing package(s)&amp;#34;&lt;/span> (&lt;span style="color:#a6e22e">length&lt;/span> missing-packages))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (package-refresh-contents)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#a6e22e">mapc&lt;/span> &lt;span style="color:#a6e22e">#&amp;#39;&lt;/span>package-install missing-packages))))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(my/install-packages)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>With a little luck, you&amp;rsquo;re all set! Restart Emacs. It may take a minute for it to install all of your packages, but if it all appears to finish without error, you&amp;rsquo;re good to go!&lt;/p>
&lt;p>If you encounter errors, continue with the next section.&lt;/p>
&lt;h2 id="robustifying-your-config">Robustifying your Config&lt;/h2>
&lt;p>If you encounter errors after restarting Emacs, it&amp;rsquo;s likely that your configuration assumed the presence of some package that wasn&amp;rsquo;t re-installed&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>. Usually you can locate the general source of the error from the error message. For example:&lt;/p>
&lt;pre tabindex="0">&lt;code>Warning (initialization): An error occurred while loading `/Users/camdez/.emacs.d/init.el&amp;#39;:
Symbol&amp;#39;s function definition is void: keyfreq-mode
To ensure normal operation, you should investigate and remove the
cause of the error in your initialization file. Start Emacs with
the `--debug-init&amp;#39; option to view a complete error backtrace.
&lt;/code>&lt;/pre>&lt;p>In this case we can tell that we referenced &lt;code>keyfreq-mode&lt;/code> before the package which defines it had been loaded. To get out of this situation we have three options:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Remove the offending configuration lines.&lt;/strong> We can simply find the reference to &lt;code>keyfreq-mode&lt;/code> and remove it (or comment it out), but we probably added that for a reason so this should be our last resort.&lt;/li>
&lt;li>&lt;strong>Install the missing package.&lt;/strong> Ultimately this is what we want to do. We can typically infer the name of the package by guessing or by searching on &lt;a href="http://stable.melpa.org">stable.melpa.org&lt;/a>. For example, &lt;code>keyfreq-mode&lt;/code> is defined by the package &lt;code>keyfreq&lt;/code>. Once we know the package name we can add it to our &lt;code>my/packages&lt;/code> list and restart Emacs.&lt;/li>
&lt;li>&lt;strong>Make our config robust against the missing package.&lt;/strong> Even if we ultimately go with option #2, it&amp;rsquo;s a great idea to make our configuration load whether or not any particular package exists. This means that we can get our (bare-bones) config up and running in any environment, regardless of package availability, including a complete network outage. A complete discussion of this is beyond the scope of this article, but a good starting approach is to wrap the relevant configuration lines in a conditional call which loads the desired package and only executes the configuration line if it succeeds. To do this properly we&amp;rsquo;ll need to know the symbol used on the &lt;code>(provide '...)&lt;/code> line in the package&amp;rsquo;s source code. Once we have that we can do something like the following:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(when (&lt;span style="color:#a6e22e">require&lt;/span> &lt;span style="color:#e6db74">&amp;#39;keyfreq&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> &lt;span style="color:#e6db74">&amp;#39;no-error&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (keyfreq-mode &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#75715e">; configuration of keyfreq&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (keyfreq-autosave-mode &lt;span style="color:#ae81ff">1&lt;/span>)) &lt;span style="color:#75715e">; more configuration of keyfreq&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Once we&amp;rsquo;ve taken care of one piece of the configuration like this, we can restart Emacs and see if we have more success. If we have another error, we repeat the process. Admittedly this is a bit of a hassle, but along the way we improve our Emacs config such that it will continue work in a variety of different environments (missing packages, different versions, etc.).&lt;/p>
&lt;p>One final note: if you manage to damage your config file to such a degree that you can no longer use Emacs to edit the file, you can always invoke Emacs with an argument instructing it not to load your config file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>$ emacs -q ~/.emacs&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>This will leave you without any of your customizations, but it will allow you to edit your config file back to a functional state.&lt;/p>
&lt;h2 id="my-experience">My Experience&lt;/h2>
&lt;p>&lt;a href="https://github.com/camdez/emacs.d/commit/52fa0b582a1d00b31a92ddeec29dbde9dd0ad669">When I switched to MELPA Stable&lt;/a> last November, I found that most of the packages I use were already available. The notable exceptions were &lt;code>guide-key&lt;/code>, &lt;code>yaml-mode&lt;/code>, and &lt;code>idomenu&lt;/code>. I &lt;a href="https://github.com/kai2nenobu/guide-key/issues/28">opened an issue for guide-key&lt;/a>, added a +1 on &lt;a href="https://github.com/yoshiki/yaml-mode/issues/22">the relevant yaml-mode issue&lt;/a>, and emailed the author of idomenu, asking to get the packages uploaded to GitHub and tagged with releases for MELPA Stable. These package maintainers have been unanimously awesome, and all of the packages have since been added to Stable.&lt;/p>
&lt;p>If you find yourself requesting that package authors / maintainers prepare their package for MELPA Stable, please feel free to use &lt;a href="https://gist.github.com/camdez/48a4fd2bb3a05572f0a5">my YASnippet&lt;/a> which explains what MELPA Stable is, why it matters, and exactly how to add their package.&lt;/p>
&lt;p>Last but not least, between the time I first switched to Stable and now, I&amp;rsquo;ve personally added / updated four MELPA package recipes for Stable (&lt;a href="https://github.com/milkypostman/melpa/commit/ecd670e645eb48259c502c4cbc1e02103e0a4526">checkbox&lt;/a>, &lt;a href="https://github.com/milkypostman/melpa/commit/60191ae7de2c8b65520d6b68a78caa92b386793e">goto-last-change&lt;/a>, &lt;a href="https://github.com/milkypostman/melpa/commit/bd00ad43bc4943cdba641c90baf55cf40e97e2eb">idomenu&lt;/a>, &lt;a href="https://github.com/milkypostman/melpa/commit/f86aee2479f99a09ab20794885a13bc9f697173b">org-table-comment&lt;/a>). It&amp;rsquo;s an easy way to scratch your own itch and make a small contribution to the Emacs community.&lt;/p>
&lt;p>That&amp;rsquo;s it! Enjoy your newfound stability!&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Actually the story is a bit more complex because MELPA recipes can pull code from a few different places (e.g. EmacsWiki), but pulling from Git master is probably the most common (and best) story.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>With real version numbers, not the timestamp-style identifiers regular MELPA is forced to generate!&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>At the time of writing, 40% of MELPA packages are available via MELPA Stable (955 / 2397).&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>A less likely possibility is that your config assumed the presence of a newer version of the package than that which was installed. In this case you don&amp;rsquo;t have a lot of options&amp;mdash;you&amp;rsquo;ll need to adapt your configuration to the older version of the package if you wish to stick with Melpa Stable.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs Hangouts</title><link>https://camdez.com/blog/2014/11/19/emacs-hangouts/</link><pubDate>Wed, 19 Nov 2014 19:00:22 -0600</pubDate><guid>https://camdez.com/blog/2014/11/19/emacs-hangouts/</guid><description>&lt;p>Two weeks ago I had the pleasure of participating in an Emacs-themed
Google Hangout arranged by &lt;a href="http://sachachua.com">Sacha Chua&lt;/a>, in which several of us
Emacs geeks got together and discussed what we&amp;rsquo;ve been working on,
questions we have about particular packages or workflows, etc.:&lt;/p></description><content:encoded>&lt;p>Two weeks ago I had the pleasure of participating in an Emacs-themed
Google Hangout arranged by &lt;a href="http://sachachua.com">Sacha Chua&lt;/a>, in which several of us
Emacs geeks got together and discussed what we&amp;rsquo;ve been working on,
questions we have about particular packages or workflows, etc.:&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
&lt;iframe src="https://www.youtube.com/embed/rmGTNzfit2A" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video">&lt;/iframe>
&lt;/div>
&lt;p>I don&amp;rsquo;t think any of use knew exactly what to expect, but we talked a
bit about the different autocomplete frameworks
(&lt;a href="http://cx4a.org/software/auto-complete/">auto-complete-mode&lt;/a> and &lt;a href="http://company-mode.github.io/">company-mode&lt;/a>), &lt;a href="http://orgmode.org">org-mode&lt;/a>,
&lt;a href="https://github.com/rejeep/wrap-region.el">wrap-region&lt;/a>, and I yapped a bit about Emacs testing tools and BDD.&lt;/p>
&lt;p>Today I got to fill in for Sacha and host the second of these
Hangouts:&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
&lt;iframe src="https://www.youtube.com/embed/NSvBMqnxAEo" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video">&lt;/iframe>
&lt;/div>
&lt;p>Today&amp;rsquo;s chat dove into &lt;a href="https://magit.vc/">magit&lt;/a> trickery, &lt;a href="https://github.com/rlister/org-present">org-present&lt;/a>, achieving
Vim parity via &lt;a href="http://www.emacswiki.org/Evil">evil-mode&lt;/a>, &lt;a href="https://github.com/jwiegley/use-package">use-package&lt;/a>, and switching to
&lt;a href="http://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard">Dvorak&lt;/a>.&lt;/p>
&lt;p>Many thanks to &lt;a href="https://twitter.com/@jjasghar">@jjasghar&lt;/a>, &lt;a href="https://twitter.com/@amirrajan">@amirrajan&lt;/a>, &lt;a href="https://twitter.com/@mwfogleman">@mwfogleman&lt;/a> for
speaking and sharing their expertise. I&amp;rsquo;m really enjoying these and I
hope interest stays high so we can keep them going.&lt;/p>
&lt;p>Finally, sorry for the technical difficulties at the beginning of the
recording&amp;ndash;I really hope everyone who wanted to join was able to! This
was my first time hosting a Hangout-on-Air and it&amp;rsquo;s a bit quirky. For
future reference, the thing that really tripped me up is how little
integration there is between the Hangout and the event page for it.
The RSVP list has nothing to do with the people who get to participate
in the Hangout&amp;ndash;all it does is send a reminder to those people to view
the event&amp;ndash;and there&amp;rsquo;s no way to invite those people to become
participants once it has started. AFAIK the only thing you can do is
to copy the URL visible inside of the Hangout (not clearly marked for
&lt;em>participation&lt;/em> rather than &lt;em>viewing&lt;/em>) and post it on the event page
and / or the in-Hangout chat.&lt;/p>
&lt;p>Anyway, thanks for your patience and if I host another one I&amp;rsquo;ll know what
to do!&lt;/p>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>μProject: checkbox.el</title><link>https://camdez.com/blog/2014/11/17/uproject-checkbox-dot-el/</link><pubDate>Mon, 17 Nov 2014 09:31:34 -0600</pubDate><guid>https://camdez.com/blog/2014/11/17/uproject-checkbox-dot-el/</guid><description>&lt;p>I&amp;rsquo;ve been playing with Emacs in the evenings lately and writing a lot
of Elisp, and I just finished a little Emacs package for quickly
manipulating textual checkboxes (&lt;code>[ ]&lt;/code> / &lt;code>[x]&lt;/code>, etc.) in buffers, like
a simple version of &lt;a href="http://orgmode.org">org-mode&lt;/a>&amp;rsquo;s task manipulation, but available
everywhere. It&amp;rsquo;s called &lt;a href="https://github.com/camdez/checkbox.el">checkbox.el&lt;/a>.&lt;/p></description><content:encoded>&lt;p>I&amp;rsquo;ve been playing with Emacs in the evenings lately and writing a lot
of Elisp, and I just finished a little Emacs package for quickly
manipulating textual checkboxes (&lt;code>[ ]&lt;/code> / &lt;code>[x]&lt;/code>, etc.) in buffers, like
a simple version of &lt;a href="http://orgmode.org">org-mode&lt;/a>&amp;rsquo;s task manipulation, but available
everywhere. It&amp;rsquo;s called &lt;a href="https://github.com/camdez/checkbox.el">checkbox.el&lt;/a>.&lt;/p>
&lt;p>For example, if you have a simple to-do list in a Markdown file like
this:&lt;/p>
&lt;pre>&lt;code>- [ ] Buy gin&amp;lt;point&amp;gt;
- [ ] Buy tonic
&lt;/code>&lt;/pre>
&lt;p>And you invoke &lt;code>checkbox-toggle&lt;/code>, you&amp;rsquo;ll get the following:&lt;/p>
&lt;pre>&lt;code>- [x] Buy gin&amp;lt;point&amp;gt;
- [ ] Buy tonic
&lt;/code>&lt;/pre>
&lt;p>Invoke it again and you&amp;rsquo;re back to the original unchecked version.&lt;/p>
&lt;pre>&lt;code>- [ ] Buy gin&amp;lt;point&amp;gt;
- [ ] Buy tonic
&lt;/code>&lt;/pre>
&lt;p>Next, if we add a line without a checkbox&amp;hellip;&lt;/p>
&lt;pre>&lt;code>- [ ] Buy gin
- [ ] Buy tonic
- Buy limes&amp;lt;point&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>We can invoke the command again to insert a new checkbox.&lt;/p>
&lt;pre>&lt;code>- [ ] Buy gin
- [ ] Buy tonic
- [ ] Buy limes&amp;lt;point&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>&lt;code>checkbox.el&lt;/code> understands how to work with comments in programming
modes, tries to be smart about when and where it moves point (DWIM!),
allows for a fully custom set of &amp;ldquo;checkboxes&amp;rdquo; (e.g. &lt;code>TODO&lt;/code>, &lt;code>DONE&lt;/code>,
&lt;code>HOLD&lt;/code>), can remove checkboxes entirely with a universal argument
(&lt;code>C-u&lt;/code>), or directly select a particular checkbox state (rather than
cycling through them) when given a numeric prefix.&lt;/p>
&lt;p>It also has a fairly extensive test suite leveraging &lt;a href="http://www.gnu.org/software/emacs/manual/html_node/ert/">ert&lt;/a>,
&lt;a href="https://github.com/ecukes/ecukes">ecukes&lt;/a>, and &lt;a href="https://travis-ci.org/camdez/checkbox.el">continuous integration via Travis CI&lt;/a>. Check out
&lt;a href="https://github.com/camdez/checkbox.el">checkbox.el on GitHub&lt;/a> or install it via &lt;a href="http://melpa.org">MELPA&lt;/a> or
&lt;a href="https://marmalade-repo.org">Marmalade&lt;/a>!&lt;/p>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs: Rapid Buffer Navigation with Imenu</title><link>https://camdez.com/blog/2013/11/28/emacs-rapid-buffer-navigation-with-imenu/</link><pubDate>Thu, 28 Nov 2013 15:32:00 -0700</pubDate><guid>https://camdez.com/blog/2013/11/28/emacs-rapid-buffer-navigation-with-imenu/</guid><description>&lt;p>&lt;a href="https://twitter.com/krisajenkins">Kris Jenkins&lt;/a> wrote a great post last month about
&lt;a href="http://blog.jenkster.com/2013/10/a-tip-for-navigating-clojure-files-in-emacs.html">rapidly navigating Clojure files in Emacs&lt;/a> using
&lt;a href="https://github.com/emacs-helm/helm">Helm&lt;/a>&amp;ndash;definitely check it out. Helm is near the top of my
list of Emacs extensions I need to explore, but in the meantime I
thought I&amp;rsquo;d point out that&amp;rsquo;s there actually a great solution for this
use case in a stock Emacs installation&amp;ndash;&lt;code>imenu-mode&lt;/code>.&lt;/p></description><content:encoded>&lt;p>&lt;a href="https://twitter.com/krisajenkins">Kris Jenkins&lt;/a> wrote a great post last month about
&lt;a href="http://blog.jenkster.com/2013/10/a-tip-for-navigating-clojure-files-in-emacs.html">rapidly navigating Clojure files in Emacs&lt;/a> using
&lt;a href="https://github.com/emacs-helm/helm">Helm&lt;/a>&amp;ndash;definitely check it out. Helm is near the top of my
list of Emacs extensions I need to explore, but in the meantime I
thought I&amp;rsquo;d point out that&amp;rsquo;s there actually a great solution for this
use case in a stock Emacs installation&amp;ndash;&lt;code>imenu-mode&lt;/code>.&lt;/p>
&lt;p>Imenu is a really slick library by Ake Stenhoff and Lars Lindberg
which scans the open buffer and creates a menu of locations&amp;ndash;usually
representing top-level items like functions&amp;ndash;that you can rapidly
jump to. The mode gets just about everything right: it&amp;rsquo;s widely
supported, easily extensible, uses &lt;a href="http://www.gnu.org/software/emacs/manual/html_node/elisp/Overview-of-Markers.html#Overview-of-Markers">markers&lt;/a> to track
buffer locations (so they stay correct even as you edit the file),
supports auto-updating, and is available via either the GUI (for you
mousey types) or the keyboard. It&amp;rsquo;s really a stellar example of the
flexibility and extensibility of Emacs.&lt;/p>
&lt;p>Basic usage involves running the &lt;code>imenu&lt;/code> command (&lt;code>M-x imenu RET&lt;/code>)
and entering the name of the item you want to jump to. Hit &lt;code>TAB&lt;/code> to
see a list of all possible jump targets. (If you&amp;rsquo;re an &lt;a href="http://www.emacswiki.org/emacs/InteractivelyDoThings">ido&lt;/a> user,
check out &lt;a href="https://gist.github.com/magnars/2360578">this gist&lt;/a> from the always-wonderful
&lt;a href="https://twitter.com/magnars">Magnar Sveen&lt;/a> to get your integration on.)&lt;/p>
&lt;p>But honestly, a lot of the magic is in the GUI menu&amp;ndash;even for those
of us who usually neglect the mouse.&lt;/p>
&lt;p>You&amp;rsquo;ll need to run the &lt;code>imenu-add-menubar-index&lt;/code> command to get things
up and running but once you do you&amp;rsquo;ll see a new menu named &lt;code>Index&lt;/code> in
your menu bar:&lt;/p>
&lt;p>&lt;img src="https://camdez.com/images/blog/2013-11-28-emacs-rapid-buffer-navigation-with-imenu/imenu.png" alt="The eponymous Imenu menu.">&lt;/p>
&lt;p>Clicking an item in the menu will jump you directly to it.&lt;/p>
&lt;p>If you want the menu to be available automatically for certain modes,
all you have to do is add the trigger function to the respective mode
hooks, like so:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(add-hook &lt;span style="color:#e6db74">&amp;#39;clojure-mode-hook&lt;/span> &lt;span style="color:#e6db74">&amp;#39;imenu-add-menubar-index&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(add-hook &lt;span style="color:#e6db74">&amp;#39;emacs-lisp-mode-hook&lt;/span> &lt;span style="color:#e6db74">&amp;#39;imenu-add-menubar-index&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>One additional tweak that you&amp;rsquo;ll probably want to add to your
&lt;code>.emacs&lt;/code> file is to automatically rescan the buffer contents so that
new jump targets appear in the menu as they are added:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#66d9ef">setq&lt;/span> imenu-auto-rescan &lt;span style="color:#66d9ef">t&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Most Emacs modes (&lt;code>clojure-mode&lt;/code> included) already implement Imenu
support, but it&amp;rsquo;s actually pretty easy to extend Imenu&amp;rsquo;s functionality
to any kind of content we want to index. In fact, one of my favorite
uses is not even for programming&amp;ndash;it&amp;rsquo;s my extension to Markdown mode,
allowing me to jump to document section headers.&lt;/p>
&lt;p>The most full-featured way to implement Imenu for a mode is to
implement &lt;code>imenu-create-index-function&lt;/code>, providing a custom function
which creates a data structure in the format Imenu is expecting (see
&lt;code>imenu.el&lt;/code> for details), but the &lt;em>easiest&lt;/em> way is simply to provide a
regular expression for the items we want to match and let Imenu do the
rest.&lt;/p>
&lt;p>Here&amp;rsquo;s what that looks like for &lt;code>markdown-mode&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defvar camdez/markdown-imenu-generic-expression
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>((&lt;span style="color:#66d9ef">nil&lt;/span> &lt;span style="color:#e6db74">&amp;#34;^#\\s-+\\(.+\\)$&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(defun camdez/markdown-imenu-configure ()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">setq&lt;/span> imenu-generic-expression camdez/markdown-imenu-generic-expression))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(add-hook &lt;span style="color:#e6db74">&amp;#39;markdown-mode-hook&lt;/span> &lt;span style="color:#e6db74">&amp;#39;camdez/markdown-imenu-configure&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>This pattern will work for most any usage. We define a generic
expression (more on this in a sec), and when the given mode is
activated, we put that expression in &lt;code>imenu-generic-expression&lt;/code>, a
predefined location where Imenu expects to find such a thing (unless
you&amp;rsquo;ve provided a full &lt;code>imenu-create-index-function&lt;/code> implementation).&lt;/p>
&lt;p>The simplest version of this &amp;ldquo;generic expression&amp;rdquo;, shown here, is
&lt;code>(MENU-TITLE REGEXP INDEX)&lt;/code>; &lt;code>MENU-TITLE&lt;/code> defines where to nest the
new menu item (or &lt;code>nil&lt;/code>, as we do here, to put it at the top level),
&lt;code>REGEXP&lt;/code> is the regular expression matching the content we want to
index, and &lt;code>INDEX&lt;/code> specifies which piece of the match we want to
insert in the menu. We could pass &lt;code>0&lt;/code> to include the whole expression
in the menu, but in this case I&amp;rsquo;ve decide to match strings with look
like &lt;code># Foo&lt;/code>, but only put the &lt;code>Foo&lt;/code> part into the menu (note the
subpattern offset by &lt;code>\\(&lt;/code> and &lt;code>\\)&lt;/code>). Also notice that
&lt;code>imenu-generic-expression&lt;/code> is a list of lists so that you can provide
multiple patterns to match, each with their own rules on where to nest
and what to display.&lt;/p>
&lt;p>That&amp;rsquo;s really all there is to it. Let me know if you have any really
novel uses for Imenu, I&amp;rsquo;d love to hear about them!&lt;/p>&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs: Jump to Info from Command Documentation</title><link>https://camdez.com/blog/2013/11/27/emacs-jump-to-info-from-command-docs/</link><pubDate>Wed, 27 Nov 2013 15:06:00 -0700</pubDate><guid>https://camdez.com/blog/2013/11/27/emacs-jump-to-info-from-command-docs/</guid><description>One of the coolest things about Emacs is that it&amp;rsquo;s self-documenting. What this means is that for any piece of functionality in Emacs, we can ask the editor about that thing. We can ask it to tell us about any function (C-h f), variable (C-h v), key binding (C-h k) or even the mode(s) we&amp;rsquo;re currently in (C-h m). Most of the time this documentation is comprehensive and heavily cross-referenced. If you&amp;rsquo;re not using these commands, you absolutely should start today.</description><content:encoded>&lt;p>One of the coolest things about Emacs is that it&amp;rsquo;s
&lt;em>self-documenting&lt;/em>. What this means is that for any piece of
functionality in Emacs, we can ask the editor about that thing. We can
ask it to tell us about any function (&lt;code>C-h f&lt;/code>), variable (&lt;code>C-h v&lt;/code>),
key binding (&lt;code>C-h k&lt;/code>) or even the mode(s) we&amp;rsquo;re currently in (&lt;code>C-h m&lt;/code>). Most of the time this documentation is comprehensive and heavily
cross-referenced. If you&amp;rsquo;re not using these commands, you absolutely
should start today.&lt;/p>
&lt;p>Emacs also comes bundled with a detailed user manual (&lt;code>C-h r&lt;/code> &amp;ndash;
think, &lt;em>read&lt;/em> the manual), which is important when you don&amp;rsquo;t know
exactly what you&amp;rsquo;re looking for, or if you want to see a command in
the context of related functionality. Maybe you know about
&lt;code>kill-word&lt;/code> and &lt;code>kill-sentence&lt;/code> but they aren&amp;rsquo;t exactly what you&amp;rsquo;re
looking for &amp;ndash; the manual is the first place to check to learn about
(say) &lt;code>kill-sentence&lt;/code> or &lt;code>kill-sexp&lt;/code>.&lt;/p>
&lt;p>Somewhat less well-known is the handy &lt;code>Info-goto-emacs-command-node&lt;/code>
command (on &lt;code>C-h F&lt;/code>) which will take you directly to the Emacs manual
page that talks about a given command. But unless we&amp;rsquo;re coding in
Elisp, most of the time we work in terms of keystrokes and not command
names. Wouldn&amp;rsquo;t it be more useful if we could look at the
documentation for given key sequence and then, if we wanted more
information, easily jump to the corresponding manual page? Let&amp;rsquo;s code
that up:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defun camdez/Info-goto-from-command-help ()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Go to the Info node in the Emacs manual for the command
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">currently being viewed in `help-mode&amp;#39;.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">let&lt;/span> ((help-function (&lt;span style="color:#a6e22e">car&lt;/span> help-xref-stack-item))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (help-symbol (&lt;span style="color:#a6e22e">cadr&lt;/span> help-xref-stack-item)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if&lt;/span> (and (&lt;span style="color:#a6e22e">eq&lt;/span> help-function &lt;span style="color:#e6db74">&amp;#39;describe-function&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (commandp help-symbol))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (Info-goto-emacs-command-node help-symbol)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">error&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Info is only available for commands&amp;#34;&lt;/span>))))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>(Note that we have to do a couple tests on &lt;code>help-xref-stack-item&lt;/code>
because we can only jump into the manual for &lt;em>commands&lt;/em>, and not for
arbitrary functions or variables.)&lt;/p>
&lt;p>Now let&amp;rsquo;s bind that to the (previously unused) &lt;code>i&lt;/code> key in &lt;code>help-mode&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(eval-after-load &lt;span style="color:#e6db74">&amp;#39;help-mode&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>(define-key help-mode-map &lt;span style="color:#e6db74">&amp;#34;i&amp;#34;&lt;/span> &lt;span style="color:#e6db74">&amp;#39;camdez/Info-goto-from-command-help&lt;/span>))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>And we&amp;rsquo;re done! After putting that in your &lt;code>.emacs&lt;/code> file and
restarting Emacs (or reloading the config), try it out with something
like &lt;code>C-h k C-k&lt;/code> (&amp;ldquo;what does the &lt;code>C-k&lt;/code> keystroke do?&amp;rdquo;) and then press
&lt;code>i&lt;/code> in the &lt;code>*Help*&lt;/code> buffer.&lt;/p>
&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs: Show Buffer File Name</title><link>https://camdez.com/blog/2013/11/14/emacs-show-buffer-file-name/</link><pubDate>Thu, 14 Nov 2013 22:53:00 -0700</pubDate><guid>https://camdez.com/blog/2013/11/14/emacs-show-buffer-file-name/</guid><description>I share my Emacs configuration on GitHub, but the truth is that most of the fun stuff happens in my experimental.el file (mentioned previously), which I don&amp;rsquo;t share. It&amp;rsquo;s growing rather large and some of the contents are fairly mature so I&amp;rsquo;m going to going to work on moving more things into my stable config and I may as well share them along the way.
One little utility I&amp;rsquo;ve grown quite fond of is my show-buffer-file-name utility:</description><content:encoded>&lt;p>I share &lt;a href="https://github.com/camdez/dotfiles">my Emacs configuration on GitHub&lt;/a>, but the truth is
that most of the fun stuff happens in my &lt;code>experimental.el&lt;/code> file
(&lt;a href="https://camdez.com/blog/2012/08/06/emacs-tab-width-woes">mentioned previously&lt;/a>), which I don&amp;rsquo;t share.
It&amp;rsquo;s growing rather large and some of the contents are fairly mature
so I&amp;rsquo;m going to going to work on moving more things into my stable
config and I may as well share them along the way.&lt;/p>
&lt;p>One little utility I&amp;rsquo;ve grown quite fond of is my
&lt;code>show-buffer-file-name&lt;/code> utility:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defun camdez/show-buffer-file-name ()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Show the full path to the current file in the minibuffer.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">let&lt;/span> ((file-name (buffer-file-name)))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if&lt;/span> file-name
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">progn&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (message file-name)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (kill-new file-name))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">error&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Buffer not visiting a file&amp;#34;&lt;/span>))))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&amp;hellip;which I keep on &lt;!-- raw HTML omitted -->C-x C-p&lt;!-- raw HTML omitted -->, overriding the fairly useless
&lt;code>mark-page&lt;/code> command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(global-set-key (kbd &lt;span style="color:#e6db74">&amp;#34;C-x C-p&amp;#34;&lt;/span>) &lt;span style="color:#e6db74">&amp;#39;camdez/show-buffer-file-name&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>It&amp;rsquo;s fairly self-explanatory but notice that it not only shows you the
path to the current file but also leaves it on the &lt;code>kill-ring&lt;/code>. I
find this to be pretty useful when switching to the shell to operate
on a file (though obviously there are lots of ways to do such things
&lt;em>within&lt;/em> Emacs), and for pasting filenames into GitHub discussions,
emails, or the company chat room.&lt;/p>
&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs: Tab Width Woes</title><link>https://camdez.com/blog/2012/08/06/emacs-tab-width-woes/</link><pubDate>Mon, 06 Aug 2012 20:03:00 -0700</pubDate><guid>https://camdez.com/blog/2012/08/06/emacs-tab-width-woes/</guid><description>Emacs uses the value of the tab-width variable to decide how wide tab characters should be displayed. Setting tab-width is usually one of the first customizations Emacs newbies make:
(setq-default tab-width 2) Displaying tab characters at whatever width you prefer works well for most applications but eventually fails when files mix tab and space characters and (invariably) make assumptions about what the width of those characters will be.
One particularly conspicuous offender is the Emacs (Lisp) source code.</description><content:encoded>&lt;p>Emacs uses the value of the &lt;code>tab-width&lt;/code> variable to decide how wide
tab characters should be displayed. Setting &lt;code>tab-width&lt;/code> is usually
one of the first customizations Emacs newbies make:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(setq-default tab-width &lt;span style="color:#ae81ff">2&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Displaying tab characters at whatever width you prefer works well for
most applications but eventually fails when files mix tab and space
characters and (invariably) make assumptions about what the width of
those characters will be.&lt;/p>
&lt;p>One particularly conspicuous offender is the Emacs (Lisp) source code.
I feel like I&amp;rsquo;ve recently reached a new level of skill with Emacs&amp;ndash;a
point where I&amp;rsquo;m finally effective enough with it that I write Emacs
Lisp to improve my workflow &lt;em>as a regular part of my daily workflow.&lt;/em>
One consequence of this is that I spend a lot of time reading Emacs
source code, looking for either implementation clues or undocumented
gems. It&amp;rsquo;s a hell of a lot of fun but unfortunately it means that I
spend a lot of time alternating between my preferred &lt;code>tab-width&lt;/code> of 2
and 8, the size the Emacs source thinks a tab should be.&lt;/p>
&lt;p>My initial solution was to throw together a quick function to toggle
between these two values, which I bound to &lt;code>C-c TAB&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defun camdez/toggle-tab-width ()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Toggles `tab-width&amp;#39; between 8 and 2.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">setq&lt;/span> tab-width
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#a6e22e">=&lt;/span> tab-width &lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">8&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">2&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (message &lt;span style="color:#e6db74">&amp;#34;Tab width set to %d&amp;#34;&lt;/span> tab-width))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>It could definitely use a lot of improvement but that&amp;rsquo;s the kind of
thing that I now tend to hammer out quickly and improve later if the
concept survives the prototyping phase. I keep this type of hacks in
a file called &lt;code>experimental.el&lt;/code> which I load from my Emacs
initialization file. I also keep this file in the &lt;code>x&lt;/code> register so that
I can immediately jump to it with &lt;code>C-x r j x&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(load-library &lt;span style="color:#e6db74">&amp;#34;experimental&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(set-register ?x (&lt;span style="color:#a6e22e">cons&lt;/span> &lt;span style="color:#e6db74">&amp;#39;file&lt;/span> &lt;span style="color:#e6db74">&amp;#34;~/.emacs.d/experimental.el&amp;#34;&lt;/span>))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>But I was never thrilled about the idea of having to manually toggle
that value, even if it was a couple keystrokes away. I started
scheming about ways to analyze source files to determine what
&lt;code>tab-width&lt;/code> they implied (certainly possible&amp;ndash;not a lot of fun) when
I realized that the Emacs source was really the only place where I was
having this problem.&lt;/p>
&lt;p>My next thought, then, was to create a hook that would fire whenever a
file was opened, examine the file path, and set the &lt;code>tab-width&lt;/code> to 8
if it was part of the Emacs distribution. But hardcoding a file path?
That&amp;rsquo;s a bit distasteful.&lt;/p>
&lt;p>I realized today that there&amp;rsquo;s a wonderfully effective, simple solution
called &amp;ldquo;Directory Variables&amp;rdquo;. All you have to do is put a file called
&lt;code>dir-locals.el&lt;/code> in a directory and whenever Emacs visits a file in
that directory (or one of it&amp;rsquo;s subdirectories), those local variables
will be loaded and applied. In fact, there&amp;rsquo;s even a command that will
build the file contents for us. Here&amp;rsquo;s how we can set it up for the
Emacs source:&lt;/p>
&lt;ol>
&lt;li>Open a file in the Emacs lisp directory. The easiest way to this is
pull up the documentation for a function in the standard distribution
(say, &lt;code>occur&lt;/code>) with &lt;code>C-h f occur RET&lt;/code>, tab to the file name
it says it&amp;rsquo;s defined in, and hit &lt;code>RET&lt;/code> to jump to that
function&amp;rsquo;s definition.&lt;/li>
&lt;li>Next, run &lt;code>M-x add-dir-local-variable RET&lt;/code>.&lt;/li>
&lt;li>Hit &lt;code>RET&lt;/code> to accept the default of only applying this
variable to &lt;code>emacs-lisp-mode&lt;/code>.&lt;/li>
&lt;li>Enter &lt;code>tab-width&lt;/code> as the variable to set.&lt;/li>
&lt;li>Enter &lt;code>8&lt;/code> as the value of the variable.&lt;/li>
&lt;li>You&amp;rsquo;ll now be looking at a new file with contents like this:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">;;; Directory Local Variables&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">;;; See Info node `(emacs) Directory Variables&amp;#39; for more information.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>((emacs-lisp-mode
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (tab-width &lt;span style="color:#f92672">.&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>)))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Save the file with &lt;code>C-x C-s&lt;/code> and you&amp;rsquo;re good to go. Now whenever you
open a file in the Emacs source code it&amp;rsquo;ll have the &lt;code>tab-width&lt;/code>
properly set to 8.&lt;/p>
&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs: Save, Not Search!</title><link>https://camdez.com/blog/2012/03/26/emacs-save-not-search/</link><pubDate>Mon, 26 Mar 2012 13:39:00 -0700</pubDate><guid>https://camdez.com/blog/2012/03/26/emacs-save-not-search/</guid><description>I&amp;rsquo;m a compulsive saver. No, not with money&amp;ndash;files. It probably comes from using Photoshop in the 90s, but regardless, I probably save hundreds of times a day.
Sometimes in Emacs I fat-finger C-x C-s (save-buffer) and end up landing in search mode instead (C-s&amp;ndash;isearch-forward). Then I have to C-g or ESC ESC ESC my way out before actually saving.
I recently learned (again, from having clumsy fingers) that isearch-mode actually understands C-x C-s, so you can just hit it to save the file and exit search mode in one go.</description><content:encoded>&lt;p>I&amp;rsquo;m a compulsive saver. No, not with money&amp;ndash;files. It probably comes
from using Photoshop in the 90s, but regardless, I probably save
hundreds of times a day.&lt;/p>
&lt;p>Sometimes in Emacs I fat-finger &lt;code>C-x C-s&lt;/code> (&lt;code>save-buffer&lt;/code>) and end up
landing in search mode instead (&lt;code>C-s&lt;/code>&amp;ndash;&lt;code>isearch-forward&lt;/code>). Then I
have to &lt;code>C-g&lt;/code> or &lt;code>ESC ESC ESC&lt;/code> my way out before actually saving.&lt;/p>
&lt;p>I recently learned (again, from having clumsy fingers) that
&lt;code>isearch-mode&lt;/code> actually understands &lt;code>C-x C-s&lt;/code>, so you can just hit it
to save the file and exit search mode in one go. In fact, it actually
seems to be pretty clever about only eating keystrokes it understands
and otherwise exiting &lt;code>isearch-mode&lt;/code> and passing them along. Check out
the docs for &lt;code>isearch-other-meta-char&lt;/code> for details.&lt;/p>
&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs: transpose-lines</title><link>https://camdez.com/blog/2012/02/21/emacs-transpose-lines/</link><pubDate>Tue, 21 Feb 2012 16:58:00 -0700</pubDate><guid>https://camdez.com/blog/2012/02/21/emacs-transpose-lines/</guid><description>The command transpose-lines, bound to C-x C-t by default, is a standard Emacs workhorse. It exchanges the line point is on with the previous line. Because it also moves point down a line we can invoke it repeatedly to &amp;ldquo;drag&amp;rdquo; a line down:
one two two two two two&amp;lt; one three three three three --&amp;gt; three&amp;lt; --&amp;gt; one --&amp;gt; four --&amp;gt; four four four four&amp;lt; one five five five five five&amp;lt; one &amp;lt; This is particularly handy for reordering lists.</description><content:encoded>&lt;p>The command &lt;code>transpose-lines&lt;/code>, bound to &lt;code>C-x C-t&lt;/code> by default, is a
standard Emacs workhorse. It exchanges the line point is on with the
previous line. Because it also moves point down a line we can invoke
it repeatedly to &amp;ldquo;drag&amp;rdquo; a line down:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>one two two two two
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>two&amp;lt; one three three three
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>three --&amp;gt; three&amp;lt; --&amp;gt; one --&amp;gt; four --&amp;gt; four
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>four four four&amp;lt; one five
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>five five five five&amp;lt; one
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>This is particularly handy for reordering lists. We can also give it a
numeric argument or a negative argument and these do what you&amp;rsquo;d expect
(&lt;code>C-h f transpose-lines RET&lt;/code> for details), transposing over distances
or in reverse direction.&lt;/p>
&lt;p>But what I did &lt;em>not&lt;/em> know is that if invoked with a &lt;code>M-0&lt;/code> prefix, it
will exchange the line point is in with the line mark is in,
essentially allowing us to insert a line at an arbitrary location we
had previously marked.&lt;/p>
&lt;p>I have to say, this definitely beats my typical &lt;code>C-a C-k C-k (movement) C-y&lt;/code> workflow, assuming I know the destination ahead of
time.&lt;/p>
&lt;p>&lt;strong>Update:&lt;/strong> turns out I got a little excited and didn&amp;rsquo;t think through
the details of what I was saying. The semantics of those two scenarios
are different&amp;ndash;&lt;code>M-0 C-x C-t&lt;/code> &lt;em>swaps&lt;/em> the two lines whereas the other
simply &lt;em>inserts&lt;/em> the killed line, but doesn&amp;rsquo;t move the line at point
to where mark was. &lt;em>Mea culpa.&lt;/em>&lt;/p>
&lt;p>Here&amp;rsquo;s a quick-and-dirty function for your &lt;code>.emacs&lt;/code> to get the
behavior I claimed:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defun move-line-to-point ()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Insert the line mark is in before the current line.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive &lt;span style="color:#e6db74">&amp;#34;*&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (save-excursion
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (exchange-point-and-mark)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (beginning-of-line)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (kill-whole-line)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (exchange-point-and-mark)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (beginning-of-line)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (yank)))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Emacs Windowing Improvements</title><link>https://camdez.com/blog/2007/02/28/emacs-windowing-improvements/</link><pubDate>Wed, 28 Feb 2007 00:00:00 -0700</pubDate><guid>https://camdez.com/blog/2007/02/28/emacs-windowing-improvements/</guid><description>One element of Emacs&amp;rsquo;s behavior that annoyed me for quite a while is Emacs&amp;rsquo;s handling of windows (or rather, the natural consequence of having multiple windows which arrive at various times). Often I end up with a random window that I really don&amp;rsquo;t want to be there. Usually the window is occupied by a temporary buffer (or something like *info*) which has outstayed its welcome.
In most cases point is not in the window, so I have to switch to the other window and then kill the buffer with C-x o C-x k RET.</description><content:encoded>&lt;p>One element of Emacs&amp;rsquo;s behavior that annoyed me for quite a while is
Emacs&amp;rsquo;s handling of windows (or rather, the natural consequence of
having multiple windows which arrive at various times). Often I end up
with a random window that I really don&amp;rsquo;t want to be there. Usually the
window is occupied by a temporary buffer (or something like &lt;code>*info*&lt;/code>)
which has outstayed its welcome.&lt;/p>
&lt;p>In most cases point is not in the window, so I have to switch to the
other window and then kill the buffer with &lt;!-- raw HTML omitted -->C-x o C-x k RET&lt;!-- raw HTML omitted -->.
But then I still have the window sitting around occupying space in
front of the code I was actually trying to look at. So next I
eliminate the window with &lt;!-- raw HTML omitted -->C-x 0&lt;!-- raw HTML omitted -->.&lt;/p>
&lt;p>You see why this is annoying. I&amp;rsquo;m using seven keystrokes (&lt;!-- raw HTML omitted -->C-x o
C-x k RET C-x 0&lt;!-- raw HTML omitted -->) just to clean up the mess from a temporary
buffer. Of course this is Emacs, so a solution is only an elisp hack
away. So I defined two new functions which relieve my woes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(defun delete-window-replacement (&lt;span style="color:#66d9ef">&amp;amp;optional&lt;/span>&lt;span style="color:#75715e">; p)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Kill current window. If called with PREFIX, kill the buffer too.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive &lt;span style="color:#e6db74">&amp;#34;P&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if&lt;/span> p
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (kill-buffer &lt;span style="color:#66d9ef">nil&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (delete-window))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(defun delete-other-windows-replacement (&lt;span style="color:#66d9ef">&amp;amp;optional&lt;/span>&lt;span style="color:#75715e">; p)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Make the selected window fill its frame. If called with PREFIX,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">kill all other visible buffers.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (interactive &lt;span style="color:#e6db74">&amp;#34;P&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (&lt;span style="color:#66d9ef">if&lt;/span> p
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (dolist (window (window-list))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (unless (&lt;span style="color:#a6e22e">equal&lt;/span> (window-buffer window) (current-buffer))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (kill-buffer (window-buffer window)))))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (delete-other-windows))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>I bind these in place of the original delete-window (&lt;!-- raw HTML omitted -->C-x 0&lt;!-- raw HTML omitted -->) and delete-other-windows (&lt;!-- raw HTML omitted -->C-x 1&lt;!-- raw HTML omitted -->):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(global-set-key &lt;span style="color:#e6db74">&amp;#34;C-x0&amp;#34;&lt;/span> &lt;span style="color:#e6db74">&amp;#39;delete-window-replacement&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(global-set-key &lt;span style="color:#e6db74">&amp;#34;C-x1&amp;#34;&lt;/span> &lt;span style="color:#e6db74">&amp;#39;delete-other-windows-replacement&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>My functions work exactly as the built-ins they replace unless they
are given a prefix argument (in fact they call the original
functions). So now, if point is in a window I don&amp;rsquo;t want, which
contains a buffer I don&amp;rsquo;t want, all I have to do is &lt;!-- raw HTML omitted -->C-u C-x
0&lt;!-- raw HTML omitted --> and I&amp;rsquo;m back to my original work. Or, if my cursor is sitting
in my original code, and the other buffer is the problem, I type
&lt;!-- raw HTML omitted -->C-u C-x 1&lt;!-- raw HTML omitted -->. It&amp;rsquo;s natural enough that I&amp;rsquo;d like to see it in
the default Emacs distribution.&lt;/p>
&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item><item><title>Adding Emacs / PyBlosxom Support for a Custom Format</title><link>https://camdez.com/blog/2006/01/04/adding-emacs-slash-pyblosxom-support-for-a-custom-format/</link><pubDate>Wed, 04 Jan 2006 00:00:00 -0700</pubDate><guid>https://camdez.com/blog/2006/01/04/adding-emacs-slash-pyblosxom-support-for-a-custom-format/</guid><description>In PyBlosxom, blog entries are stored in regular files rather than in a database. This means that I can write my entries in Emacs (hurrah). PyBlosxom can handle posts in any format it has a parser for.
The simplest parser removes the metadata from the beginning of the file and passes the remainder of the file directly to the output webpage. Ergo, in the most simple format, the entries should be written in html (with a basic text header).</description><content:encoded>&lt;p>In PyBlosxom, blog entries are stored in regular files rather than in a database. This means that I can write my entries in Emacs (hurrah). PyBlosxom can handle posts in any format it has a parser for.&lt;/p>
&lt;p>The simplest parser removes the metadata from the beginning of the file and passes the remainder of the file directly to the output webpage. Ergo, in the most simple format, the entries should be written in html (with a basic text header). More complicated parsers could be used for formats like xml or wiki markup. PyBlosxom uses a file&amp;rsquo;s file extension to determine what format the entry file is in.&lt;/p>
&lt;p>For some unusual reason PyBlosxom associates the simple pass-through parser with &lt;!-- raw HTML omitted -->.txt&lt;!-- raw HTML omitted --> files (wouldn&amp;rsquo;t it make more sense to use &lt;!-- raw HTML omitted -->.html&lt;!-- raw HTML omitted -->?). In any case, I decided that I wanted to add my own file extension, &lt;!-- raw HTML omitted -->.blog&lt;!-- raw HTML omitted -->, so that I could easily distinguish my blog posts from other text files and html files on my system and so that my editor could treat the files specially.&lt;/p>
&lt;p>The first step was to make PyBlosxom recognize the files as entries which it knows how to parse (anything PyBlosxom doesn&amp;rsquo;t have a parser for will simply be ignored).&lt;/p>
&lt;p>On line 79 in &lt;!-- raw HTML omitted -->pyblosxom.py&lt;!-- raw HTML omitted -->, is a block of code which I modified as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># entryparser callback is run here first to allow other plugins&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># register what file extensions can be used&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>data[&lt;span style="color:#e6db74">&amp;#39;extensions&amp;#39;&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> tools&lt;span style="color:#f92672">.&lt;/span>run_callback(&lt;span style="color:#e6db74">&amp;#34;entryparser&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {&lt;span style="color:#e6db74">&amp;#39;txt&amp;#39;&lt;/span>: blosxom_entry_parser, &lt;span style="color:#e6db74">&amp;#39;blog&amp;#39;&lt;/span>: blosxom_entry_parser},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> mappingfunc&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">lambda&lt;/span> x,y:y,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> defaultfunc&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">lambda&lt;/span> x:x)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>This is sufficient to make PyBlosxom treat &lt;!-- raw HTML omitted -->.blog&lt;!-- raw HTML omitted --> files just like &lt;!-- raw HTML omitted -->.txt&lt;!-- raw HTML omitted --> files.&lt;/p>
&lt;p>The next step was to make the files easier for me to write. First off, Emacs should open the files in &lt;!-- raw HTML omitted -->html-mode&lt;!-- raw HTML omitted -->. Adding the following bit of code to my &lt;!-- raw HTML omitted -->.emacs&lt;!-- raw HTML omitted --> file accomplishes this task:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(add-to-list &lt;span style="color:#e6db74">&amp;#39;auto-mode-alist&lt;/span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;\\.blog\\&amp;#39;&amp;#34;&lt;/span> &lt;span style="color:#f92672">.&lt;/span> html-mode))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>The next step requires a tiny bit of background information on the format of PyBlosxom entries. The basic format of a PyBlosxom entry looks like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>Title Of Entry
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#metadata-1 value-1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#metadata-2 value-2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">(&lt;/span>...&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#metadata-N value-N&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Post line 1.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Post line 2.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">(&lt;/span>...&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Post line N.&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>&lt;strong>Note:&lt;/strong> the blank line is not required, but it makes the file more (human-) readable.&lt;/p>
&lt;p>I always use the same two metadata lines: &lt;!-- raw HTML omitted -->#postdate&lt;!-- raw HTML omitted --> (from my &lt;a href="https://camdez.com/blog/2005/12/25/metadate-dot-py-for-pyblosxom">metadate.py&lt;/a>), and &lt;!-- raw HTML omitted -->tags&lt;!-- raw HTML omitted --> (from Joe Topjian&amp;rsquo;s &lt;a href="http://joe.terrarum.net/code/python/tags.txt">tags.py&lt;/a>). Because of this there are a few lines which are similar across all of my blog posts. Why not have my editor enter these automagically, including entering the current &lt;!-- raw HTML omitted -->#postdate&lt;!-- raw HTML omitted --> (in the format &lt;!-- raw HTML omitted -->YYYY-MM-DD HH:MM&lt;!-- raw HTML omitted -->)? How convenient that Emacs provides a mechanism just for this purpose: &lt;em>skeletons&lt;/em>.&lt;/p>
&lt;p>I wrote the following code and added it to my &lt;!-- raw HTML omitted -->.emacs&lt;!-- raw HTML omitted --> file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(define-skeleton blog-entry-skeleton
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Inserts a PyBlosxom-style blog entry skeleton into the current buffer.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">This only makes sense for empty buffers.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Title: &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> str &lt;span style="color:#960050;background-color:#1e0010">|&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Untitled Entry&amp;#34;&lt;/span> \n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;#postdate &amp;#34;&lt;/span> (insert-date-and-time) \n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;#tags &amp;#34;&lt;/span> (&lt;span style="color:#e6db74">&amp;#34;Enter a tag: &amp;#34;&lt;/span> str &lt;span style="color:#e6db74">&amp;#34;,&amp;#34;&lt;/span>) &lt;span style="color:#f92672">&amp;#39;&lt;/span>(delete-backward-char &lt;span style="color:#ae81ff">1&lt;/span>) \n \n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;&amp;lt;p&amp;gt;&amp;#34;&lt;/span> _ &lt;span style="color:#e6db74">&amp;#34;&amp;lt;/p&amp;gt;&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>When executed, this skeleton prompts the user for a title (if the user simply presses &lt;!-- raw HTML omitted -->RET&lt;!-- raw HTML omitted --> it defaults to &lt;!-- raw HTML omitted -->Untitled Entry&lt;!-- raw HTML omitted -->), repeatedly prompts the user for tags (keywords) (until the user simply presses &lt;!-- raw HTML omitted -->RET&lt;!-- raw HTML omitted -->), enters the current &lt;!-- raw HTML omitted -->#postdate&lt;!-- raw HTML omitted --> automatically, and the leaves the cursor inside a new &amp;lt;p&amp;gt;&lt;/p>
&lt;p>The final touch is to make the skeleton automatically execute when a new &lt;!-- raw HTML omitted -->.blog&lt;!-- raw HTML omitted --> file is created:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cl" data-lang="cl">&lt;span style="display:flex;">&lt;span>(eval-after-load &lt;span style="color:#e6db74">&amp;#34;autoinsert&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>(add-to-list &lt;span style="color:#e6db74">&amp;#39;auto-insert-alist&lt;/span> &lt;span style="color:#f92672">&amp;#39;&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;\\.blog\\&amp;#39;&amp;#34;&lt;/span> &lt;span style="color:#f92672">.&lt;/span> blog-entry-skeleton)))&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>It&amp;rsquo;s like magic!&lt;/p>
&lt;div hidden="hidden">&lt;a href="https://brid.gy/publish/mastodon">&lt;/a>&lt;a href="https://brid.gy/publish/bluesky">&lt;/a>&lt;/div></content:encoded></item></channel></rss>