<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>17070415.xyz</title>
  <link href="https://17070415.xyz/feed.xml" rel="self"/>
  <link href="https://17070415.xyz/"/>
  <updated>4025-02-08T16:48:00Z</updated>
  <id>https://17070415.xyz/</id>
  <author>
    <name>jwow</name>
  </author>
  <entry>
    <title>Your World</title>
    <link href="https://17070415.xyz/blog/your-world.html"/>
    <updated>4025-02-08T16:48:00Z</updated>
    <id>https://17070415.xyz/blog/your-world.html</id>
    <content type="html">&lt;p&gt;
The dagger stood in the corpse of Your World. I saw the dried blood scatter like dust through my ocular implants as I scanned for signs of life. While watching the glint of the blade flicker in the wind, I thought of all the agents who protected me since I was a mere germ, before I could even ask to be born.
&lt;/p&gt;

&lt;p&gt;
I was too late in this timeline.
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;
Excavating lots until I found a hololens harddrive was not hard. Most of the lots are roughly the same, stacks of rubble. There was endless rubble.
&lt;/p&gt;

&lt;p&gt;
I planted what must look like a steel rod to you into the ground. And it shot out what must look merely like grey sand. Sand with nano-processors. In 10 minutes tiny spines rose out of the ground that started merging like strands of rock. I hear rustling as burned roofing, wood, tires, and rusted metal, merge. After 20 minutes of letting the machine combine itself and seeing the tragic beauty of a red sky I am ready.
&lt;/p&gt;

&lt;p&gt;
I must have dug into what was once a living room. I could tell by trace fabric residue I was looking at a rug; a coffee table; ceramic bits that were once a mug; and the picture frames with black rectangles.
&lt;/p&gt;

&lt;p&gt;
On specific missions like these, I command my visual overlay to put black rectangles on all faces. I haven&#39;t figured out how to make black rectangles appear on the entire body of the attached head, which would make my life a lot easier.
&lt;/p&gt;

&lt;p&gt;
After uncurling the phalanges and biomatter from the drive, I rested the still life back in its pose; the way it was before I intruded, embracing what showed as another black rectangle.
&lt;/p&gt;

&lt;p&gt;
Next I had to see what happened in this ancient civilization. To do that, I had to read out data from old technology.
&lt;/p&gt;

&lt;p&gt;
Old technology was made by authors to talk in specific ways, essentially freezing its ability to speak and adapt. Old technology did not yet talk with other systems to learn how to communicate, and talk in a negotiated way, by themselves. (Or if it had, it wasn&#39;t in mass scale.) On these occasions, I carried documentation, which I found cumbersome, slow, nonvisual, and nonimmediate&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/your-world.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. 
&lt;/p&gt;

&lt;p&gt;
My implant would still attempt to inform me how to talk to the device, but translating Standard American English documentation into a dynamic model that captured every nuance of meaning, was impossible.
&lt;/p&gt;

&lt;p&gt;
The work would be boring: finding a way to activate the drive, reading documentation, extraction of drive information, cataloging data, training a model to catalog data to work alongside me, training another model to train other models to catalog alongside me, and forensic reconstruction.
&lt;/p&gt;

&lt;p&gt;
If I find something inconsistent, I could find other drives to build a better picuture, and plug data into a consensus-reaching propagation network. Finding other drives wasn&#39;t hard since a dead body usually lies around other dead bodies, and dead bodies usually have drives on them.
&lt;/p&gt;

&lt;p&gt;
The work would be boring. Except, according to agency journals, this was the earliest timeline where humans invented silicon-based computation.
&lt;/p&gt;

&lt;p&gt;
The future of Your World is a failed one. I hope by sending this analysis in old, flat, symbolic medium, that you can save Your World.
&lt;/p&gt;

&lt;p&gt;
Please ACK. ACK by storing messages at the locations I&#39;m attaching, each a backup if anything goes wrong.
&lt;/p&gt;

&lt;p&gt;
I will find the weighted average timeline stemmed from the differences you make. Talk soon.
&lt;/p&gt;

&lt;p&gt;
&lt;span class=&quot;synetica italic&quot;&gt;&amp;#x2013; jwow3424&lt;/span&gt;
&lt;/p&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/your-world.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I wonder if civilization could have fallen this way: people who only learned to talk in one specific way by dogma were then, unable to work together. A world where everyone is trapped and alone once the author of their original dogma was no longer relevant or interested.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
Still, I couldn&#39;t change the implant inside me to cover bodies with black rectangles, so maybe I&#39;m trapped too. It&#39;s hard to see you&#39;re trapped until you can think that you are trapped.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Emacs, The Leetcode Archive Webserver</title>
    <link href="https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html"/>
    <updated>4025-01-31T12:26:00Z</updated>
    <id>https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html</id>
    <content type="html">&lt;p&gt;
There&#39;s been a gap in publishing posts after my post on setting up a PHP environment in emacs. It&#39;s because I&#39;ve been working on &lt;a href=&quot;https://leetcode-archive.onrender.com/&quot;&gt;https://leetcode-archive.onrender.com/&lt;/a&gt;. I&#39;ve been making room for the past 2 months on this project consistently with some breaks between. Honestly I never thought I&#39;d get to the point where you&#39;d be reading about this. It&#39;s weird any angle you look at it.
&lt;/p&gt;


&lt;figure id=&quot;orgd9975cc&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/emacs,-the-leetcode-archive-webserver/lc-archive-screenshot.png&quot; alt=&quot;lc-archive-screenshot.png&quot; width=&quot;100%&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 1: &lt;/span&gt;a screenshot of the front page of lc-archive with some query parameters&lt;/figcaption&gt;
&lt;/figure&gt;


&lt;p&gt;
Here&#39;s what&#39;s weird about it:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;Requests are served via emacs.&lt;/b&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;The server backend reads &lt;b&gt;your request in emacs lisp.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;HTML is generated through emacs lisp. I don&#39;t even have html templates that aren&#39;t lisp.&lt;/li&gt;
&lt;li&gt;Yes, records are backed by a non-lisp database, but &lt;b&gt;interfacing with the database is done in emacs lisp.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Did I mention it&#39;s emacs? &lt;b&gt;&lt;i&gt;Inside a docker container???&lt;/i&gt;&lt;/b&gt; Oooohh&amp;#x2026;!
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;And I did that because I have no money for an AWS EC2?&lt;/li&gt;
&lt;li&gt;And that I could not find any where to host an emacs app? Because&amp;#x2026;in the web there are approx. 0 emacs apps, so why would a cloud platform think that someone would ship an emacs app and have that as part of their product offering?&lt;/li&gt;
&lt;li&gt;And that only a few cloud providers allow shipping a docker container for free, but with resource restrictions?&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;And I cannot afford a hosted db? Or that a free hosted db would have no usable data retention?&lt;/li&gt;
&lt;li&gt;And that my container starts cold, and thus I have &lt;b&gt;data loss issues every time the container starts?&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;And in this purgatory of &lt;b&gt;suffering&lt;/b&gt;, I had to make sure the data &lt;b&gt;auto backfills itself&lt;/b&gt;, and on every UTC midnight, I grab the new daily problem? Before data gets wiped clean again?&lt;/li&gt;
&lt;li&gt;And that I did this with &lt;b&gt;emacs timers and graphql requests from emacs?&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;And that you can get &lt;b&gt;your name/alias in the &lt;a href=&quot;https://leetcode-archive.onrender.com/credits&quot;&gt;project sponsors section&lt;/a&gt;&lt;/b&gt; if you&#39;d like to &lt;b&gt;fund the project?&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;It uses &lt;i&gt;transparent&lt;/i&gt;, non-opaque &lt;b&gt;cursors for paginating data&lt;/b&gt;. I spend as little time in the DB grabbing those records for you as I can&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. This was overkill for scaling, but I feel like I have to tell every star in the sky and every ancient civilization that once inhabited them: &lt;i&gt;&quot;Hey, I implemented cursor pagination for (almost) arbitrary, user-defined sort keys and sort orders! It&#39;s way faster than using LIMIT + OFFSET.&quot;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;It&#39;s &lt;b&gt;self-exposing&lt;/b&gt;--&lt;b&gt;it shows you the source code it&#39;s running:&lt;/b&gt; &lt;a href=&quot;https://leetcode-archive.onrender.com/src/&quot;&gt;https://leetcode-archive.onrender.com/src/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;It&#39;s &lt;b&gt;the only resource online&lt;/b&gt; where you can query for dates when a specific problem was a daily problem. (Ok, fine, that is a bit niche usecase but you can query for a bunch of stuff).&lt;/li&gt;
&lt;li&gt;Did I mention? Cursor based pagination?&lt;sup&gt;&lt;a id=&quot;fnr.3&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html#fn.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;i&gt;Yes I did.&lt;/i&gt; And I auto generate each SQL query &lt;b&gt;using recursion&lt;/b&gt; to get the right sort order for the right sort keys, whether it&#39;s forward OR backward pagination?&lt;/li&gt;
&lt;li&gt;And, maybe not so great, it&#39;s running HTTP 1.1. HTTP 2 was a massive upgrade over 1. Fund my work, and I&#39;ll do whatever I can to upgrade the elnode package to use HTTP 2 or higher.&lt;/li&gt;
&lt;li&gt;And it&#39;s &lt;b&gt;all public domain code&lt;/b&gt;. Go. Steal it. Make your own thing. Or make the project better.&lt;/li&gt;
&lt;li&gt;And that it&#39;s a site that requires absolutely no javascript?&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class=&quot;example&quot; id=&quot;org2a64420&quot;&gt;
Upon the sky, it is
written,
that on this day,
4025-01-26,
cursor based pagination was implemented in the application server for
https://leetcode-archive.onrender.com/.

The stars will speak the names of my sponsors for eternity.
&lt;/pre&gt;
&lt;p&gt;
&lt;i&gt;- jwow0&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
And if you like the work I do, 
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;from reading my blog,&lt;/li&gt;
&lt;li&gt;benefiting from the very niche software projects I write,&lt;/li&gt;
&lt;li&gt;or enjoy my videos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
sponsor more my work at &lt;a href=&quot;https://www.patreon.com/patreon/jwow0&quot;&gt;https://www.patreon.com/patreon/jwow0&lt;/a&gt; and have your name appear in the timeless credits in a project if your choice&lt;sup&gt;&lt;a id=&quot;fnr.4&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html#fn.4&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. See you soon!
&lt;/p&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I guess I could have used replit, but I am not excited about nix anymore.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Though, I still need to add better DB indices so queries with different sort orders can benefit. (With enough money/time I can denormalize the data a bit more too, since a question may appear on different days).
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.3&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html#fnr.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Okay, probably not the coolest or hardest thing I&#39;ve implemented, but it seemed complicated to begin with. Even slack&#39;s oft-referenced article about cursor based pagination does not talk about how to handle arbitrary sort keys and sort orders. Take a look: &lt;a href=&quot;https://slack.engineering/evolving-api-pagination-at-slack/&quot;&gt;https://slack.engineering/evolving-api-pagination-at-slack/&lt;/a&gt;.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
Bruno&#39;s article &lt;a href=&quot;https://brunoscheufler.com/blog/2022-01-01-paginating-large-ordered-datasets-with-cursor-based-pagination&quot;&gt;https://brunoscheufler.com/blog/2022-01-01-paginating-large-ordered-datasets-with-cursor-based-pagination&lt;/a&gt; made it clearer for me. I had to make the connection myself for more complicated cases when you have a mix of ASC and DESC on keys, + how you&#39;d programatically generate the SQL query, which I did by parsing out the &lt;code&gt;ORDER BY&lt;/code&gt; clause. The nested structure of handling the sort keys is fairly regular.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.4&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/emacs,-the-leetcode-archive-webserver.html#fnr.4&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I&#39;m still figuring out the details of sponsoring my work. Feel free to email me if this interests you.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Practical Cursor Pagination</title>
    <link href="https://17070415.xyz/blog/system-design/practical-cursor-pagination.html"/>
    <updated>4025-01-29T05:46:00Z</updated>
    <id>https://17070415.xyz/blog/system-design/practical-cursor-pagination.html</id>
    <content type="html">&lt;p&gt;
This is my first published article in the system design category. (I&#39;ve had other articles in draft for a year or more about designing distributed systems for criminal organizations in year 4XXX. (I don&#39;t know when I&#39;ll get to publishing that work.))
&lt;/p&gt;

&lt;p&gt;
Let&#39;s talk about cursor based pagination, which is often used for feeds or ultra large sets of data (facebook/twitter/instagram feed, google search, etc.). I&#39;m assuming you know why you want cursor pagination as opposed to other methods&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/system-design/practical-cursor-pagination.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;

&lt;p&gt;
If your database returns serializable cursors, you don&#39;t have to implement this on your own for data. For the rest of us, there&#39;s this article&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/system-design/practical-cursor-pagination.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;

&lt;p align=&quot;center&quot; style=&quot;font-size: 2em&quot;&gt;
&lt;b&gt;At a glance, how does it work?&lt;/b&gt;
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;The browser requests new data and provides details of its current page of data, which we call a cursor, &lt;code&gt;C&lt;/code&gt;. &lt;code&gt;C&lt;/code&gt; might be a hash, or perhaps be human-readable. &lt;code&gt;C&lt;/code&gt; may be null if the browser is requesting the first page.&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;The server must know 2 things from &lt;code&gt;C&lt;/code&gt;: &lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;where the search left off, and&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;which direction to go (next page or previous page?)&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;A server gets the browser request. The server decodes &lt;code&gt;C&lt;/code&gt; and pulls out the id for &lt;code&gt;Record50&lt;/code&gt; and also also pulls out the paging direction for next page. The server now knows to start searching for the next records &lt;b&gt;after&lt;/b&gt; &lt;code&gt;Record50&lt;/code&gt; from a database. We assume &lt;code&gt;Record50&lt;/code&gt; can be efficiently found, otherwise there would be no performance benefit from choosing cursor pagination.&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Importantly, when I say &lt;b&gt;after&lt;/b&gt; &lt;code&gt;Record50&lt;/code&gt;, the &lt;i&gt;after&lt;/i&gt; part means we maintain whatever sort order was specified. If &lt;code&gt;Record50&lt;/code&gt; was found from sorting by &lt;code&gt;lastName DESC&lt;/code&gt;, then breaking ties on &lt;code&gt;telephoneNumber ASC&lt;/code&gt;, the next record isn&#39;t necessarily &lt;code&gt;Record51&lt;/code&gt;, just the record that would have come up the response to the browser included one more row.&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;So the server must know the sort order to use. The browser usually sends that information, or it is known ahead of time by the server.&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;The server sends the data AND the cursor (or enough information for the browser to build the cursor), so the browser can send it back later.&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;We&#39;ll cover backwards paging after we cover forwards paging.&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Therefore, in addition to two things from &lt;code&gt;C&lt;/code&gt;, the server must know the sort order the record came from. What&#39;s left is to build that query, return results, and wait for the browser to trigger the whole process over again until the user leaves your majestic site.
&lt;/p&gt;

&lt;p align=&quot;center&quot; style=&quot;font-size: 2em&quot;&gt;
&lt;b&gt;Build that Query&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
This is the crux of it all. If you know the sort order, and have efficient indices to for the rows you sort by, only building the query remains. This reduces the problem of cursor pagination to string/query building.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s a function from &lt;a href=&quot;https://codeberg.org/MegaJ/leetcode-archive/&quot;&gt;leetcode-archive&#39;s source code&lt;/a&gt; that reads a list of comma separated sort specs like &lt;code&gt;&quot;challengeDate DESC, rowid DESC&quot;&lt;/code&gt;&lt;sup&gt;&lt;a id=&quot;fnr.3&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/system-design/practical-cursor-pagination.html#fn.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, and churns out a WHERE clause in SQL to start getting records for the user&#39;s next page of results.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgf27d8a3&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;build-where-recursive&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;sort-specs id&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;pair &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;string-split &lt;span style=&quot;color: #b0b0b3;&quot;&gt;(&lt;/span&gt;car sort-specs&lt;span style=&quot;color: #b0b0b3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;key &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;car pair&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;dir &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;cadr pair&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;null &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;cdr sort-specs&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Base case, we assume the last sort spec sorts on a unique key,&lt;/span&gt;
        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;thus no other row can have an equal value to key in the table.&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;%1$s %2$s (select %1$s from dailies_test where rowid = %3$s)&quot;&lt;/span&gt;
                key
                &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #b0b0b3;&quot;&gt;(&lt;/span&gt;equal &lt;span style=&quot;color: #677691;&quot;&gt;&quot;ASC&quot;&lt;/span&gt; dir&lt;span style=&quot;color: #b0b0b3;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;gt;&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;
                id&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;General case that allows ties. We recurse to the next sort spec.&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;%1$s %2$s (select %1$s from dailies_test where rowid = %3$s) OR&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;  (&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;    %1$s = (select %1$s from dailies_test where rowid = %3$s) AND&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;    (&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;      %4$s&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;    )&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;  )&quot;&lt;/span&gt;
              key
              &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #b0b0b3;&quot;&gt;(&lt;/span&gt;equal &lt;span style=&quot;color: #677691;&quot;&gt;&quot;ASC&quot;&lt;/span&gt; dir&lt;span style=&quot;color: #b0b0b3;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;gt;&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;
              id
              &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;build-where-recursive &lt;span style=&quot;color: #b0b0b3;&quot;&gt;(&lt;/span&gt;cdr sort-specs&lt;span style=&quot;color: #b0b0b3;&quot;&gt;)&lt;/span&gt; id&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
In the forward page case, this returns a clause like 
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-sqlite&quot;&gt;challengeDate &amp;lt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;OR&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;
    challengeDate = &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;AND&lt;/span&gt;
    &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;
      rowid &amp;lt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
which will be later part of this query (you can ignore the select and the date range):
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-sqlite&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; rowid, challengeDate, questionFrontendId, title, link, difficulty &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test
&lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; lastName &amp;gt;= &quot;2024-12-09&quot; &lt;span style=&quot;color: #81A1C1;&quot;&gt;and&lt;/span&gt; lastName &amp;lt;= &quot;2025-01-28&quot;

&lt;span style=&quot;color: #677691;&quot;&gt;-- &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;BEGIN paging clause&lt;/span&gt;
&lt;span style=&quot;color: #81A1C1;&quot;&gt;AND&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;
  challengeDate &amp;lt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;OR&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;
    challengeDate = &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;AND&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;
      rowid &amp;lt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;-- &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;END of paging clause&lt;/span&gt;

&lt;span style=&quot;color: #81A1C1;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;BY&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;DESC&lt;/span&gt;,rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;DESC&lt;/span&gt;

&lt;span style=&quot;color: #81A1C1;&quot;&gt;limit&lt;/span&gt; 10
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The clause on the left of each &lt;code&gt;OR&lt;/code&gt; is if the cursor&#39;s &lt;code&gt;challengeDate&lt;/code&gt; has no ties. On the right is when there is a tie&amp;#x2013;we use the next sort spec, in this case rowid, to break ties.
&lt;/p&gt;

&lt;p align=&quot;center&quot; style=&quot;font-size: 2em&quot;&gt;
&lt;b&gt;More sort specs&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
Next let&#39;s try &lt;code&gt;challengeDate desc,questionFrontendId ASC,rowid desc&lt;/code&gt;. Try to make a prediction of how the where clause would look.
&lt;/p&gt;

&lt;p&gt;
Did your prediction match this? 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-sqlite&quot;&gt;challengeDate &amp;lt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;OR&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;
    challengeDate = &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;AND&lt;/span&gt;
    &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;
      questionFrontendId &amp;gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; questionFrontendId &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;OR&lt;/span&gt;
  &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;
    questionFrontendId = &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; questionFrontendId &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;AND&lt;/span&gt;
    &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;
      rowid &amp;lt; &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 50&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #81A1C1;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;BY&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;desc&lt;/span&gt;,questionFrontendId &lt;span style=&quot;color: #81A1C1;&quot;&gt;ASC&lt;/span&gt;,rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;desc&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p align=&quot;center&quot; style=&quot;font-size: 2em&quot;&gt;
&lt;b&gt;Paging Backwards&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
Remember, that &lt;code&gt;C&lt;/code&gt; gives us both an id and a paging direction. If the paging direction is backwards, we have to find records BEFORE the id. Say now our id references &lt;code&gt;Record40&lt;/code&gt;, which was the first record of the page from the database. (The UI can separately sort the page on its own, so I distinguish the page, as the sequence of records given by the data store).
&lt;/p&gt;

&lt;p&gt;
But what does that mean to our sort orders?
&lt;/p&gt;

&lt;p&gt;
We reverse them.
&lt;/p&gt;

&lt;p&gt;
We invert every &lt;code&gt;DESC&lt;/code&gt; into &lt;code&gt;ASC&lt;/code&gt;, and every &lt;code&gt;ASC&lt;/code&gt; into &lt;code&gt;DESC&lt;/code&gt; for data lookup.
&lt;/p&gt;

&lt;p&gt;
Thus, for the natural sort order for the records as &lt;code&gt;challengeDate DESC,rowid DESC&lt;/code&gt;, we invert them before calling our function. Thus, we input &lt;code&gt;challengeDate ASC,rowid ASC&lt;/code&gt; into &lt;code&gt;build-where-recursive&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
And it generates:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-sqlite&quot;&gt;challengeDate &amp;gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 40&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;OR&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;
  challengeDate = &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 40&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;AND&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;
    rowid &amp;gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 40&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And the full query:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-sqlite&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; * &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;
      &lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; rowid, challengeDate, questionFrontendId, title, link, difficulty &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; challengeDate &amp;gt;= &quot;2024-12-09&quot; &lt;span style=&quot;color: #81A1C1;&quot;&gt;and&lt;/span&gt; challengeDate &amp;lt;= &quot;2025-01-28&quot;

&lt;span style=&quot;color: #81A1C1;&quot;&gt;AND&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;challengeDate &amp;gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 1369&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;OR&lt;/span&gt;
  &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;
    challengeDate = &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 1369&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;AND&lt;/span&gt;
    &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;
      rowid &amp;gt; &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;/span&gt; rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt; dailies_test &lt;span style=&quot;color: #81A1C1;&quot;&gt;where&lt;/span&gt; rowid = 1369&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;

  &lt;span style=&quot;color: #81A1C1;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;BY&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;ASC&lt;/span&gt;,rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;ASC&lt;/span&gt;

  &lt;span style=&quot;color: #81A1C1;&quot;&gt;limit&lt;/span&gt; 10

    &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;order&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;by&lt;/span&gt; challengeDate &lt;span style=&quot;color: #81A1C1;&quot;&gt;DESC&lt;/span&gt;,rowid &lt;span style=&quot;color: #81A1C1;&quot;&gt;DESC&lt;/span&gt;;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Going into 4,5,n sort specs is the same. &lt;code&gt;build-where-recursive&lt;/code&gt; handles it the same.
&lt;/p&gt;

&lt;p align=&quot;center&quot; style=&quot;font-size: 2em&quot;&gt;
&lt;b&gt;What&#39;s the outer select doing?&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
You may have noticed the nested query. It&#39;s because when we get records paged backward, the records from the inner query are in reverse order. The outer query merely reverses the order again to return records in the natural sort order used in the application.
&lt;/p&gt;

&lt;p align=&quot;center&quot; style=&quot;font-size: 2em&quot;&gt;
&lt;b&gt;What If I&#39;m sorting by nullable values?&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
The above code doesn&#39;t handle nullable fields. Whatever sort order you&#39;ve decided on regarding nulls, you have to flip them when paging for previous page. 
&lt;/p&gt;

&lt;p&gt;
Example: If the sort order in play contains a sort spec like
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org34def4d&quot;&gt;
ORDER BY name DESC, email IS NULL, id ASC
&lt;/pre&gt;
&lt;p&gt;
you do this when paging backwards:
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org5a3e602&quot;&gt;
ORDER BY name ASC, email IS NOT NULL, id DESC
&lt;/pre&gt;

&lt;p&gt;
Since the order by syntax can contain computed values as well, it&#39;s harder to write a generalized inverse for those cases. Consult this stackoverflow post: &lt;a href=&quot;https://stackoverflow.com/questions/1498648/sql-how-to-make-null-values-come-last-when-sorting-ascending&quot;&gt;sql-how-to-make-null-values-come-last-when-sorting-ascending&lt;/a&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot; style=&quot;font-size: 2em&quot;&gt;
&lt;b&gt;Last Note On the Client&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
When implementing cursor pagination, your server sends the cursor to the client. The client then has the responsibility of sending the first entry of the page&#39;s data for paging backwards. Or for paging forward, the last entry of the data. The client may not necessarily be able to decode it however, it might be a hash. We call this an &lt;i&gt;opaque cursor&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
And of course, if your database gives you serializable cursors, your app server should send that to the browser. When the browser sends it back to you, your server deserializes it, and uses it to get the next records.
&lt;/p&gt;

&lt;p align=&quot;center&quot; style=&quot;font-size: 2em&quot;&gt;
&lt;b&gt;Attack&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
Practice what you&#39;ve learned, use my free site (warning, this site cold starts) &lt;a href=&quot;https://leetcode-archive.onrender.com/&quot;&gt;https://leetcode-archive.onrender.com/&lt;/a&gt; and try out the cursor pagination. The &lt;a href=&quot;https://codeberg.org/MegaJ/leetcode-archive/&quot;&gt;source code&lt;/a&gt; is public domain.
&lt;/p&gt;

&lt;p&gt;
Lastly, if you&#39;re a law enforcement official from year 4XXX, consider hiring me or sending me a warm pair of gloves because it is cold this winter. Get algorithm lectures at &lt;a href=&quot;https://www.youtube.com/channel/jwow-0&quot;&gt;https://www.youtube.com/channel/jwow-0&lt;/a&gt; or like and subscribe for emacs videos.
&lt;/p&gt;

&lt;p&gt;
Thanks!
&lt;/p&gt;

&lt;hr class=&quot;hr&quot; /&gt;
&lt;div id=&quot;text-Footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/system-design/practical-cursor-pagination.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
See &lt;a href=&quot;https://brunoscheufler.com/blog/2022-01-01-paginating-large-ordered-datasets-with-cursor-based-pagination&quot;&gt;https://brunoscheufler.com/blog/2022-01-01-paginating-large-ordered-datasets-with-cursor-based-pagination&lt;/a&gt;, which helped me learn this topic.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/system-design/practical-cursor-pagination.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I&#39;m using emacs sqlite library. If SQLite provides serializable cursors, great, but the emacs sqlite connector certainly hasn&#39;t exposed them to me in emacs 30.0.50.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.3&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/system-design/practical-cursor-pagination.html#fnr.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Note that you &lt;i&gt;always&lt;/i&gt; want a final tie breaker (here I use &lt;code&gt;id&lt;/code&gt;, which must be unique), even if no sort order is provided by the user. Otherwise the DB engine can decide to return records in any order&amp;#x2013;which potentially breaks pagination. 
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>4025-01 In Review</title>
    <link href="https://17070415.xyz/blog/4025-01-in-review.html"/>
    <updated>4025-01-28T19:49:00Z</updated>
    <id>https://17070415.xyz/blog/4025-01-in-review.html</id>
    <content type="html">&lt;div id=&quot;outline-container-My%20meaningful%20achievements%20this%20month%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;My%20meaningful%20achievements%20this%20month%3A&quot;&gt;My meaningful achievements this month:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-My%20meaningful%20achievements%20this%20month%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;Published &lt;code&gt;8&lt;/code&gt; blog articles so far&lt;/b&gt;, &lt;code&gt;4&lt;/code&gt; (including this one) are partially done, &lt;code&gt;1&lt;/code&gt; planned but started yet, &lt;code&gt;1&lt;/code&gt; on hold.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I could have done &lt;code&gt;14&lt;/code&gt; at EOM if I maximally prioritized this, but that is unlikely.&lt;/li&gt;
&lt;li&gt;I&#39;m getting faster at making demo videos.&lt;/li&gt;
&lt;li&gt;The hardest one was &lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html&quot;&gt;Emacs Guide for PHP Development in 2025 and Beyond&lt;/a&gt; as it was pretty long, and I also recorded gifs and videos.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It is also the most comprehensive Emacs for PHP Development guide I&#39;ve seen. I read through a few long time PHP hacker&#39;s blogs who also used emacs.&lt;/li&gt;
&lt;li&gt;Technically started the article back in Dec, but at the time, I did not get &lt;code&gt;dape&lt;/code&gt; working through a docker container. Earlier this month I did, letting me complete it!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Got dape working to debug php code through a container for my nonprofit work!&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Shipped 3 audio/sfx related libraries: &lt;a href=&quot;https://17070415.xyz/blog/snd-selectric-mode-v0.0.1-released.html&quot;&gt;snd-selectric-mode&lt;/a&gt;, &lt;a href=&quot;https://17070415.xyz/blog/sndd.el-v0.0.1-released!.html&quot;&gt;sndd.el&lt;/a&gt;, &lt;a href=&quot;https://17070415.xyz/blog/hella-sounds-v0.0.1-released!.html&quot;&gt;hella-sounds.el&lt;/a&gt;&lt;/b&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;snd-selectric-mode&lt;/code&gt; is a remix of &lt;code&gt;selectric-mode&lt;/code&gt;. Writing it gave me the groundwork to drive snd from emacs.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sndd.el&lt;/code&gt; generalizes driving of &lt;code&gt;snd&lt;/code&gt;, for any emacs client. I wanted to use sndd.el for other projects.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hella-sounds.el&lt;/code&gt; abstracts the emacs advice mechanism as a declarative datastructure and wraps calls to &lt;code&gt;sndd.el&lt;/code&gt;. In the future, hella-sounds should support other ways to drive audio.&lt;/li&gt;
&lt;li&gt;I wrote so much lisp for just these three projects. I debugged a lot.&lt;/li&gt;
&lt;li&gt;I didn&#39;t have enough time to do creative writing pieces in each readme.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Shipped a website where requests are served by emacs: &lt;a href=&quot;https://leetcode-archive.onrender.com/&quot;&gt;leetcode-archive&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;You can search for what the daily leetcode problem was for a given day. 

&lt;p&gt;
Technically I started this project in December, then left it off because debugging was really hard. I had to fight to make this project come alive. Oh and, because I&#39;m on free tier, when you visit it likely will spin up cold, and take ~ 50 seconds to serve you the first request, but after it should be quick. Until it gets cold again.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;Milestones:&lt;/b&gt;
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I used &lt;code&gt;el-node&lt;/code&gt;, and started with basic serving of requests. I later added graphql libs and &lt;code&gt;esxml&lt;/code&gt; so I could do html templating in emacs. (el-node has a way to do html templating, but I didn&#39;t want to figure out if it was broken. Plus &lt;code&gt;esxml&lt;/code&gt; has more usage.)&lt;/li&gt;
&lt;li&gt;Elnode is ~ 2010 years old. Some of its documentation is wrong. I had to struggle to realize it wasn&#39;t accepting requests on &lt;code&gt;0.0.0.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I containerized emacs, and got emacs to run as an &lt;code&gt;fg-daemon&lt;/code&gt;, so docker wouldn&#39;t quit out. This was the first major struggle.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Why did I do this? Because &lt;b&gt;I couldn&#39;t find any cloud platforms that would let me ship an emacs app for free.&lt;/b&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&quot;emacs app&quot; aren&#39;t really two words you see together much eh?&lt;/li&gt;
&lt;li&gt;But I did find render.io, which lets me ship docker containers for free.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Cloudflare, despite rescinding an offer that would have changed my life, would have been my first choice still. I wonder if it would be possible, since they technically support C right?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Debugged through all the broken web requests happening for some reason when building the container. I had serious intermittent connectivity issues. Sometimes downloading an emacs package would fail.&lt;/li&gt;
&lt;li&gt;I couldn&#39;t connect an emacsclient to the unix socket through the container. I gave up, and this was a wise move. I could try a TCP connection next.&lt;/li&gt;
&lt;li&gt;I got comfortable with SQLite. It was either that or PostgreSQL. SQLite was easier because I make no money and can colocate the db more easily in the container with less moving parts.&lt;/li&gt;
&lt;li&gt;I hydrated the DB with all the records I could find. Leetcode doesn&#39;t list problems earlier than 2020-04-01, using the endpoint &lt;code&gt;dailyCodingChallengeV2(year: $year, month: $month)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I implemented features for data consistency.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;auto-backfill on startup for the app, so if startup succeeds, the data should be correct.&lt;/li&gt;
&lt;li&gt;implemented a timer to fetch the new daily problem. This was surprisingly easy. But then I also needed to make inserts idempotent. (Why did sqlite diverge in syntax from other DBs for upserts?)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Implemented cursor based pagination!&lt;/li&gt;
&lt;li&gt;Do you know what it takes to implement this at the backend application level for arbitrary sort keys and directions? I&#39;m proud of this.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I read through a blog post to help me: &lt;a href=&quot;https://brunoscheufler.com/blog/2022-01-01-paginating-large-ordered-datasets-with-cursor-based-pagination&quot;&gt;https://brunoscheufler.com/blog/2022-01-01-paginating-large-ordered-datasets-with-cursor-based-pagination&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I used recursion to build up the SQL query.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Now I need to clean up the code, make the repo readme better, and make it visually prettier.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Did more work for nonprofits, one as a software engineer, another as an IT Admin.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I&#39;m working on a critical bug right now.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Still doing daily Duolingo
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I massively scaled back my goal of 1 unit / day. But I think it&#39;s worth it to have more time doing projects and watch less ads.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Still putting time into doing a daily leetcode problem
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;but I do wish now that I was doing something else. I&#39;m really close to a 365 day streak.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Meaningful%20losses%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Meaningful%20losses%3A&quot;&gt;Meaningful losses:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Meaningful%20losses%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;When I have heart pain I have to slow down. I&#39;m completely sure why, but I have sense it might be air quality.&lt;/li&gt;
&lt;li&gt;Continued problems from unemployment.&lt;/li&gt;
&lt;li&gt;Egg shortage / avian flu. I do not buy eggs because of cost now. Hope those chickens get better.&lt;/li&gt;
&lt;li&gt;Haven&#39;t done creative writing.&lt;/li&gt;
&lt;li&gt;Haven&#39;t made new relationships. Next month will be similar.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-What%20I%27m%20grateful%20for%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;What%20I%27m%20grateful%20for%3A&quot;&gt;What I&#39;m grateful for:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-What%20I%27m%20grateful%20for%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I&#39;m still lucid. My implementation and speed of execution remain strong, despite declining health.&lt;/li&gt;
&lt;li&gt;Ability and time to focus. So much of life is how we aim our attention. (But doing it against the backdrop of pain is hard.)&lt;/li&gt;
&lt;li&gt;I try at things, even when it&#39;s hard. Even when I start a morning and feel frustrated when implementing/understanding has roadblocks, or I don&#39;t have the progress I&#39;m looking for. I&#39;m able to come back. Org mode helps me in this because I record what&#39;s going on and it&#39;s easy to re-reference what I was looking at.&lt;/li&gt;
&lt;li&gt;Costco. I&#39;ve been eating well ever since a friend brought me to costco. I bought peanut butter, sliced bread, jam, a cheese pizza, oatmeal, sweet potatoes, fresh-baked bread.&lt;/li&gt;
&lt;li&gt;Nights where I can sleep, unhaunted.&lt;/li&gt;
&lt;li&gt;Leftovers from other people.&lt;/li&gt;
&lt;li&gt;Moments where I am not in pain, I feel like freedom is possible. Maybe that is freedom, the very hope of it.&lt;/li&gt;
&lt;li&gt;Local public library reopening soon.&lt;/li&gt;
&lt;li&gt;My friend for letting me stay with him.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Looking%20ahead%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Looking%20ahead%3A&quot;&gt;Looking ahead:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Looking%20ahead%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Hopefully, I have to start learning + shipping emacs&#39; first state-charts library.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It&#39;s a pattern from video game programming.&lt;/li&gt;
&lt;li&gt;I want to colorize my cursor more reliably based on state. Managing a ton of state is hard. State charts is like using a finite state machine pattern, but more powerful and flexible.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Suffering.&lt;/li&gt;
&lt;li&gt;I want to get to &quot;done&quot; for my custom font, &lt;code&gt;synentica&lt;/code&gt;. I made it in 4020? 4021? It&#39;s unfinished but it&#39;s used in the &lt;a href=&quot;https://17070415.xyz/about.html&quot;&gt;/about&lt;/a&gt; page of this blog. I&#39;ll have to fire up inkscape and remember what my workflow was again. Not sure if that&#39;s slated for February. I don&#39;t know where I&#39;ll be in March.&lt;/li&gt;
&lt;li&gt;More work for nonprofits.&lt;/li&gt;
&lt;li&gt;I really don&#39;t like using social media to promote myself but I think I have to. Sigh.&lt;/li&gt;
&lt;li&gt;Trying to put more links for patreon/buymeacoffee/liberapay.&lt;/li&gt;
&lt;li&gt;Another round of job apps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Firefox Sends Commands To Emacs</title>
    <link href="https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html"/>
    <updated>4025-01-28T17:19:00Z</updated>
    <id>https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html</id>
    <content type="html">&lt;p&gt;
We create an endpoint in emacs that listens to commands from firefox (the same technique works in chrome or other browsers&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;). For this article, we focus on &lt;code&gt;org-protocol&lt;/code&gt; only&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; on linux.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s a demo of of me writing the current url to a file using a &lt;i&gt;custom&lt;/i&gt; org protocol (not capture, not store-link, not something built in!):
&lt;/p&gt;

&lt;figure id=&quot;firefox-sends-commands-emacs-demo&quot;&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; width=&quot;100%&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/firefox-sends-commands-to-emacs/firefox-sends-commands-emacs-demo_x0.5.mp4&quot; /&gt;
&lt;/video&gt;
&lt;figcaption&gt;A video of myself clicking a button in firefox, on the left. Emacs on the right shows that I&#39;m receiveing the url it auto adds to a buffer.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
But of course, you could make emacs do anything, like take a screenshot through a shell command, create a todo item, send out an email, and more!
&lt;/p&gt;

&lt;p&gt;
Head to &lt;a href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#Setup&quot;&gt;Setup&lt;/a&gt; if you want to get setup right away!
&lt;/p&gt;
&lt;div id=&quot;outline-container-Breakdown%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Breakdown%3A&quot;&gt;Breakdown:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Breakdown%3A&quot;&gt;
&lt;p&gt;
Just note, that 
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I click a javascript bookmarklet, which attempts to GET a resource.
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-js&quot; id=&quot;orgcd23b20&quot;&gt;javascript:(&lt;span style=&quot;color: #81A1C1;&quot;&gt;function&lt;/span&gt;(){document.location.href=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-protocol://my-protocol?url=&quot;&lt;/span&gt; + encodeURIComponent(location.href) + &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;amp;file-name=.txt&quot;&lt;/span&gt;;})();
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Firefox recognizes &lt;code&gt;org-protocol://my-protocol?url=https://17070415.xyz/support&amp;amp;file-name=delete-me.txt&lt;/code&gt;

&lt;p&gt;
and lets the system handle the request.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;My linux system looks table for handling the &lt;code&gt;org-protocol&lt;/code&gt; protocol (the bit before the first &lt;code&gt;:&lt;/code&gt;)

&lt;p&gt;
Inside either &lt;code&gt;/usr/share/applications/mimeinfo.cache&lt;/code&gt; or &lt;code&gt;~/.config/mimeapps.list&lt;/code&gt;, I have 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;x-scheme-handler/org-protocol=emacsclient.desktop;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;

&lt;li&gt;emacsclient.desktop handles the call

&lt;p&gt;
The relevant part is the &lt;code&gt;Exec&lt;/code&gt; key. The main focus is &lt;code&gt;emacsclient %U&lt;/code&gt;:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-conf-unix&quot; id=&quot;orgb0cfbb0&quot;&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;Exec&lt;/span&gt;=sh -c &lt;span style=&quot;color: #677691;&quot;&gt;&quot;if [ -n &#92;&#92;&quot;&lt;/span&gt;&#92;&#92;$*&#92;&#92;&lt;span style=&quot;color: #677691;&quot;&gt;&quot; ]; then exec /usr/bin/emacsclient --alternate-editor= --display=&#92;&#92;&quot;&lt;/span&gt;&#92;&#92;$DISPLAY&#92;&#92;&lt;span style=&quot;color: #677691;&quot;&gt;&quot; &#92;&#92;&quot;&lt;/span&gt;&#92;&#92;$@&#92;&#92;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;; else exec emacsclient %U; fi&quot;&lt;/span&gt; sh %F
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
The &lt;code&gt;%U&lt;/code&gt; allows emacsclient to be called with an arg interpreted as a url, and not a file&lt;sup&gt;&lt;a id=&quot;fnr.3&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#fn.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;emacsclient receives arguments

&lt;p&gt;
and is called like so, as if I was executing from a terminal:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot; id=&quot;org4106ebc&quot;&gt;emacsclient &lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-protocol://my-protocol?url=https://17070415.xyz/support&amp;amp;file-name=delete-me.txt&quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;the custom handler in emacs runs!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
And of course, you can use the same technique to have emacs call anything on your system! Further, you can use arbitrary javascript to get a lot data from the webpages (currently selected text, author of an article, etc.).
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Requirements&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Requirements&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;You have emacsclient installed (ships with emacs)&lt;/li&gt;
&lt;li&gt;org mode (ships with emacs)&lt;/li&gt;
&lt;li&gt;firefox, but this also works on most major browsers&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Setup&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Setup&quot;&gt;Setup&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Setup&quot;&gt;
&lt;p&gt;
Setup in three parts: 
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;Load some code so emacs can listen for a request&lt;/li&gt;
&lt;li&gt;Configure firefox to open a org-protocol externally.&lt;/li&gt;
&lt;li&gt;Ensure your system recognizes the org-protocol to open emacsclient, allowing us to trigger code from 1.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-1.%20In%20emacs%2C%20run%20this%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;1.%20In%20emacs%2C%20run%20this%3A&quot;&gt;1. In emacs, run this:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-1.%20In%20emacs%2C%20run%20this%3A&quot;&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org6510314&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;require&lt;/span&gt; &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;org-protocol&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;server-start&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;my-protocol-handler&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;url&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;message &lt;span style=&quot;color: #677691;&quot;&gt;&quot;%s&quot;&lt;/span&gt; url&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(:url https:/duckduckgo.com :title TITLE)
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;splitparts &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-protocol-parse-parameters url nil &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:url&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:file-name&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;uri &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-protocol-sanitize-uri &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-get splitparts &lt;span style=&quot;color: #81A1C1;&quot;&gt;:url&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;file-name &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plist-get splitparts &lt;span style=&quot;color: #81A1C1;&quot;&gt;:file-name&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;kill-p &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plist-get splitparts &lt;span style=&quot;color: #81A1C1;&quot;&gt;:kill-p&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;buffer &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;find-file-noselect &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;file-name-concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/tmp/delete-me.txt&quot;&lt;/span&gt; file-name&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;

    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;with-current-buffer&lt;/span&gt; buffer
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;goto-char &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;point-max&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;insert &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;insert uri&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;save-buffer&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;when&lt;/span&gt; kill-p &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;kill-current-buffer&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  nil&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;with-eval-after-load&lt;/span&gt; &#39;org-protocol
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; org-protocol-protocol-alist
        &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;my-protocol&quot;&lt;/span&gt;
           &lt;span style=&quot;color: #81A1C1;&quot;&gt;:protocol&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;my-protocol&quot;&lt;/span&gt;
           &lt;span style=&quot;color: #81A1C1;&quot;&gt;:function&lt;/span&gt; my-protocol-handler&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-2.%20Configure%20firefox&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;2.%20Configure%20firefox&quot;&gt;2. Configure firefox&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-2.%20Configure%20firefox&quot;&gt;
&lt;p&gt;
Create a bookmark in firefox:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-js&quot;&gt;javascript:(&lt;span style=&quot;color: #81A1C1;&quot;&gt;function&lt;/span&gt;(){document.location.href=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-protocol://my-protocol?url=&quot;&lt;/span&gt; + encodeURIComponent(location.href) + &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;amp;file-name=.txt&quot;&lt;/span&gt;;})();
&lt;/pre&gt;
&lt;/div&gt;

&lt;figure id=&quot;firefox-sends-commands-emacs-demo&quot;&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; width=&quot;100%&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/firefox-sends-commands-to-emacs/adding-bookmark_x0.25.mp4&quot; /&gt;
&lt;/video&gt;
&lt;figcaption&gt;Creating a new bookmark with the bookmark pane open (Ctrl + b) for the custom org protocol.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
And in firefox, goto &lt;code&gt;about:config&lt;/code&gt; and make sure you have these items set:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;network.protocol-handler.expose.org-protocol&lt;/code&gt; is set to true&lt;/li&gt;
&lt;li&gt;&lt;code&gt;network.protocol-handler.external.org-protocol&lt;/code&gt; is set to true&lt;br /&gt;(or &lt;code&gt;network.protocol-handler.external-default&lt;/code&gt; is set to true, but this applies more broadly than just org-protocol)&lt;/li&gt;
&lt;/ul&gt;


&lt;figure id=&quot;orge3864ab&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/firefox-sends-commands-to-emacs/about-config-settings.png&quot; alt=&quot;about-config-settings.png&quot; /&gt;

&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-3.%20Mime%20types&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;3.%20Mime%20types&quot;&gt;3. Mime types&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-3.%20Mime%20types&quot;&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;cp /usr/share/applications/emacsclient.desktop ~/.local/share/applications/emacsclient.desktop
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
and change the Exec in the &lt;code&gt;.local&lt;/code&gt; copy to:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-conf-unix&quot;&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;Exec&lt;/span&gt;=sh -c &lt;span style=&quot;color: #677691;&quot;&gt;&quot;if [ -n &#92;&#92;&quot;&lt;/span&gt;&#92;&#92;$*&#92;&#92;&lt;span style=&quot;color: #677691;&quot;&gt;&quot; ]; then exec /usr/bin/emacsclient --alternate-editor= --display=&#92;&#92;&quot;&lt;/span&gt;&#92;&#92;$DISPLAY&#92;&#92;&lt;span style=&quot;color: #677691;&quot;&gt;&quot; &#92;&#92;&quot;&lt;/span&gt;&#92;&#92;$@&#92;&#92;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;; else exec emacsclient %U; fi&quot;&lt;/span&gt; sh %F
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Or change the Exec to just
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;emacsclient %U
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Sometimes you need to ensure that this setting takes effect. On my system it was instant.
&lt;/p&gt;

&lt;p&gt;
Run this to be sure:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;update-desktop-database ~/.local/share/applications/
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-4.%20Try%20it%21&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;4.%20Try%20it%21&quot;&gt;4. Try it!&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-4.%20Try%20it%21&quot;&gt;
&lt;p&gt;
In firefox, click the bookmark. You should have similar results as the demo.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Troubleshooting&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Troubleshooting&quot;&gt;Troubleshooting&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Troubleshooting&quot;&gt;
&lt;p&gt;
Here are useful debugging steps to figure out what&#39;s not working
&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-The%20handler%20works%2C%20but%20the%20webpage%20gets%20rewritten&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;The%20handler%20works%2C%20but%20the%20webpage%20gets%20rewritten&quot;&gt;The handler works, but the webpage gets rewritten&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-The%20handler%20works%2C%20but%20the%20webpage%20gets%20rewritten&quot;&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/firefox-sends-commands-to-emacs/org-protocol-blank-page_x0.25.mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;
For whatever reason, on my firefox version 133.0.3 javascript of this form
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-js&quot;&gt;javascript:document.location.href=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-protocol://my-protocol?url=&quot;&lt;/span&gt; + encodeURIComponent(location.href) + &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;amp;file-name=delete-me.txt&quot;&lt;/span&gt;;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
will overwrite the current tab&#39;s state. What ended up working for me was wrapping the assignment in a function:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-js&quot;&gt;javascript:(&lt;span style=&quot;color: #81A1C1;&quot;&gt;function&lt;/span&gt;(){document.location.href=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-protocol://my-protocol?url=&quot;&lt;/span&gt; + encodeURIComponent(location.href) + &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;amp;file-name=delete-me.txt&quot;&lt;/span&gt;;})();
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Does%20emacsclient%20recognize%20the%20protocol%3F&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Does%20emacsclient%20recognize%20the%20protocol%3F&quot;&gt;Does emacsclient recognize the protocol?&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Does%20emacsclient%20recognize%20the%20protocol%3F&quot;&gt;
&lt;p&gt;
Try calling in your terminal:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;emacsclient &lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-protocol://my-protocol?url=https://17070415.xyz&amp;amp;file-name=delete-me.txt&quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If your handler doesn&#39;t fire, do step 1 again. Inspect &lt;code&gt;org-protocol-protocol-alist&lt;/code&gt;. It should look like
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;my-protocol&quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:protocol&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;my-protocol&quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:function&lt;/span&gt; my-protocol-handler&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If this variable doesn&#39;t exist, you forgot to &lt;code&gt;(require &#39;org-protocol)&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Firefox%20doesn%27t%20recognize%20the%20protocol&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Firefox%20doesn%27t%20recognize%20the%20protocol&quot;&gt;Firefox doesn&#39;t recognize the protocol&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Firefox%20doesn%27t%20recognize%20the%20protocol&quot;&gt;
&lt;p&gt;
Your console (bring it up with &lt;code&gt;F12&lt;/code&gt; in your browser) will show
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org368f1a9&quot;&gt;
Prevented navigation to “org-protocol://my-protocol?url=https%3A%2F%2Fspecifications.freedesktop.org%2Fdesktop-entry-spec%2Flatest%2Fexec-variables.html&amp;amp;file-name=delete-me.txt” due to an unknown protocol.
&lt;/pre&gt;

&lt;p&gt;
This error shows up usually because you are missing some firefox config flags. And different config flags seem to change depending on your FF version or perhaps even how you installed FF.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;visit &lt;code&gt;about:config&lt;/code&gt; in the URL bar.&lt;/li&gt;
&lt;li&gt;ensure &lt;code&gt;network.protocol-handler.expose.org-protocol&lt;/code&gt; is set to true&lt;/li&gt;
&lt;li&gt;ensure &lt;code&gt;network.protocol-handler.external.org-protocol&lt;/code&gt; is set to true&lt;br /&gt;or &lt;code&gt;network.protocol-handler.external-default&lt;/code&gt; is set to true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
You&#39;ll know if this is working when you don&#39;t see the error message anymore when you run
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-js&quot;&gt;(&lt;span style=&quot;color: #81A1C1;&quot;&gt;function&lt;/span&gt;(){document.location.href=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-protocol://my-protocol?url=&quot;&lt;/span&gt; + encodeURIComponent(location.href) + &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;amp;file-name=.txt&quot;&lt;/span&gt;;})();
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Emacs%20tries%20to%20open%20a%20file&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Emacs%20tries%20to%20open%20a%20file&quot;&gt;Emacs tries to open a file&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Emacs%20tries%20to%20open%20a%20file&quot;&gt;
&lt;p&gt;
Most likely in your emacsclient.desktop, emacsclient is called with &lt;code&gt;%F&lt;/code&gt;, not &lt;code&gt;%U&lt;/code&gt;.
&lt;/p&gt;

&lt;div class=&quot;verbatim&quot; id=&quot;orgbc1e6e5&quot;&gt;
&lt;p&gt;
%U	A list of URLs. Each URL is passed as a separate argument to the executable program. Local files may either be passed as file: URLs or as file path. 
&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;
You can verify correct behavior from steps in &lt;a href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#Does%20emacsclient%20recognize%20the%20protocol%3F&quot;&gt;Does emacsclient recognize the protocol?&lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Doesn%27t%20work%20in%20some%20FF%20browsers%3F&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Doesn%27t%20work%20in%20some%20FF%20browsers%3F&quot;&gt;Doesn&#39;t work in some FF browsers?&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Doesn%27t%20work%20in%20some%20FF%20browsers%3F&quot;&gt;
&lt;p&gt;
If you use FF based browsers, like Tor Browser, I found that 
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;~/.local/share/applications/emacsclient.desktop
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
wasn&#39;t used. Instead it uses explicitly, 
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;/usr/share/applications/emacsclient.desktop
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
In this case, modify the &lt;code&gt;emacsclient.desktop&lt;/code&gt; file at the system level to call &lt;code&gt;emacsclient %U&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Something%20else%3F&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Something%20else%3F&quot;&gt;Something else?&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Something%20else%3F&quot;&gt;
&lt;p&gt;
See footnotes for sources for this article&lt;sup&gt;&lt;a id=&quot;fnr.4&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#fn.4&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. One of those links might be useful.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Wrap%20up&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Wrap%20up&quot;&gt;Wrap up&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Wrap%20up&quot;&gt;
&lt;p&gt;
We&#39;ve seen how to register our own &quot;subprotocol&quot; under &lt;code&gt;org-protocol&lt;/code&gt;, (in our example, the subprotocol is &quot;my-protocol&quot;). What if you wanted even more power?
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Emacs can open ports and listen to them allowing you to have a full request/response cycle. You can have your browser javascript make a GET/POST request on a local server served by emacs.&lt;/li&gt;
&lt;li&gt;This is how browser extensions like Atomic Chrome, and Edit With Emacs work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Lastly if this article helped you please consider supporting my content and visit &lt;a href=&quot;https://17070415.xyz/support.html&quot;&gt;support&lt;/a&gt;. Thanks so much!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
You&#39;ll want to make sure the browser opens an org-protocol link externally. 
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
firefox also supports DBUS, but its interface is limited. I doubt you can send to dbus on firefox with javascript. If you&#39;re interested in using emacs with DBUS, check out &lt;a href=&quot;https://17070415.xyz/blog/flameshot-+-emacs-+-dbus.html&quot;&gt;my other article on using dbus in emacs&lt;/a&gt;. 
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.3&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#fnr.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
See &lt;a href=&quot;https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html&quot;&gt;https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html&lt;/a&gt;. If your emacsclient is opening a new frame, emacsclient is likely treating the argument as a file.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.4&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/firefox-sends-commands-to-emacs.html#fnr.4&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Other links
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://emacstil.com/til/2021/11/09/firefox-org-capture/&quot;&gt;https://emacstil.com/til/2021/11/09/firefox-org-capture/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kisaragi-hiu.com/org-protocol-linux&quot;&gt;https://kisaragi-hiu.com/org-protocol-linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cestlaz.github.io/post/using-emacs-70-org-protocol/&quot;&gt;https://cestlaz.github.io/post/using-emacs-70-org-protocol/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redlib.catsarch.com/r/emacs/comments/ai7hf0/does_anyone_here_still_use_orgprotocol/&quot;&gt;https://redlib.catsarch.com/r/emacs/comments/ai7hf0/does_anyone_here_still_use_orgprotocol/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://orgmode.org/worg/org-contrib/org-protocol.html&quot;&gt;https://orgmode.org/worg/org-contrib/org-protocol.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Emacs Guide for PHP Development in 2025 and Beyond</title>
    <link href="https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html"/>
    <updated>4025-01-18T10:31:00Z</updated>
    <id>https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html</id>
    <content type="html">&lt;p&gt;
&lt;b&gt;If you&#39;re new to php development (and its ecosystem), and you want to write php in emacs, this article is for you.&lt;/b&gt; I won&#39;t cover the language much but I will cover tooling, packages, etc., and getting them to work with emacs. (gifs/videos included!)
&lt;/p&gt;

&lt;p&gt;
As with most setups, I usually start by looking at the spacemacs layer for a language (&lt;a href=&quot;https://www.spacemacs.org/layers/+lang/php/README.html&quot;&gt;php&lt;/a&gt;).
&lt;/p&gt;

&lt;p&gt;
Here&#39;s a short list of things we&#39;ll cover:
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Tooling%20Outside%20Emacs&quot;&gt;Tooling Outside Emacs&lt;/a&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Package%20Management%20%28composer%20and%20packagist%29&quot;&gt;Package Management (composer and packagist)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#PHP%20Settings%20%28php.ini%29&quot;&gt;PHP Settings (php.ini)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#xdebug%203%20%28php%20debugger%29&quot;&gt;xdebug 3 (php debugger)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Linter%20%2B%20Fixer&quot;&gt;Linter + Fixer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#repl%20%28psysh%29&quot;&gt;repl (psysh)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Testing%20Framework%20%28phpunit%29&quot;&gt;Testing Framework (phpunit)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Language%20Server%20%28phpactor%29&quot;&gt;Language Server (phpactor)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Emacs%20Packages&quot;&gt;Emacs Packages&lt;/a&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#PHP%20Major%20Modes&quot;&gt;PHP Major Modes&lt;/a&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#php-mode&quot;&gt;php-mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#php-ts-mode&quot;&gt;php-ts-mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#web-mode&quot;&gt;web-mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Which%20Should%20You%20Pick%3F&quot;&gt;Which Should You Pick?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Auto-Lint%20Fix%20On%20Save%20%28phpcbf%29&quot;&gt;Auto-Lint Fix On Save (phpcbf)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Language%20Server%20%28eglot%29&quot;&gt;Language Server (eglot)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Autocompletion%20%28company%29&quot;&gt;Autocompletion (company)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Step%20Breakpointing%20%28dape%29&quot;&gt;Step Breakpointing (dape)&lt;/a&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Breakpointing%20Through%20Docker&quot;&gt;Breakpointing Through Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Test%20Runner%20Shortcuts%20%28phpunit%29&quot;&gt;Test Runner Shortcuts (phpunit)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#REPL%20%28pysh.el%29&quot;&gt;REPL (pysh.el)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Before jumping in, just know that some settings are right for one project, but not for another. If you need project specific settings, read about dir-locals in &lt;a href=&quot;https://17070415.xyz/blog/project-specific-on-save-hooks-in-emacs.html&quot;&gt;my article&lt;/a&gt; or &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/emacs.html#Directory-Variables&quot;&gt;check out the manual&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Jump to &lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#tl%3Bdr&quot;&gt;tl;dr&lt;/a&gt; if you came here to copy and paste.
&lt;/p&gt;
&lt;div id=&quot;outline-container-Tooling%20Outside%20Emacs&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Tooling%20Outside%20Emacs&quot;&gt;Tooling Outside Emacs&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Tooling%20Outside%20Emacs&quot;&gt;
&lt;p&gt;
Here are the tools emacs interfaces with, in brief. You&#39;ll want to install the relevant items so emacs can find them. I use &lt;code&gt;yay&lt;/code&gt;, but replace with your packaging tool of choice like &lt;code&gt;brew&lt;/code&gt;, &lt;code&gt;apt&lt;/code&gt;, or whatever else.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Package%20Management%20%28composer%20and%20packagist%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Package%20Management%20%28composer%20and%20packagist%29&quot;&gt;Package Management (composer and packagist)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Package%20Management%20%28composer%20and%20packagist%29&quot;&gt;
&lt;p&gt;
&lt;a href=&quot;https://getcomposer.org/&quot;&gt;composer&lt;/a&gt; is the tool for managing packages (pecl is another one, but composer is de facto according to some). It&#39;s what &lt;code&gt;npm&lt;/code&gt; is for node.js, &lt;code&gt;gem&lt;/code&gt; is for ruby, &lt;code&gt;leiningen&lt;/code&gt; is for Clojure.
&lt;/p&gt;

&lt;p&gt;
It also uses a &lt;code&gt;composer.json&lt;/code&gt; file, specific to each project. (Like a &lt;code&gt;package.json&lt;/code&gt;, or a bundle file.)
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;https://packagist.org/&quot;&gt;Packagist&lt;/a&gt; hosts the packages for easy downloading from command line.
&lt;/p&gt;

&lt;p&gt;
To install (if using yay)
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;yay -S composer
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Verify your install:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;composer --version
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-PHP%20Settings%20%28php.ini%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;PHP%20Settings%20%28php.ini%29&quot;&gt;PHP Settings (php.ini)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-PHP%20Settings%20%28php.ini%29&quot;&gt;
&lt;p&gt;
This is the file that specifies modules active in the language. On my linux distro, it&#39;s at &lt;code&gt;/etc/php/php.ini&lt;/code&gt;. I don&#39;t know another language that does it like this. I&#39;m used to specifying what modules I&#39;m importing in a file and that&#39;s it. Here, you have to make it available in what is essentially a giant config file.
&lt;/p&gt;

&lt;p&gt;
In php, people tend to just edit this &lt;code&gt;php.ini&lt;/code&gt;&amp;#x2013;and you usually need root permissions to do it.
&lt;/p&gt;

&lt;p&gt;
There&#39;s also &lt;code&gt;.user.ini&lt;/code&gt;, which only works for &lt;i&gt;some cases&lt;/i&gt;. See the PHP manual: &lt;a href=&quot;https://www.php.net/manual/en/configuration.file.per-user.php&quot;&gt;https://www.php.net/manual/en/configuration.file.per-user.php&lt;/a&gt; and pay more attention to the user contributed notes, which are clearer than the official doc.
&lt;/p&gt;

&lt;p&gt;
In the next section, you&#39;ll be modifying &lt;code&gt;php.ini&lt;/code&gt;, so the php runtime can load the xdebug module.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-xdebug%203%20%28php%20debugger%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;xdebug%203%20%28php%20debugger%29&quot;&gt;xdebug 3 (php debugger)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-xdebug%203%20%28php%20debugger%29&quot;&gt;
&lt;p&gt;
Step breakpointing requires &lt;a href=&quot;https://xdebug.org/&quot;&gt;xdebug&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Unlike many kinds of debuggers, xdebug requires that you run a server that it will connect to (xdebug will act as a client, not a server). This will be important when we talk about step through debugging in emacs.
&lt;/p&gt;

&lt;p&gt;
For now, &lt;b&gt;you need these lines&lt;/b&gt; to either be included in your &lt;code&gt;php.ini&lt;/code&gt; file directly, or indirectly (by making &lt;code&gt;php.ini&lt;/code&gt; include another file with these lines, like an &lt;code&gt;xdebug.ini&lt;/code&gt;).
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;label class=&quot;org-src-name&quot;&gt;&lt;span class=&quot;listing-number&quot;&gt;Listing 1: &lt;/span&gt;an example of some settings that need to be loaded by php.ini&lt;/label&gt;&lt;pre class=&quot;src src-conf-unix&quot; id=&quot;orgbf3f6e9&quot;&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;zend_extension&lt;/span&gt;=xdebug.so
&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;xdebug.mode&lt;/span&gt; = debug
&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;xdebug.start_with_request&lt;/span&gt; = yes &lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;trigger is also a good value, read the docs
&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;xdebug.log&lt;/span&gt;=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;/home/jwow0/tmp/xdebug.log&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;or wherever you want these logs
&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;xdebug.client_port&lt;/span&gt;=9003 &lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;you can omit this usually, the default port is 9003&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If this doesn&#39;t work, check the docs: &lt;a href=&quot;https://xdebug.org/docs/step_debug#configure&quot;&gt;https://xdebug.org/docs/step_debug#configure&lt;/a&gt;
We&#39;ll go over xdebug over docker in the &lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Step%20Breakpointing%20%28dape%29&quot;&gt;Step Breakpointing (dape)&lt;/a&gt; section.
&lt;/p&gt;

&lt;p&gt;
Install:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;yay -S xdebug
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Then setup your ini file like above.
&lt;/p&gt;

&lt;p&gt;
To verify you have xdebug installed:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;php -m -c
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
should output some lines that include
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org2863d08&quot;&gt;
[Zend Modules]
Xdebug
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-repl%20%28psysh%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;repl%20%28psysh%29&quot;&gt;repl (psysh)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-repl%20%28psysh%29&quot;&gt;
&lt;p&gt;
The built in repl, &lt;code&gt;php -a&lt;/code&gt;, is bad. Do not use it. Use &lt;a href=&quot;https://github.com/bobthecow/psysh&quot;&gt;pysh&lt;/a&gt;. It&#39;s a repl that looks and feels as powerful as a ruby &lt;code&gt;pry&lt;/code&gt; shell. You can look up documentation, skip writing those semi-colons, and get instrospection of object automatically without having to &lt;code&gt;var_dump(obj)&lt;/code&gt;. The autocomplete and font coloring are also appreciated.
&lt;/p&gt;

&lt;p&gt;
Psysh has many ways to install I won&#39;t cover:
&lt;a href=&quot;https://github.com/bobthecow/psysh/wiki/Installation&quot;&gt;https://github.com/bobthecow/psysh/wiki/Installation&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
To install with composer per project:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;composer require --dev psy/psysh:@stable
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
To install globally:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;composer global require psy/psysh:@stable
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
For global installs, you&#39;ll want to also add the psysh executable in path:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;echo&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;PATH=&#92;$PATH:~/.config/composer/vendor/bin&quot;&lt;/span&gt; &amp;gt;&amp;gt; ~/.profile
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
After sourcing your &lt;code&gt;~/.profile&lt;/code&gt; can run it simply with
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;psysh
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Try getting docs for &lt;code&gt;str_split&lt;/code&gt;:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;&amp;gt; doc str_split
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Linter%20%2B%20Fixer&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Linter%20%2B%20Fixer&quot;&gt;Linter + Fixer&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Linter%20%2B%20Fixer&quot;&gt;
&lt;p&gt;
Multiple linter and fixer programs exist. I recommend you go with &lt;code&gt;php-cs-fixer&lt;/code&gt; or &lt;code&gt;phpcbf&lt;/code&gt;, but if you&#39;re joining a mature project you have little choice.
&lt;/p&gt;

&lt;p&gt;
Later I&#39;ll show you how to &lt;a href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#Auto-Lint%20Fix%20On%20Save%20%28phpcbf%29&quot;&gt;auto-lint on save&lt;/a&gt; which requires you have phpcbf.
&lt;/p&gt;

&lt;p&gt;
You can install &lt;code&gt;phpcbf&lt;/code&gt; into your project
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;composer require --dev squizlabs/php_codesniffer 
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Or install &lt;code&gt;php-cs-fixer&lt;/code&gt; into your project:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;composer require --dev friendsofphp/php-cs-fixer
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Just note that there isn&#39;t a &lt;code&gt;php-cs-fixer&lt;/code&gt; emacs package, but since they both work on a common standard, there should be little if any difference in how they lint/fix.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Testing%20Framework%20%28phpunit%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Testing%20Framework%20%28phpunit%29&quot;&gt;Testing Framework (phpunit)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Testing%20Framework%20%28phpunit%29&quot;&gt;
&lt;p&gt;
Your testing framework, as you would expect, should be per project since various projects are likely to have various versions.
&lt;/p&gt;

&lt;p&gt;
I&#39;m not aware of any other testing frameworks in php other than phpunit (and I consider that a good thing!&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;).
&lt;/p&gt;

&lt;p&gt;
Running 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;composer require phpunit
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
yields choices
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;composer require phpunit
Could not find package phpunit.
Pick one of these or leave empty to abort:
  [0] phpunit/phpunit
  [1] phpunit/php-timer
  [2] phpunit/php-invoker
  [3] brianium/paratest
  [4] symfony/phpunit-bridge
 &amp;gt; 
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
because the full specification was &lt;code&gt;phpunit/phpunit&lt;/code&gt;. That&#39;s kinda nice!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Language%20Server%20%28phpactor%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Language%20Server%20%28phpactor%29&quot;&gt;Language Server (phpactor)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Language%20Server%20%28phpactor%29&quot;&gt;
&lt;p&gt;
You need the standalone program that acts as a server that emacs will talk to over jsonrpc.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;yay -S phpactor
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
I recommend &lt;code&gt;phpactor&lt;/code&gt; because I trust Usami Kenta (aka zonuexe), maintainer of &lt;code&gt;php-mode&lt;/code&gt; and longtime php hacker: &lt;a href=&quot;https://github.com/emacs-php/php-mode/wiki/LSP-Support#language-servers&quot;&gt;Usami&#39;s recommendation&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Emacs%20Packages&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Emacs%20Packages&quot;&gt;Emacs Packages&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Emacs%20Packages&quot;&gt;
&lt;p&gt;
Let&#39;s see how the tools we installed above can integrate seamlessly in emacs!
&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-PHP%20Major%20Modes&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;PHP%20Major%20Modes&quot;&gt;PHP Major Modes&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-PHP%20Major%20Modes&quot;&gt;
&lt;p&gt;
There are three major modes I recommend, depending on your preferences.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;tl;dr:&lt;/b&gt; I recommend using &lt;code&gt;php-mode&lt;/code&gt; or &lt;code&gt;php-ts-mode&lt;/code&gt; when you&#39;re in a pure php file. If you&#39;re dealing mainly with an html or html templating language in a file, choose &lt;code&gt;web-mode&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-php-mode&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;php-mode&quot;&gt;php-mode&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-php-mode&quot;&gt;
&lt;p&gt;
Find notes on configuring at &lt;a href=&quot;https://github.com/emacs-php/php-mode&quot;&gt;https://github.com/emacs-php/php-mode&lt;/a&gt;. php-mode also detects your linter too (&lt;code&gt;php-cs-fixer&lt;/code&gt;, &lt;code&gt;phpcbf&lt;/code&gt;, or &lt;code&gt;ecs&lt;/code&gt;).
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgb97ec93&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; php-mode
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:after&lt;/span&gt; eglot
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt; 
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;if you use flymake
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;php-mode-hook #&#39;flymake-mode&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-to-list &#39;auto-mode-alist &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.php&#92;&#92;&#39;&quot;&lt;/span&gt; . php-mode&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;

  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;custom-set-variables
   &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;php-mode-coding-style &#39;PSR12&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
   &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;php-mode-template-compatibility nil&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
   &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;php-imenu-generic-expression &#39;php-imenu-generic-expression-simple&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
This mode is fully featured to integrate with other tools, and strives to give you a full IDE experience. &lt;b&gt;In the config above, I have not enabled all those tools.&lt;/b&gt; See &lt;a href=&quot;https://github.com/emacs-php/php-mode?tab=readme-ov-file#personal-settings&quot;&gt;https://github.com/emacs-php/php-mode?tab=readme-ov-file#personal-settings&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-php-ts-mode&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;php-ts-mode&quot;&gt;php-ts-mode&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-php-ts-mode&quot;&gt;
&lt;p&gt;
Use the tree-sitter-powered &lt;code&gt;php-ts-mode&lt;/code&gt; as a drop-in replacement for php-mode. It ships with emacs, and has a small performance cost since the a parser is running all the time in your file. But it also doesn&#39;t pull in a lot of niceties that php-mode comes with, like auto-detecting your php coding standards.
&lt;/p&gt;

&lt;p&gt;
To activate, you need the grammar, so run
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org8c6607e&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-to-list &#39;treesit-language-source-alist &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;php &lt;span style=&quot;color: #677691;&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-php&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Then &lt;code&gt;M-x treesit-install-language-grammar&lt;/code&gt; and pick &lt;code&gt;php&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
If you want to wrap your settings in a use-package, you can
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgf02af30&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; php-ts-mode
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;set your settings here
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Note that this will conflict with php-mode, since you can only have 1 major mode at a time in emacs
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-to-list &#39;auto-mode-alist &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.php&#92;&#92;&#39;&quot;&lt;/span&gt; . php-ts-mode&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Cosmetically, it has different font choices than &lt;code&gt;php-mode&lt;/code&gt;. Functionally, it&#39;s much more accurate if you want to jump to a location in the code. Definitely recommended if you want to build on top, and say, bind keybindings to do things to a class, function, string, etc.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-web-mode&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;web-mode&quot;&gt;web-mode&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-web-mode&quot;&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org9e1099f&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; web-mode
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-auto-mode &#39;web-mode
                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*html*&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*twig*&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*tmpl*&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.erb&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.rhtml$&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.ejs$&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.hbs$&quot;&lt;/span&gt;
                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.ctp$&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.tpl$&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.njk$&quot;&lt;/span&gt;
                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;views&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;templates&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;/.*&#92;&#92;.php$&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;web-mode-hook #&#39;eglot-ensure&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Which%20Should%20You%20Pick%3F&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;Which%20Should%20You%20Pick%3F&quot;&gt;Which Should You Pick?&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-Which%20Should%20You%20Pick%3F&quot;&gt;
&lt;p&gt;
PHP was a language built for &lt;b&gt;p&lt;/b&gt; ersonal &lt;b&gt;h&lt;/b&gt; ome &lt;b&gt;p&lt;/b&gt; ages. Still to this day, in a &lt;code&gt;.php&lt;/code&gt; file, you specify which part is &lt;code&gt;php&lt;/code&gt;, and which isn&#39;t.
&lt;/p&gt;

&lt;p&gt;
PHP actually functions quite natively as a templating language for html. As a result of this legacy, there are many cases where a PHP file is pure php, and those that aren&#39;t.
&lt;/p&gt;

&lt;p&gt;
Use &lt;code&gt;web-mode&lt;/code&gt;, when you are dealing with mixed html and php, and &lt;code&gt;php-mode&lt;/code&gt; (or &lt;code&gt;php-ts-mode&lt;/code&gt; if you want to use treesitter) when it&#39;s just php. In &lt;code&gt;web-mode&lt;/code&gt;, it&#39;s possible to get language server support for the php portions of your code, and not have it impact your html. Keep in mind your keybindings will be web-mode keybindings in this case, so I still recommend using a php major mode in a pure php file.
&lt;/p&gt;

&lt;p&gt;
You may occasionally want to set the mode manaully when visiting a file, but you can also use &lt;code&gt;.dir-locals&lt;/code&gt; to define the mode for a subdirectory. This works well when php template files are in separate directories than pure php app code files.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Language%20Server%20%28eglot%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Language%20Server%20%28eglot%29&quot;&gt;Language Server (eglot)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Language%20Server%20%28eglot%29&quot;&gt;

&lt;figure id=&quot;org44bd417&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/emacs-guide-for-php-development-in-2025-and-beyond/eglot-quick-fix-action.gif&quot; alt=&quot;eglot-quick-fix-action.gif&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 1: &lt;/span&gt;gif of using eglot to remove the unused SplArray import&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
Eglot just works provided you have an lsp backend like &lt;code&gt;phpactor&lt;/code&gt; findable in your search &lt;code&gt;$PATH&lt;/code&gt;. It will autodetect it and manage it on its own.
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;eglot&lt;/code&gt; gives auto-complete, code-jumping to source, suggestions, and refactoring shortcuts. You&#39;ll also be prompted to enable certain extensions if inside the project you have certain packages installed:
&lt;/p&gt;


&lt;figure id=&quot;org657b936&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/emacs-guide-for-php-development-in-2025-and-beyond/eglot-detects-php-codesniffer.png&quot; alt=&quot;eglot-detects-php-codesniffer.png&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 2: &lt;/span&gt;image of eglot asking if I want to enable an extension for php code sniffer (phpcbf)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
If you only cared about code-jumping to source I&#39;d still recommend &lt;code&gt;eglot&lt;/code&gt; but you can of course just build ETAGS which is lightning fast.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s a commented config:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgb441a66&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; eglot
        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I tell straight to use the built-in eglot that ships with emacs
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;omit the following line if you don&#39;t use straight
&lt;/span&gt;  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:straight&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; built-in&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; 
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:hook&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;When eglot is active, I like to use company and yasnippet. Omit if you don&#39;t use these packages
&lt;/span&gt;        &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;eglot-managed-mode-hook . &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;()&lt;/span&gt;
                               &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;add-to-list &#39;company-backends &#39;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;company-capf &lt;span style=&quot;color: #81A1C1;&quot;&gt;:with&lt;/span&gt; company-yasnippet&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                                            &#39;t&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I use yasnippet, and I need company-yasnippet to be defined
&lt;/span&gt;        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;prior to setting the hook. If you do not use company nor yasnippet, 
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;remove the following line:
&lt;/span&gt;  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:after&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;yasnippet company&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;For web-mode; eglot can do its job in the php sections of your code
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-to-list &#39;eglot-server-programs
               &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;web-mode &lt;span style=&quot;color: #81A1C1;&quot;&gt;:language-id&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;php&quot;&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt; . &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;phpactor&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;language-server&quot;&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;

  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;For php-mode
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;php-mode-hook #&#39;eglot-ensure&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;When you waant to use php-ts-mode, you&#39;ll want eglot to activate too.
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;php-ts-mode-hook #&#39;eglot-ensure&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Auto-Lint%20Fix%20On%20Save%20%28phpcbf%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Auto-Lint%20Fix%20On%20Save%20%28phpcbf%29&quot;&gt;Auto-Lint Fix On Save (phpcbf)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Auto-Lint%20Fix%20On%20Save%20%28phpcbf%29&quot;&gt;

&lt;figure id=&quot;org87aa4b8&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/emacs-guide-for-php-development-in-2025-and-beyond/phpcbf-auto-fix.gif&quot; alt=&quot;phpcbf-auto-fix.gif&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 3: &lt;/span&gt;a gif of me saving a php file, and code is automatically formatted to PSR12&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
To integrate with your linter/fixer, you&#39;ll typically set which coding standard (a named set of code format rules, like &lt;code&gt;es2020&lt;/code&gt; for js). PSR-4, PSR-2, PSR-12, and PEAR, are some common names you&#39;ll see.
&lt;/p&gt;

&lt;p&gt;
If there&#39;s a &lt;code&gt;phpcs.xml&lt;/code&gt;, you&#39;ll want to conform to what it says for the project.
&lt;/p&gt;

&lt;p&gt;
There&#39;s also more than one program you can use for linting and fixing (&lt;a href=&quot;https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/3459&quot;&gt;php-cs-fixer&lt;/a&gt;) and to be honest, &lt;a href=&quot;https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/3459&quot;&gt;others can tell you the differences better&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Most of the time, a project&#39;s &lt;code&gt;composer.json&lt;/code&gt; will explicitly state the code format standard used (check &lt;code&gt;&quot;autoload&quot;&lt;/code&gt; or if there&#39;s a linting script in &lt;code&gt;&quot;scripts&quot;&lt;/code&gt;).
&lt;/p&gt;

&lt;p&gt;
For auto format on save, I recommend using the emacs &lt;code&gt;phpcbf&lt;/code&gt; package.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org0289d49&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; phpcbf
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;php-mode-hook #&#39;phpcbf-enable-on-save&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;php-ts-mode-hook #&#39;phpcbf-enable-on-save&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Set to nil means use the phpcs.xml in the project
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; phpcbf-standard nil&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If you don&#39;t have phpcbf in your project, you can install it globally.
&lt;/p&gt;

&lt;p&gt;
Assuming you want to use a specific standard per project (if there&#39;s no &lt;code&gt;phpcs.xml&lt;/code&gt; file in your project), you can use a dir local.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;label class=&quot;org-src-name&quot;&gt;&lt;span class=&quot;listing-number&quot;&gt;Listing 2: &lt;/span&gt;an entry into your &lt;code&gt;.dir-locals.el&lt;/code&gt;&lt;/label&gt;&lt;pre class=&quot;src src-zsh&quot;&gt;((php-mode . ((phpcbf-standard . &lt;span style=&quot;color: #677691;&quot;&gt;&quot;PSR12&quot;&lt;/span&gt;)
              (phpcbf-executable . &lt;span style=&quot;color: #677691;&quot;&gt;&quot;~/src/php-proj/vendor/bin/phpcbf&quot;&lt;/span&gt;))))
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Yes, it is confusing that we call the standard &quot;PSR-12&quot; but the string is in fact &lt;code&gt;&quot;PSR12&quot;&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Autocompletion%20%28company%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Autocompletion%20%28company%29&quot;&gt;Autocompletion (company)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Autocompletion%20%28company%29&quot;&gt;

&lt;figure id=&quot;org4747e75&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/emacs-guide-for-php-development-in-2025-and-beyond/company-php.gif&quot; alt=&quot;company-php.gif&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 4: &lt;/span&gt;autocompletion with company&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgeb68821&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; company-php&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;if you want, you can put this inside the use-package of eglot
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;define-key eglot-mode-map &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;tab&amp;gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &#39;company-indent-or-complete-common&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
I recommend readers stick with their completion framework. Corfu is another good choice and might work even better with the dape repl&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. 
&lt;/p&gt;

&lt;p&gt;
I don&#39;t recommend my company setup, but here it is for transparency:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; company
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:after&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;yasnippet eglot&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:hook&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;prog-mode . company-mode&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-mode . company-mode&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:bind&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:map&lt;/span&gt; company-active-map
              &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;tab&amp;gt;&quot;&lt;/span&gt; . company-complete-selection&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:custom&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;company-minimum-prefix-length 1&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;company-idle-delay 0.3&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;global-set-key &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-o&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&#39;company-complete&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; company-box
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:hook&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;company-mode . company-box-mode&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Step%20Breakpointing%20%28dape%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Step%20Breakpointing%20%28dape%29&quot;&gt;Step Breakpointing (dape)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Step%20Breakpointing%20%28dape%29&quot;&gt;
&lt;figure id=&quot;dape-php-demo&quot;&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; width=&quot;100%&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/emacs-guide-for-php-development-in-2025-and-beyond/dape-php-demo.mp4&quot; /&gt;
&lt;/video&gt;
&lt;figcaption&gt;A video of myself using dape to debug PHP code, change variables, and control execution.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
&lt;a href=&quot;https://github.com/svaante/dape/&quot;&gt;Dape&lt;/a&gt;. It&#39;s the newer alternative to &lt;code&gt;dap-mode&lt;/code&gt;, and it strives to depend only on emacs built-in libraries.
&lt;/p&gt;

&lt;p&gt;
Before you can &lt;code&gt;M-x dape&lt;/code&gt; successfully, you need to &lt;a href=&quot;https://github.com/svaante/dape/?tab=readme-ov-file#php---xdebug&quot;&gt;follow the instructions for dape to work with xdebug&lt;/a&gt;, including downloading a vs-code extension. Why? Because the extension sets up a server that xdebug can talk to. Dape then talks to the vs-code extension.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s a minimal use-package incantation:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org4495fd4&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; dape
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:hook&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Save breakpoints on quit
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;kill-emacs . dape-breakpoint-save&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Load breakpoints on startup
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;after-init . dape-breakpoint-load&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
I recommend you read the readme, as it has a use-package declartion decorated with comments on the various options.
&lt;/p&gt;

&lt;p&gt;
Once you have have &lt;code&gt;dape&lt;/code&gt;, &lt;code&gt;xdebug&lt;/code&gt;, and the vs code exension, you can type &lt;code&gt;M-x dape&lt;/code&gt; then type &lt;code&gt;xdebug&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
If something&#39;s not working you can debug further by
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;reading through logs you set in the &lt;code&gt;xdebug.log&lt;/code&gt;.  The logs will note if it can find the server it&#39;s looking for, and what breakpoints xdebug knows about.&lt;/li&gt;
&lt;li&gt;In your php file, place &lt;code&gt;phpinfo()&lt;/code&gt; at the top of your file. This should list all the modules available in your php runtime. xdebug info should be included if it&#39;s in the runtime.&lt;/li&gt;
&lt;li&gt;In your php file, place &lt;code&gt;xdebug_info()&lt;/code&gt; at the top of your file. It should print out how xdebug is configured.&lt;/li&gt;
&lt;li&gt;Check if xdebug can work using just the command line. The shell command I use in the video above: &lt;code&gt;php -d xdebug.profiler_enable=On hello.php&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;setting &lt;code&gt;dape-debug&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; and read dape&#39;s debug messages. Pay attention to the &lt;code&gt;*dape-repl*&lt;/code&gt; and &lt;code&gt;*dape-connection events*&lt;/code&gt; buffers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Breakpointing%20Through%20Docker&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;Breakpointing%20Through%20Docker&quot;&gt;Breakpointing Through Docker&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-Breakpointing%20Through%20Docker&quot;&gt;
&lt;p&gt;
Say your app runs in docker. And it has a docker volume that mounts code from your host machine. You do this because your container can run the code as you&#39;re changing it, giving you a better sense of behavior.
&lt;/p&gt;

&lt;p&gt;
That means your xdebug must also run in the docker container. You now have two options: should you breakpoint as if the code is local to the container? Or local to your host machine?
&lt;/p&gt;

&lt;p&gt;
I&#39;m not an expert on your system, but I think it&#39;s way more convenient to debug the code on your host machine, with all your tools set up, and your accustomed web-browser.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;You need two things in this case:&lt;/b&gt;
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;Update the &lt;code&gt;xdebug.ini&lt;/code&gt; used in your docker container (or &lt;code&gt;php.ini&lt;/code&gt; if you wrote the config in that):
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-conf-unix&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;include these two lines
&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;xdebug.discover_client_host&lt;/span&gt;=1
&lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;linux can use 172.17.0.1; mac and windows use host.docker.internal
&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;xdebug.client_host&lt;/span&gt;=172.17.0.1 
&lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;You may also need to change where the xdebug.log is set, so the process in the container
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;can write logs&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;From dape, you may need to tweak the settings in the Run adapter prompt.

&lt;p&gt;
Once you &lt;code&gt;M-x dape&lt;/code&gt;, you can set &lt;code&gt;command-cwd&lt;/code&gt;, &lt;code&gt;prefix-local&lt;/code&gt;, and &lt;code&gt;prefix-remote&lt;/code&gt; like so:
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org4c6b140&quot;&gt;
xdebug command-cwd &quot;~/&quot; prefix-local &quot;/home/jwow0/src/php-proj/&quot; prefix-remote &quot;/var/www/html/&quot;
&lt;/pre&gt;
&lt;p&gt;
Note that this assumes &lt;code&gt;/home/jwow0/src/php-proj/&lt;/code&gt; is mounted in the docker volume as &lt;code&gt;/var/www/html/&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
If you want to save that as a preset, you can explicity set a config in elisp.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org75dc085&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-to-list &#39;dape-configs
             `&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;my-xdebug-config
               modes &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;php-mode php-ts-mode&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
               command-cwd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;~/&quot;&lt;/span&gt;
               prefix-local &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/home/jwow0/src/php-proj/&quot;&lt;/span&gt;
               prefix-remote &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/var/www/html/&quot;&lt;/span&gt;
               ensure &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;config&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;dape-ensure-command config&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;dap-debug-server-path
                               &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;car &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist-get config &#39;command-args&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                          &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unless&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;file-exists-p dap-debug-server-path&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                            &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;user-error&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;File %S does not exist&quot;&lt;/span&gt; dap-debug-server-path&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
               command &lt;span style=&quot;color: #677691;&quot;&gt;&quot;node&quot;&lt;/span&gt;
               command-args &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;expand-file-name
                               &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;file-name-concat dape-adapter-dir
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;php-debug&quot;&lt;/span&gt;
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;extension&quot;&lt;/span&gt;
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;out&quot;&lt;/span&gt;
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;phpDebug.js&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
               &lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;php&quot;&lt;/span&gt;
               &lt;span style=&quot;color: #81A1C1;&quot;&gt;:port&lt;/span&gt; 9003&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Then &lt;code&gt;M-x dape&lt;/code&gt; should let you use the option &lt;code&gt;my-xdebug-config&lt;/code&gt;.
&lt;/p&gt;

&lt;figure id=&quot;org3316b7a&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/emacs-guide-for-php-development-in-2025-and-beyond/dape-with-custom-xdebug-config.gif&quot; alt=&quot;dape-with-custom-xdebug-config.gif&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 5: &lt;/span&gt;a gif of myself running &lt;code&gt;M-x dape&lt;/code&gt;, then typing &lt;code&gt;my-xdebug-config&lt;/code&gt; for the &quot;Run adapter&quot; prompt.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
If you can&#39;t get the debugger to snag, you&#39;ll want to look at where you set the &lt;code&gt;xdebug.log&lt;/code&gt; to, and &lt;code&gt;tail -f&lt;/code&gt; that file.
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Test%20Runner%20Shortcuts%20%28phpunit%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Test%20Runner%20Shortcuts%20%28phpunit%29&quot;&gt;Test Runner Shortcuts (phpunit)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Test%20Runner%20Shortcuts%20%28phpunit%29&quot;&gt;
&lt;p&gt;
Assuming you use phpunit, use &lt;a href=&quot;https://github.com/nlamirault/phpunit.el/&quot;&gt;phpunit.el&lt;/a&gt;!
&lt;/p&gt;

&lt;figure id=&quot;dape-php-demo&quot;&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; width=&quot;100%&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/emacs-guide-for-php-development-in-2025-and-beyond/phpunit-keybindings_x0.5.mp4&quot; /&gt;
&lt;/video&gt;
&lt;figcaption&gt;A video of myself using dape to debug PHP code, change variables, and control execution.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
(I remember there being an emacs tree-sitter test runner package somewhere. It does not show up in search however and I lost track of it.)
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org5eee019&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; phpunit
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;define-key php-mode-map &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-t t&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&#39;phpunit-current-test&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;define-key php-mode-map &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-t c&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&#39;phpunit-current-class&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;define-key php-mode-map &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-t p&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&#39;phpunit-current-project&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You should be testing your apps, especially if they reach a certain size. One way to lower friction for adding tests is to make running tests joyful. You shouldn&#39;t be switching to terminal back and forth in a separate window, losing precious cycles to context switching.
&lt;/p&gt;

&lt;p&gt;
For example, if your point is enclosed by a test case.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-REPL%20%28pysh.el%29&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;REPL%20%28pysh.el%29&quot;&gt;REPL (pysh.el)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-REPL%20%28pysh.el%29&quot;&gt;
&lt;p&gt;
If you prefer using psysh from emacs, there&#39;s &lt;code&gt;psysh.el&lt;/code&gt;, which integrates with &lt;code&gt;eldoc&lt;/code&gt;:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgb59da57&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; psysh&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
You can use all your emacs shortcuts in the comint buffer too.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Not%20covered&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Not%20covered&quot;&gt;Not covered&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Not%20covered&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;php-stan and &lt;code&gt;phpstan.el&lt;/code&gt; for static type analysis.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-tl%3Bdr&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;tl%3Bdr&quot;&gt;tl;dr&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-tl%3Bdr&quot;&gt;
&lt;p&gt;
Here&#39;s a yay command (apt-get probably works too, but as with distros, the package names may be different) to grab the packages:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;yay -S php phpactor xdebug composer php-sqlite php-cgi php-gd php-imagick
&lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;tbh I forgot if the last 3 were needed for apache and wordpress instead, if you were going to use them
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;yay -S apache php-apache # uncomment this line if you want to install apache, which gives the apache server&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And here are all the use-package incantations:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; php-mode
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:after&lt;/span&gt; eglot
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt; 
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;if you use flymake
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;php-mode-hook #&#39;flymake-mode&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-to-list &#39;auto-mode-alist &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.php&#92;&#92;&#39;&quot;&lt;/span&gt; . php-mode&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;

  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;custom-set-variables
   &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;php-mode-coding-style &#39;PSR12&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
   &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;php-mode-template-compatibility nil&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
   &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;php-imenu-generic-expression &#39;php-imenu-generic-expression-simple&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-to-list &#39;treesit-language-source-alist &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;php &lt;span style=&quot;color: #677691;&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-php&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;treesit-install-language-grammar &#39;php&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; php-ts-mode
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;set your settings here
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Note that this will conflict with php-mode, since you can only have 1 major mode at a time in emacs
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-to-list &#39;auto-mode-alist &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.php&#92;&#92;&#39;&quot;&lt;/span&gt; . php-ts-mode&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; web-mode
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-auto-mode &#39;web-mode
                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*html*&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*twig*&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*tmpl*&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.erb&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.rhtml$&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.ejs$&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.hbs$&quot;&lt;/span&gt;
                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.ctp$&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.tpl$&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.njk$&quot;&lt;/span&gt;
                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;views&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;templates&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;/.*&#92;&#92;.php$&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;web-mode-hook #&#39;eglot-ensure&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; eglot
        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I tell straight to use the built-in eglot that ships with emacs
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;omit the following line if you don&#39;t use straight
&lt;/span&gt;  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:straight&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; built-in&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; 
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:hook&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;When eglot is active, I like to use company and yasnippet. Omit if you don&#39;t use these packages
&lt;/span&gt;        &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;eglot-managed-mode-hook . &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;()&lt;/span&gt;
                               &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;add-to-list &#39;company-backends &#39;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;company-capf &lt;span style=&quot;color: #81A1C1;&quot;&gt;:with&lt;/span&gt; company-yasnippet&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                                            &#39;t&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I use yasnippet, and I need company-yasnippet to be defined
&lt;/span&gt;        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;prior to setting the hook. If you do not use company nor yasnippet, 
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;remove the following line:
&lt;/span&gt;  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:after&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;yasnippet company&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;For web-mode; eglot can do its job in the php sections of your code
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-to-list &#39;eglot-server-programs
               &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;web-mode &lt;span style=&quot;color: #81A1C1;&quot;&gt;:language-id&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;php&quot;&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt; . &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;phpactor&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;language-server&quot;&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;

  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;For php-mode
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;php-mode-hook #&#39;eglot-ensure&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;When you waant to use php-ts-mode, you&#39;ll want eglot to activate too.
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;add-hook &#39;php-ts-mode-hook #&#39;eglot-ensure&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; company-php&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;if you want, you can put this inside the use-package of eglot
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;define-key eglot-mode-map &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;tab&amp;gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &#39;company-indent-or-complete-common&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; dape
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:hook&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Save breakpoints on quit
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;kill-emacs . dape-breakpoint-save&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Load breakpoints on startup
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;after-init . dape-breakpoint-load&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-to-list &#39;dape-configs
             `&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;my-xdebug-config
               modes &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;php-mode php-ts-mode&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
               command-cwd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;~/&quot;&lt;/span&gt;
               prefix-local &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/home/jwow0/src/php-proj/&quot;&lt;/span&gt;
               prefix-remote &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/var/www/html/&quot;&lt;/span&gt;
               ensure &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;config&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;dape-ensure-command config&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;dap-debug-server-path
                               &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;car &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist-get config &#39;command-args&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                          &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unless&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;file-exists-p dap-debug-server-path&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                            &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;user-error&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;File %S does not exist&quot;&lt;/span&gt; dap-debug-server-path&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
               command &lt;span style=&quot;color: #677691;&quot;&gt;&quot;node&quot;&lt;/span&gt;
               command-args &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;expand-file-name
                               &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;file-name-concat dape-adapter-dir
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;php-debug&quot;&lt;/span&gt;
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;extension&quot;&lt;/span&gt;
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;out&quot;&lt;/span&gt;
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;phpDebug.js&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
               &lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;php&quot;&lt;/span&gt;
               &lt;span style=&quot;color: #81A1C1;&quot;&gt;:port&lt;/span&gt; 9003&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; phpunit
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;define-key php-mode-map &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-t t&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&#39;phpunit-current-test&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;define-key php-mode-map &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-t c&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&#39;phpunit-current-class&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;define-key php-mode-map &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-t p&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&#39;phpunit-current-project&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; psysh&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Enjoy!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Conclusion&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Conclusion&quot;&gt;
&lt;p&gt;
And that should be it. Hopefully this helps you understand what tools are commonly used in the php ecosystem, the emacs tools that integrate with them, as well as a sense of where to debug should things go awry.
&lt;/p&gt;

&lt;p&gt;
What&#39;s your favorite php integration with emacs?
&lt;/p&gt;

&lt;p&gt;
If you&#39;d like more articles like this, consider supporting me with a donation, help me find employment, and check out my work at &lt;a href=&quot;https://codeberg.org/MegaJ&quot;&gt;https://codeberg.org/MegaJ&lt;/a&gt;. Writing these articles, recording gifs and videos, and debugging take hours. Your support is tremendously appreciated.
&lt;/p&gt;

&lt;p&gt;
Stay warm!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Consider the javascript ecosystem, in excess of 1 million packages, a lot of them doing the same thing. It&#39;s hard to choose a package. PHP however, has an ecosystem where core packages are maintained, and remains lean but durable.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
In php, small projects will not bring in hundreds of dependencies like in node.js, leading to half a gig of &lt;code&gt;node_modules&lt;/code&gt; for a basic react app. You have something more modest, in tens of megabytes perhaps, and of course more for larger applications.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/emacs-guide-for-php-development-in-2025-and-beyond.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I was unable to get company working in the dape repl. 
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>dwim-convert-mkv-to-mp4</title>
    <link href="https://17070415.xyz/blog/dwim-convert-mkv-to-mp4.html"/>
    <updated>4025-01-18T08:41:00Z</updated>
    <id>https://17070415.xyz/blog/dwim-convert-mkv-to-mp4.html</id>
    <content type="html">&lt;p&gt;
I downloaded xenodium&#39;s &lt;code&gt;dwim-shell-commands&lt;/code&gt; package a while back, and I added my own little extension:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;dwim-shell-commands-mkv-to-mp4&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Convert to mkv to mp4&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;dwim-shell-command-on-marked-files
   &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Convert to mov to mp4&quot;&lt;/span&gt;
   &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;https://stackoverflow.com/questions/63664953/converting-mkv-to-mp4
&lt;/span&gt;   &lt;span style=&quot;color: #677691;&quot;&gt;&quot;ffmpeg -i &#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&amp;lt;f&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#39; -map 0 -c copy -c:a aac &#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&amp;lt;fne&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#39;.mp4&quot;&lt;/span&gt;
   &lt;span style=&quot;color: #81A1C1;&quot;&gt;:utils&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;ffmpeg&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;figure id=&quot;dape-php-demo&quot;&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; width=&quot;100%&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/dwim-convert-mkv-to-mp4/dwim-shell-commands-mkv-to-mp4_x0.5.mp4&quot; /&gt;
&lt;/video&gt;
&lt;figcaption&gt;Converting mkv to mp4 on command line, then opening the newly created mp4 video&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
I&#39;m trying to record more video lately and I use OBS. I like outputting in mkv format as it allows OBS to pause recordings. But &lt;code&gt;mkv&lt;/code&gt; isn&#39;t web-friendly, and &lt;code&gt;mp4&lt;/code&gt; enjoys universal support by browsers as a MIME type.
&lt;/p&gt;

&lt;p&gt;
Instead of slapping my video into kdenlive each time and rendering into mp4, it&#39;s quicker for me (and less context switching) to hit &lt;code&gt;M-x dwim-shell-commands-mkv-to-mp4&lt;/code&gt; from a dired buffer.
&lt;/p&gt;

&lt;p&gt;
Just as easily of course, you could attach a command line tool to dired without dwim-shell-commands.
&lt;/p&gt;

&lt;p&gt;
I&#39;ll still use kdenlive for when I need to cut and splice.
&lt;/p&gt;

&lt;p&gt;
Have a good weekend!
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>hella-sounds v0.0.1 Released!</title>
    <link href="https://17070415.xyz/blog/hella-sounds-v0.0.1-released!.html"/>
    <updated>4025-01-17T16:41:00Z</updated>
    <id>https://17070415.xyz/blog/hella-sounds-v0.0.1-released!.html</id>
    <content type="html">&lt;p&gt;
I previously shipped &lt;a href=&quot;https://codeberg.org/MegaJ/snd-selectric-mode&quot;&gt;snd-selectric-mode&lt;/a&gt; and wrote &lt;a href=&quot;https://17070415.xyz/blog/snd-selectric-mode-v0.0.1-released.html&quot;&gt;an article&lt;/a&gt; about it. A couple days ago I released &lt;a href=&quot;https://codeberg.org/MegaJ/hella-sounds.el&quot;&gt;hella-sounds.el&lt;/a&gt; for evented audio for any action you take in emacs.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;My favorite sound is the book-page-turn sound&lt;/b&gt; that I attached to &lt;b&gt;folding/unfolding in org-mode&lt;/b&gt;. It reminds me of opening magic spell books in Diablo games.
&lt;/p&gt;

&lt;p&gt;
Demo (turn sound on!):
&lt;/p&gt;

&lt;figure id=&quot;demo&quot;&gt;
    &lt;iframe width=&quot;100%&quot; height=&quot;705&quot; src=&quot;https://www.youtube.com/embed/Pn76Kr8VOhU?si=8VpaX1XRs24IgcAb&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
    &lt;figcaption&gt; Video of jwow0 showing sound effects attached to various commands &lt;/figcaption&gt;
&lt;/figure&gt;



&lt;p&gt;
Try the &lt;a href=&quot;https://codeberg.org/MegaJ/hella-sounds.el/src/branch/main/interactive-examples.org&quot;&gt;interactive examples&lt;/a&gt;!
&lt;/p&gt;

&lt;p&gt;
You might wonder why I did this. It&#39;s because want more &quot;game feel&quot; in emacs. Audio can be distracting, but designed correctly, actually enhances user experience. Audio emphasizes aspects, provides clues, and helps us process more information than only using our eyes. In the puzzle platformer Portal 2, you might not have realized the amount of audio design done&amp;#x2013;but it&#39;s there. As an example, when you reflect a laser to the wrong spot, sounds pitch differently.
&lt;/p&gt;

&lt;p&gt;
Hell, you can even download the &lt;a href=&quot;https://github.com/sourcesounds/portal2&quot;&gt;Portal 2 sounds on github&lt;/a&gt; and hook them up to &lt;code&gt;hella-sounds.el&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
I have no experience in sound design but I wanted to see more done by others. I hope you have fun with it!
&lt;/p&gt;

&lt;p&gt;
If you just want to get started, see the readme. Keep in mind the package is still alpha, and has technical limitations. Open PRs and make noise in &lt;a href=&quot;https://codeberg.org/MegaJ/hella-sounds.el/issues&quot;&gt;Issues&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
If you want to hear about my own reflection as well as notes on the technical aspects, see next article: &lt;a href=&quot;https://17070415.xyz/blog/hella-sounds.el-technical-article-1.html&quot;&gt;hella-sounds.el-technical-article-1.html&lt;/a&gt;
&lt;/p&gt;
&lt;div id=&quot;outline-container-You%20can%20help&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;You%20can%20help&quot;&gt;You can help&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-You%20can%20help&quot;&gt;
&lt;p&gt;
Besides trying to throw some dimes my way (seriously, your dimes are important)
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;you can contribute soundscapes/themes under a &lt;code&gt;themes/&lt;/code&gt; folder via PR (please use CC0 audio). I would like to have a default theme for users. I&#39;d be interested to hear what audio themes you come up with. Minecraft theme? Portal 2 as a rock ballad? Or maybe a whimsical forest bird and frog duet, replete with rain drops and tree rustling.&lt;/li&gt;
&lt;li&gt;use it, and raise issues.&lt;/li&gt;
&lt;li&gt;submit PRs to help with the code, or discuss and help me with scheme or emacs lisp.&lt;/li&gt;
&lt;li&gt;tell your friends!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Thanks to my supporters, who make this work possible! And if you&#39;d consider supporting me, send me an email.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>sndd.el v0.0.1 released!</title>
    <link href="https://17070415.xyz/blog/sndd.el-v0.0.1-released!.html"/>
    <updated>4025-01-16T08:29:00Z</updated>
    <id>https://17070415.xyz/blog/sndd.el-v0.0.1-released!.html</id>
    <content type="html">&lt;p&gt;
After finishing &lt;a href=&quot;https://codeberg.org/MegaJ/snd-selectric-mode&quot;&gt;snd-selectric-mode&lt;/a&gt;, I pulled out the layer of elisp that talks to the &lt;code&gt;snd&lt;/code&gt; process, and decoupled it from snd-selectric-mode&#39;s use case. The result is &lt;a href=&quot;https://codeberg.org/MegaJ/sndd.el&quot;&gt;sndd.el&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s a demo with some computer generated frog sounds. Of course, I chose the charismatic &lt;a href=&quot;https://en.wikipedia.org/wiki/Pacific_tree_frog&quot;&gt;Pacific Chorus Frog&lt;/a&gt;: 
&lt;/p&gt;

&lt;figure id=&quot;demo&quot;&gt;
    &lt;iframe width=&quot;100%&quot; height=&quot;705&quot; src=&quot;https://www.youtube.com/embed/-6dlgqytIfE?si=gRVaDoNXwlZuwWPg&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
    &lt;figcaption&gt; Video of jwow0 using functions from sndd.el to run scheme code &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
Not shown is all the hackyness I&#39;ve done if you want to toggle verbosity in the buffer. 
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;See &lt;a href=&quot;https://17070415.xyz/blog/hella-sounds-v0.0.1-released!.html&quot;&gt;a demo video using hella-sounds.el in my article&lt;/a&gt;. &lt;br /&gt;&lt;a href=&quot;https://codeberg.org/MegaJ/hella-sounds.el&quot;&gt;hella-sounds.el&lt;/a&gt; uses it to drive audio from emacs.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;snd-selectric-mode&lt;/code&gt; can be refactored to use it.&lt;/li&gt;
&lt;li&gt;and you can use it too! (on linux, mac and other unix-like systems, since it depends on &lt;code&gt;snd&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Thanks again to all my supporters. Your help makes it dramatically easier for me to write software and articles. And if you&#39;d consider supporting my work, send me an email (I still don&#39;t have an automated way).
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>p-list Destructuring</title>
    <link href="https://17070415.xyz/blog/p-list-destructuring.html"/>
    <updated>4025-01-13T09:31:00Z</updated>
    <id>https://17070415.xyz/blog/p-list-destructuring.html</id>
    <content type="html">&lt;p&gt;
I&#39;m dealing with plists (lists of a form &lt;code&gt;&#39;(:key1 &quot;val1&quot; :key2 &quot;val2&quot; ...)&lt;/code&gt;) in &lt;code&gt;org-mode&lt;/code&gt; or in &lt;a href=&quot;https://codeberg.org/MegaJ/hella-sounds.el&quot;&gt;hella-sounds.el&lt;/a&gt;. And I wanted a way to bind variables to key values.
&lt;/p&gt;

&lt;p&gt;
The problem is the repitition:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;date &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist-get info &lt;span style=&quot;color: #81A1C1;&quot;&gt;:date&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;title &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist-get info &lt;span style=&quot;color: #81A1C1;&quot;&gt;:title&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;title_html &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist-get info &lt;span style=&quot;color: #81A1C1;&quot;&gt;:title_html&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;author &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist-get info &lt;span style=&quot;color: #81A1C1;&quot;&gt;:author&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;...
&lt;/span&gt;       &lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;;&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;finally do a thing
&lt;/span&gt;  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Seems like we could shorten it.
&lt;/p&gt;

&lt;p&gt;
So today I wrote a macro, &lt;code&gt;plet&lt;/code&gt;:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org1abe389&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;plet&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist keys &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;rest&lt;/span&gt; body&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Given a PLIST, bind symbols in KEYS to variables and do BODY.
Ex:
(let ((prop-l &#39;(:key1 1 :key2 2 :key3 3)))
  (plet prop-l (key1 key2 key3 key4)
    (list key1 key2 key3)))
=&amp;gt; &#39;(1 2 3 nil)
&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;declare&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;indent 1&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  `&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; ,&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;cl-loop&lt;/span&gt; for key in keys
                  collect &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;list key
                                &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;turn key1 -&amp;gt; :key1
&lt;/span&gt;                                `&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plist-get
                                  ,plist
                                  ,&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;intern
                                    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;symbol-name key&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
     ,@body&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
and I&#39;ll just run the code for you:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;prop-l &#39;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:key1&lt;/span&gt; 1 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key2&lt;/span&gt; 2 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key3&lt;/span&gt; 3&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plet prop-l &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;key1 key2 key3 key4&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;list key1 key2 key3&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;1 2 3&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
and this is how I did macro expansion:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;macroexp--expand-all &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;let &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;prop-l &#39;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:key1&lt;/span&gt; 1 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key2&lt;/span&gt; 2 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key3&lt;/span&gt; 3&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;plet prop-l &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;key1 key2 key3 key4&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;list key1 key2 key3&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
and I formatted the output for readability:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;prop-l &#39;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:key1&lt;/span&gt; 1 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key2&lt;/span&gt; 2 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key3&lt;/span&gt; 3&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;key1 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plist-get prop-l &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key1&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;key2 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plist-get prop-l &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key2&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;key3 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plist-get prop-l &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key3&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;key4 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plist-get prop-l &lt;span style=&quot;color: #81A1C1;&quot;&gt;:key4&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;list key1 key2 key3&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
and it works. Unfortunately only after searching online, writing this macro, and debugging it; did I find other, inspirational answers online.
&lt;/p&gt;

&lt;p&gt;
Before jumping in, I&#39;ll note that I have a requirement that if I access keys that don&#39;t exist, I don&#39;t want an error&amp;#x2013;I expect &lt;code&gt;nil&lt;/code&gt;, as if I had just done a simple &lt;code&gt;(plist-get plist :key)&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Further, an ergonomic drawback of &lt;code&gt;plet&lt;/code&gt; is that I&#39;m declaring a &lt;code&gt;keys&lt;/code&gt; list to bind to up front. It feels like duplication.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s are the other approaches I looked at:
&lt;/p&gt;
&lt;div id=&quot;outline-container-cl-destructuring-bind&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;cl-destructuring-bind&quot;&gt;cl-destructuring-bind&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-cl-destructuring-bind&quot;&gt;
&lt;p&gt;
Stefan Monnier (&lt;a href=&quot;https://emacs.stackexchange.com/questions/22542/cl-destructuring-bind-on-partial-plist&quot;&gt;link&lt;/a&gt;) suggested to fommil
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;cl-destructuring-bind&lt;/span&gt; 
    &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;key&lt;/span&gt; a b &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;allow-other-keys&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; 
    &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;foo&quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 13 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:c&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; 
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;list a b&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And this is great for fommil&#39;s question. But if I wanted to access a symbol, say that didn&#39;t exist in the &lt;code&gt;&amp;amp;key&lt;/code&gt; specification, here just &lt;code&gt;a b&lt;/code&gt;, of course it won&#39;t work because &lt;code&gt;d&lt;/code&gt; is unbound.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;cl-destructuring-bind&lt;/span&gt; 
    &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;key&lt;/span&gt; a b &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;allow-other-keys&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; 
    &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;foo&quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 13 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:c&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; 
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;list a b d&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;let*: Symbol&lt;span style=&quot;color: #D08770;&quot;&gt;&amp;#8217;&lt;/span&gt;s value as variable is void: d
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Macro expanding like so
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;macroexp--expand-all &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;cl-destructuring-bind 
                       &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;key&lt;/span&gt; a b &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;allow-other-keys&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; 
                       &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;foo&quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 13 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:c&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; 
                     &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;list a b d&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
gives
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;--cl-rest-- &#39;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;foo&quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 13 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:c&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;a &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;car &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;cdr &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-member --cl-rest-- &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;b &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;car &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;cdr &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-member --cl-rest-- &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;list a b d&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-cl-destructuring-bind%20again&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;cl-destructuring-bind%20again&quot;&gt;cl-destructuring-bind again&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-cl-destructuring-bind%20again&quot;&gt;
&lt;p&gt;
fommil then updated his answer, and the call for &lt;code&gt;plist-bind&lt;/code&gt; is more succinct, more readable, less extensible. It still has the same drawbacks however.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;plist-bind&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;args expr &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;rest&lt;/span&gt; body&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;`&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;destructuring-bind&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#39; without the boilerplate for plists.&quot;&lt;/span&gt;
  `&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;cl-destructuring-bind&lt;/span&gt;
       &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;key&lt;/span&gt; ,@args &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;allow-other-keys&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       ,expr
     ,@body&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
In action:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;plist &#39;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;foo&quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 13 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:c&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-bind &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;a b&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; plist
              &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;list a b&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;foo&quot;&lt;/span&gt; 13 nil&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
But what I&#39;m really look for is some way to destructure, without having to explicitly declare the items.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-with-plist-vals&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;with-plist-vals&quot;&gt;with-plist-vals&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-with-plist-vals&quot;&gt;
&lt;p&gt;
From &lt;a href=&quot;https://kitchingroup.cheme.cmu.edu/blog/2017/04/16/A-callable-plist-data-structure-for-Emacs/#orgb831a3d&quot;&gt;John Kitchin&#39;s post&lt;/a&gt;, (I replaced &lt;code&gt;loop&lt;/code&gt; with &lt;code&gt;cl-loop&lt;/code&gt; since loop was removed):
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;with-plist-vals&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;rest&lt;/span&gt; body&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Bind the values of a plist to variables with the name of the keys.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;declare&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;indent 1&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  `&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; ,&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;cl-loop&lt;/span&gt; for key in &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;-slice plist 0 nil 2&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                  for val in &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;-slice plist 1 nil 2&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                  collect &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;list &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;intern
                                 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;substring &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;symbol-name key&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; 1&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                                val&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
     ,@body&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;with-plist-vals &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; 4 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 6&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;* 2 a&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;=&amp;gt; 8&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
This works in his example because he uses a literal list passed in as &lt;code&gt;plist&lt;/code&gt;, but doesn&#39;t work we pass in a symbol referring to a list. Here&#39;s a clarifying example:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;plist &#39;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; 4 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 6&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;with-plist-vals 
      &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;* 2 a&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;=&amp;gt; nil&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
when we macro expand like this:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;macroexp--expand-all &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;let &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist &#39;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; 4 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 6&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                         &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;with-plist-vals 
                             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;* 2 a&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
we get
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;plist &#39;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; 4 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 6&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;## 2&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; nil&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
The binding in the inner &lt;code&gt;let&lt;/code&gt; is missing because &lt;code&gt;(-slice plist 0 nil 2)&lt;/code&gt; is working on the symbol &lt;code&gt;&#39;plist&lt;/code&gt; (an error), not the value &lt;code&gt;(:a 4 :b 6)&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
That&#39;s ok. That can be fixed. What I like about it: it interns all the keys, so you don&#39;t have to explicitly declare which keys you want in another form like the previous solutions we&#39;ve seen.
&lt;/p&gt;

&lt;p&gt;
It still has the draw back that you can&#39;t access a key that isn&#39;t present.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;with-plist-vals &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:a&lt;/span&gt; 4 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:b&lt;/span&gt; 6&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;* 2 a d&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;=&amp;gt; leads to Lisp error: (void-variable d)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
So this leads me to think that a better design involves specially marking your variables, specifically for destructuring. We see that next.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-let-plist&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;let-plist&quot;&gt;let-plist&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-let-plist&quot;&gt;
&lt;p&gt;
Someone asked about an impletmentation for &lt;code&gt;let-plist&lt;/code&gt;, as an anologous utility to Mr.Endlessparentheses&#39;s &lt;code&gt;let-alist&lt;/code&gt;. (&lt;a href=&quot;https://emacs.stackexchange.com/questions/45581/equivalent-of-let-alist-for-plists&quot;&gt;link&lt;/a&gt;).
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;let-alist&lt;/code&gt; allows nested searching as well, which is more power than I was looking for. (There are other good responses in the post, and I&#39;m particularly interested in Stefan&#39;s answer, but I don&#39;t understand pcase yet.)
&lt;/p&gt;

&lt;p&gt;
From xuchunyang (who says the code they wrote isn&#39;t difficult to make, I don&#39;t know, it would have taken me a fair amount of time):
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;require&lt;/span&gt; &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let-alist&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;let-plist--list-to-sexp&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;list var&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Turn symbols LIST into recursive calls to `&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;plist-get&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#39; on VAR.&quot;&lt;/span&gt;
  `&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-get ,&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;cdr list&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                   &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;let-plist--list-to-sexp &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;cdr list&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; var&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                   var&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
              &#39;,&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;intern &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;symbol-name &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;car list&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;let-plist--access-sexp&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;symbol variable&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Return a sexp used to access SYMBOL inside VARIABLE.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;clean &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;let-alist--remove-dot symbol&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;name &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;symbol-name clean&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;string-match &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;`&#92;&#92;.&quot;&lt;/span&gt; name&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        clean
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;let-plist--list-to-sexp
         &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;mapcar #&#39;intern &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;nreverse &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;split-string name &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;.&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
         variable&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;let-plist&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;rest&lt;/span&gt; body&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;declare&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;indent 1&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;var &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;make-symbol &lt;span style=&quot;color: #677691;&quot;&gt;&quot;plist&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    `&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;,var ,plist&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
       &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; ,&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;mapcar &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;lambda &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;x&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; `&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;car x&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt; ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;let-plist--access-sexp &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;car x&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; var&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                     &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;((&#92;.question.id . question.id) (&#92;.question.author . question.author) (&#92;.dinosaur . dinosaur))
&lt;/span&gt;                     &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;delete-dups &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;let-alist--deep-dot-search body&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
         ,@body&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;let-plist plist
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;list .question.id .question.author .dinosaur&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;macroexp--expand-all &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;let &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist &#39;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:question&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:title&lt;/span&gt;
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Equivalent of let-alist for plists?&quot;&lt;/span&gt;
                                                 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:id&lt;/span&gt;
                                                 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;45581&quot;&lt;/span&gt;
                                                 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:tags&lt;/span&gt;
                                                 &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;property-lists&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                         &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;let-plist plist
                           &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;list .question.id .question.author .dinosaur&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Leads to:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;plist &#39;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:question&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:title&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Equivalent of let-alist for plists?&quot;&lt;/span&gt;
                                 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:id&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;45581&quot;&lt;/span&gt;
                                 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:tags&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;property-lists&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plist plist&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&#92;.question.id &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-get
                          &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;plist-get plist &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:question&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                          &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
          &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&#92;.question.author &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-get
                              &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;plist-get plist &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:question&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                              &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:author&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
          &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&#92;.dinosaur &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-get plist &#39;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:dinosaur&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;list
       &#92;.question.id
       &#92;.question.author
       &#92;.dinosaur&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And evaluates to
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;45581&quot;&lt;/span&gt; nil nil&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;code&gt;let-plist&lt;/code&gt; essentially does depth first search IN THE BODY for all symbols that start with &lt;code&gt;.&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Then &lt;code&gt;let-plist--access-sexp&lt;/code&gt; builds &lt;code&gt;plist-get&lt;/code&gt; access chain for the &lt;code&gt;let&lt;/code&gt; like
&lt;code&gt;(&#92;.dinosaur (plist-get plist &#39;:dinosaur))&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Be wary of nesting calls to &lt;code&gt;let-plist&lt;/code&gt;&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/p-list-destructuring.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;

&lt;p&gt;
And finally, what is that sharp quote doing there? &lt;code&gt;&quot;&#92;&#92;`&quot;&lt;/code&gt; will be read as &lt;code&gt;&#92;`&lt;/code&gt;, which is used to match the beginning of a string or buffer. I don&#39;t know why they didn&#39;t use &lt;code&gt;^&lt;/code&gt; which is more understandable in my opinion: &lt;code&gt;&quot;^&#92;&#92;.&quot;&lt;/code&gt;, but this matches lines.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Conclusion&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Conclusion&quot;&gt;
&lt;p&gt;
Many possibilities exist. I will probably stick with &lt;code&gt;cl-destructuring-bind&lt;/code&gt; since it&#39;s built in, but it was a pretty fun exploration of macros which I don&#39;t do very often.
&lt;/p&gt;

&lt;p&gt;
If you liked this synthesis, please econsider supporting this blog. It&#39;s because of supporters that I can dedicate my time and energy into exploring topics like this one and share them with others.
&lt;/p&gt;

&lt;p&gt;
From 13 Jan 4XXX, have a nice day in 13 Jan 2XXX!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/p-list-destructuring.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
One issue I&#39;ve had with &lt;code&gt;let-alist&lt;/code&gt; is when an inner &lt;code&gt;let-alist&lt;/code&gt; tries to access properties from the outer &lt;code&gt;let-alist&lt;/code&gt; form. The outer &lt;code&gt;let-alist&lt;/code&gt; won&#39;t read the inner &lt;code&gt;let-alist&lt;/code&gt; form to expand accessors. Meaning if the inner form accesses a &lt;code&gt;.property.from.outside&lt;/code&gt;, it will be &lt;code&gt;nil&lt;/code&gt;.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
I don&#39;t know how to get around that, or if I should.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>snd-selectric-mode v0.0.1 released</title>
    <link href="https://17070415.xyz/blog/snd-selectric-mode-v0.0.1-released.html"/>
    <updated>4025-01-09T14:09:00Z</updated>
    <id>https://17070415.xyz/blog/snd-selectric-mode-v0.0.1-released.html</id>
    <content type="html">&lt;p&gt;
I fixed the performance issues from selectric-mode that I wrote about in my article about &lt;a href=&quot;https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html&quot;&gt;ipc for sounds in emacs&lt;/a&gt;. Code is here:  &lt;a href=&quot;https://codeberg.org/MegaJ/snd-selectric-mode&quot;&gt;https://codeberg.org/MegaJ/snd-selectric-mode&lt;/a&gt;.
&lt;/p&gt;


&lt;p&gt;
Demo (turn sound on!):
&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;705&quot; src=&quot;https://www.youtube.com/embed/PlEK1P9t8aw&quot; title=&quot;snd-selectric-mode demo&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;
&lt;/iframe&gt;


&lt;p&gt;
To briefly recap, last time I experimented with
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;selectric-mode without changes&lt;/li&gt;
&lt;li&gt;thread spawning for each sound played&lt;/li&gt;
&lt;li&gt;mpv as a daemon, emacs sending commands through a socket&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
My last option was the most performant but suffered from limitations like mixing not being very practical. Now, I found an option to mix that I&#39;ve tested only on linux. It relies on a binary called &lt;code&gt;snd&lt;/code&gt;, which may be packaged by your package manager.
&lt;/p&gt;

&lt;p&gt;
When you have &lt;code&gt;snd&lt;/code&gt;, here&#39;s a use-package incantation to get my emacs package if you use straight.el:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org0cc0556&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; snd-selectric-mode
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:straight&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; git &lt;span style=&quot;color: #81A1C1;&quot;&gt;:host&lt;/span&gt; codeberg
                   &lt;span style=&quot;color: #81A1C1;&quot;&gt;:repo&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;megaj/snd-selectric-mode&quot;&lt;/span&gt;
                   &lt;span style=&quot;color: #81A1C1;&quot;&gt;:files&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;*.el&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*.wav&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I recommend leaving the verbosity setting on in case you run into bugs
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;the first time you use it.
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;You can check the *snd-selectric-scheme* buffer for output.
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;:custom (snd-selectric-verbose-process-p nil)
&lt;/span&gt;  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-How%20it%20works&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;How%20it%20works&quot;&gt;How it works&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-How%20it%20works&quot;&gt;
&lt;p&gt;
Ultimately, it&#39;s just emacs sending scheme commands through a comint buffer. There&#39;s nothing fancy here&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/snd-selectric-mode-v0.0.1-released.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. All the heavy lifting is done by &lt;code&gt;snd&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-snd&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;snd&quot;&gt;snd&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-snd&quot;&gt;
&lt;p&gt;
&lt;code&gt;snd&lt;/code&gt; is an audio editor, but it handles realtime audio playback and mixes it all down. It accepts commands through a repl directly, or even through a socket. It&#39;s what makes this all possible. And it runs scheme!
&lt;/p&gt;

&lt;p&gt;
Not only does it run scheme, but it&#39;s the emacs of sound editing&amp;#x2013;it seems most things about the currently running program can be changed while it&#39;s running.
&lt;/p&gt;

&lt;p&gt;
It was not made for my use case, but it&#39;s flexible. I&#39;ve already thought about my next project with it. I want to use it like how people use fmod for games.
&lt;/p&gt;

&lt;p&gt;
It does come with some drawbacks though. It lacks a really good debugger as admitted by the author of snd. It also doesn&#39;t have a community outside of a mailing list.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Performance&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Performance&quot;&gt;Performance&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Performance&quot;&gt;
&lt;p&gt;
This is comparable to using mpv. Maybe slightly more CPU usage, but I get mixing and a bunch more functionality.
&lt;/p&gt;

&lt;figure id=&quot;orgf3bb3bd&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/snd-selectric-mode-v0.0.1-released/2025-01-09_20-07-46_screenshot.png&quot; alt=&quot;2025-01-09_20-07-46_screenshot.png&quot; width=&quot;100%&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 1: &lt;/span&gt;20% cpu using snd&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Enjoy%21&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Enjoy%21&quot;&gt;Enjoy!&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Enjoy%21&quot;&gt;
&lt;p&gt;
This package hasn&#39;t had users other than myself yet. Please raise issues you find on &lt;a href=&quot;https://codeberg.org/MegaJ/snd-selectric-mode/issues&quot;&gt;https://codeberg.org/MegaJ/snd-selectric-mode/issues&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
And if you have any tips on writing s7 scheme or know a lot about snd, send me word at jwow [at] 17070415 [dot] xyz.
&lt;/p&gt;

&lt;p&gt;
Lastly if you enjoy my articles or any software I wrote, please consider supporting my work.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/snd-selectric-mode-v0.0.1-released.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
the only contrived thing was to suppress the output since the comint buffer acts like a repl. There is no way to suppress the output, but I&#39;ve made it possible for users to &lt;code&gt;(setq snd-selectric-command &quot;snd -b &amp;gt; /dev/null&quot;)&lt;/code&gt; which eliminates all terminal output.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
I believe I can write some scheme to change how the repl prints, but I&#39;m not sure. I actually don&#39;t know how scheme works, only that it&#39;s a compartively much smaller language spec than common lisp.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Flameshot + Emacs + Dbus</title>
    <link href="https://17070415.xyz/blog/flameshot-+-emacs-+-dbus.html"/>
    <updated>4025-01-07T12:13:00Z</updated>
    <id>https://17070415.xyz/blog/flameshot-+-emacs-+-dbus.html</id>
    <content type="html">&lt;p&gt;
I&#39;ve been looking for &lt;b&gt;faster ways to include screenshots&lt;/b&gt; and other media in org mode.
&lt;/p&gt;

&lt;p&gt;
With 0 keystrokes in emacs:
&lt;/p&gt;

&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; width=&quot;100%&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/flameshot-+-emacs-+-dbus/flameshot-into-org.mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;
The video sequence:
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;I press the Print Screen key, bound on my desktop to call &lt;code&gt;flameshot gui&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I confirm the area selection looks good to me with &lt;code&gt;Ctrl + C&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Flameshot sends a method call over dbus after it records the bytes of the image into the system clipboard.&lt;/li&gt;
&lt;li&gt;Emacs has been monitoring for that specific method call, and &lt;code&gt;(yank-media)&lt;/code&gt; is called automatically in the &lt;code&gt;(current-buffer)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Due to a quirk in the clipboard not being ready when this notification fires, &lt;code&gt;(yank-media)&lt;/code&gt; thinks we&#39;re pasting plain text, and fails.&lt;/li&gt;
&lt;li&gt;The quirk is a nonissue if existing image data exists in the clipboard, so the second time I do steps 1 - 4, it works, with the newest image.&lt;/li&gt;
&lt;li&gt;Finally I call &lt;code&gt;org-toggle-inline-images&lt;/code&gt; (ok, 1 keystroke, but it was for the demo).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
So there&#39;s a quirk, but I hope the folks at flameshot will continue to iterate on it. Or maybe it&#39;s an issue with Wayland + Gnome interaction? 
&lt;/p&gt;

&lt;p&gt;
Jump to &lt;a href=&quot;https://17070415.xyz/blog/flameshot-+-emacs-+-dbus.html#Code&quot;&gt;Code&lt;/a&gt; to steal this.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;Update 2025-01-09&lt;/b&gt; I find that flameshot is really finicky if it will work outside of being called within Gnome terminal on wayland. Sometimes it works if I restart my computer.
&lt;/p&gt;
&lt;div id=&quot;outline-container-Desired%20Workflow&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Desired%20Workflow&quot;&gt;Desired Workflow&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Desired%20Workflow&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Take a screenshot&lt;/li&gt;
&lt;li&gt;Emacs should immediately either
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;add a link to the media in kill-ring so I can decide what to do with it later.&lt;/li&gt;
&lt;li&gt;auto insert into the org doc in &lt;code&gt;(current-buffer)&lt;/code&gt;, allowing me to take a bunch of screenshots and then I can just rearrange them as I like, like a scrapbook.&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
In the video, you see me take option 2. But hopefully after reading this, you&#39;ll realize option 1 is a piece of cake too.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Tradeoffs%20Made&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Tradeoffs%20Made&quot;&gt;Tradeoffs Made&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Tradeoffs%20Made&quot;&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Other%20Approaches&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Other%20Approaches&quot;&gt;Other Approaches&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Other%20Approaches&quot;&gt;
&lt;p&gt;
Other non-dbus options exist, and they look complicated.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bburns/clipmon&quot;&gt;https://github.com/bburns/clipmon&lt;/a&gt;  &lt;a href=&quot;https://github.com/bburns/clipmon/blob/master/clipmon.el#L248&quot;&gt;polls the system clipboard&lt;/a&gt;.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Works for text and images in system clipboard.&lt;/li&gt;
&lt;li&gt;Only works on X.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cdown/clipnotify&quot;&gt;https://github.com/cdown/clipnotify&lt;/a&gt; is properly evented and I experimented with calling dbus commands to send signals to emacs
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It&#39;s not as easy to package a solution using it for various reasons&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/flameshot-+-emacs-+-dbus.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;Also only works on X.&lt;/li&gt;
&lt;li&gt;Works for text and images in system clipboard.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#File-Notifications&quot;&gt;elisp#File Notifications&lt;/a&gt; api, by listening to changes in the file system. For this, configure the screenshot tool to always save to a file.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Probably the most robust, cross platform solution. I did not choose this, partially because of fashion.&lt;/li&gt;
&lt;li&gt;I would have to save a file first, before likely moving it.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-DBUS%20%2B%20Flameshot%20approach&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;DBUS%20%2B%20Flameshot%20approach&quot;&gt;DBUS + Flameshot approach&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-DBUS%20%2B%20Flameshot%20approach&quot;&gt;
&lt;p&gt;
You might be wondering why I didn&#39;t use a DBUS event for when the system clipboard changes. It&#39;s because I couldn&#39;t find one.
&lt;/p&gt;

&lt;p&gt;
Pros:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Should work on Wayland and X.&lt;/li&gt;
&lt;li&gt;Is event-based, no polling required&lt;/li&gt;
&lt;li&gt;Uses native emacs DBUS API&lt;/li&gt;
&lt;li&gt;No integration layer to set up in Flameshot&amp;#x2013;it has native dbus support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Cons:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Has 2 hard dependencies: dbus and flameshot.&lt;/li&gt;
&lt;li&gt;Doesn&#39;t work with text, I&#39;ve only supported images since I&#39;m focusing on flameshot.&lt;/li&gt;
&lt;li&gt;DBUS support in Flameshot could be improved.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
So I&#39;ve settled on &lt;a href=&quot;https://flameshot.org/&quot;&gt;flameshot&lt;/a&gt;
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;flameshot --version
&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-sh&quot;&gt;Flameshot v12.1.0 (-)
Compiled with Qt 5.15.14
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If you&#39;re on wayland, there&#39;s scattered help online, but see if &lt;a href=&quot;https://flameshot.org/docs/guide/wayland&quot;&gt;https://flameshot.org/docs/guide/wayland&lt;/a&gt; helps.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Flameshot%20settings&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Flameshot%20settings&quot;&gt;Flameshot settings&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Flameshot%20settings&quot;&gt;
&lt;p&gt;
I like the &quot;Use last region&quot; option, which you can access by running 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;flameshot config
&lt;/pre&gt;
&lt;/div&gt;


&lt;figure id=&quot;org933239c&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/flameshot-+-emacs-+-dbus/2025-01-07_12-56-52_screenshot.png&quot; alt=&quot;2025-01-07_12-56-52_screenshot.png&quot; /&gt;

&lt;/figure&gt;

&lt;p&gt;
Then running
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;flameshot gui
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
brings up a screen where you can select your region. (Shown in demo video). Hover over icons to learn the shortcuts.
&lt;/p&gt;

&lt;p&gt;
One thing I love in emacs is browsing man pages with &lt;code&gt;(woman)&lt;/code&gt;, where you can learn more about flameshot.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;woman &lt;span style=&quot;color: #677691;&quot;&gt;&quot;flameshot&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;figure id=&quot;orgdb39f5c&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/flameshot-+-emacs-+-dbus/output-2025-01-07-18:05:04.gif&quot; alt=&quot;output-2025-01-07-18:05:04.gif&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 2: &lt;/span&gt;animation of scrolling through woman in emacs&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Code&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Code&quot;&gt;Code&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Code&quot;&gt;
&lt;p&gt;
There are only two components: 
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;&lt;b&gt;Monitor:&lt;/b&gt; gets notified of events in dbus. You specify fields to filter only the events you want.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Handler:&lt;/b&gt; handles the event. Call arbitrary code.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/dbus-flameshot-handler&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;rest&lt;/span&gt; _args&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;A dbus event handler that adds picture attachments. Forces a
 selection of media type as &#92;&quot;image/png&#92;&quot; to speed up workflow&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;completing-read-function
         &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;rest&lt;/span&gt; _&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
           &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;customize a variable for this instead to your liking
&lt;/span&gt;           &lt;span style=&quot;color: #677691;&quot;&gt;&quot;image/png&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;               
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;yank-media&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;insert &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Save the dbus object, which is a monitor, so we can unregister it if needed
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This invocation can be derived by watching dbus-monito messages
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/dbus-flameshot-monitor
      &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;dbus-register-monitor
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:session&lt;/span&gt;                       &lt;span style=&quot;color: #677691;&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;bus
&lt;/span&gt;       #&#39;jwow/dbus-flameshot-handler
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:sender&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;org.flameshot.Flameshot&quot;&lt;/span&gt;
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:path&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/org/freedesktop/Notifications&quot;&lt;/span&gt;
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:interface&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;org.freedesktop.Notifications&quot;&lt;/span&gt;
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:member&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Notify&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;To disable the auto yank-media behavior, unregister the monitor
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;dbus-unregister-object jwow/dbus-flameshot-monitor&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Quirks&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Quirks&quot;&gt;Quirks&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Quirks&quot;&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Notify%3F&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;Notify%3F&quot;&gt;Notify?&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-Notify%3F&quot;&gt;
&lt;p&gt;
Yes, I waited for &lt;code&gt;Notify&lt;/code&gt; to get called, which populates system notifications:
&lt;/p&gt;


&lt;figure id=&quot;org875b8f6&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/flameshot-+-emacs-+-dbus/2025-01-07_16-10-35_screenshot.png&quot; alt=&quot;2025-01-07_16-10-35_screenshot.png&quot; /&gt;

&lt;/figure&gt;

&lt;p&gt;
I did this in part because there weren&#39;t many identifiable events from flameshot. I was a little sad about that.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;label class=&quot;org-src-name&quot;&gt;&lt;span class=&quot;listing-number&quot;&gt;Listing 1: &lt;/span&gt;message of flameshot using Notify after writing binary data&lt;/label&gt;&lt;pre class=&quot;src src-zsh&quot; id=&quot;org527f15f&quot;&gt;method call &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;time&lt;/span&gt;=1736280897.494725 &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;sender&lt;/span&gt;=:1.229 -&amp;gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;destination&lt;/span&gt;=org.freedesktop.Notifications &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;serial&lt;/span&gt;=111
   &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;path&lt;/span&gt;=/org/freedesktop/Notifications; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;interface&lt;/span&gt;=org.freedesktop.Notifications; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;member&lt;/span&gt;=Notify string &lt;span style=&quot;color: #677691;&quot;&gt;&quot;flameshot&quot;&lt;/span&gt; uint32
   0 string &lt;span style=&quot;color: #677691;&quot;&gt;&quot;flameshot&quot;&lt;/span&gt; string &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Flameshot Info&quot;&lt;/span&gt; string &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Capture saved to clipboard.&quot;&lt;/span&gt; array [ ] array [ ] int32 5000
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-No%20Signals%3F&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;No%20Signals%3F&quot;&gt;No Signals?&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-No%20Signals%3F&quot;&gt;
&lt;p&gt;
At this point, it&#39;s a bit weird IMO, that Flameshot doesn&#39;t have any signals (for broadcasting) in its DBUS interface. I think it should. That way, emacs can register itself as a proper service and get notified that way. 
&lt;/p&gt;

&lt;p&gt;
Emacs registering a monitor might be hacky (I don&#39;t know, I&#39;m not a heavy dbus user) and I cannot comment on its performance. Creating a monitor is based on &lt;code&gt;dbus-monitor&lt;/code&gt;, a shell command (and elisp command). 
&lt;/p&gt;



&lt;figure id=&quot;orgcdba2ca&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/flameshot-+-emacs-+-dbus/2025-01-07_15-49-18_screenshot.png&quot; alt=&quot;2025-01-07_15-49-18_screenshot.png&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 4: &lt;/span&gt;In D-Spy, I inspect the interface for Flameshot. It has 3 methods and 0 signals.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Flameshot%20sends%20an%20incorrect%20DBUS%20message%3F&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;Flameshot%20sends%20an%20incorrect%20DBUS%20message%3F&quot;&gt;Flameshot sends an incorrect DBUS message?&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-Flameshot%20sends%20an%20incorrect%20DBUS%20message%3F&quot;&gt;
&lt;p&gt;
In the shell command I get something like this:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;method call &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;time&lt;/span&gt;=1736280897.456930 &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;sender&lt;/span&gt;=:1.460 -&amp;gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;destination&lt;/span&gt;=org.flameshot.Flameshot &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;serial&lt;/span&gt;=9 &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;path&lt;/span&gt;=/;
   &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;interface&lt;/span&gt;=(null); &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;member&lt;/span&gt;=attachScreenshotToClipboard array of bytes [ 00 00 00 01 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d
   49 48 44 52 00 00 02 90 00 00 01 ec 0
 ...
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
In emacs&#39;s code path for dbus events:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;dbus-event-bus-name: D-Bus error: &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Not a valid D-Bus event&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;dbus-event
 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:session-private&lt;/span&gt; 1 9 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;:1.576&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;org.flameshot.Flameshot&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/&quot;&lt;/span&gt; nil &lt;span style=&quot;color: #677691;&quot;&gt;&quot;
attachScreenshotToClipboard&quot;&lt;/span&gt; jwow/dbus-flameshot-handler ...&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The interfaces is missing; seems like a bug. In any case, it doesn&#39;t avoid the issues of text being in the clipboard, and &lt;code&gt;(yank-media)&lt;/code&gt; having no idea how to handle it.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Emacs%20~%28dbus-monitor%29~%2C%20funnels%20all%20events&quot; class=&quot;outline-4&quot;&gt;
&lt;h4 id=&quot;Emacs%20~%28dbus-monitor%29~%2C%20funnels%20all%20events&quot;&gt;Emacs &lt;code&gt;(dbus-monitor)&lt;/code&gt;, funnels all events&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-Emacs%20~%28dbus-monitor%29~%2C%20funnels%20all%20events&quot;&gt;
&lt;p&gt;
If you set up a monitor, unfortunately calling &lt;code&gt;(dbus-monitor)&lt;/code&gt; will make &lt;b&gt;your previously defined handler handle all events.&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
I think this is a flaw in the emacs dbus api. &lt;code&gt;dbus-monitor&lt;/code&gt; should call a built-in handler.
&lt;/p&gt;

&lt;p&gt;
At this point, unregister the dbus monitor to get back to normal.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;dbus-unregister-object jwow/dbus-flameshot-monitor&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Explore%20More&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Explore%20More&quot;&gt;Explore More&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Explore%20More&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;See &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/dbus.html#Top&quot;&gt;dbus#Top&lt;/a&gt; for an overview of the dbus api.&lt;/li&gt;
&lt;li&gt;Ian Eure&#39;s informative and concise presentation at &lt;a href=&quot;https://emacsconf.org/2022/talks/dbus/&quot;&gt;https://emacsconf.org/2022/talks/dbus/&lt;/a&gt;. He shows off an interface where he uses DBUS to detect if a usb drive connects to the computer.&lt;/li&gt;
&lt;li&gt;Think about things you could do with the handler:
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Save the data to a file and save the file name to kill-ring&lt;/li&gt;
&lt;li&gt;experiment with &lt;code&gt;(gui-get-selection &#39;CLIPBOARD &#39;TARGETS)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;pipe the screenshot to a program to resize it&lt;/li&gt;
&lt;li&gt;get auto-ocr, and yank the text from the image to kill-ring&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Thanks for supporting my work. Turning into an unstoppable space god wouldn&#39;t be possible without your help!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/flameshot-+-emacs-+-dbus.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
For one, you have to create a loop in bash to keep it listening. Which isn&#39;t bad. It notifies whenever text is &lt;i&gt;selected&lt;/i&gt;, not even copied, as well. To change that, you have to change the C code and recompile the binary.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
See &lt;a href=&quot;https://unix.stackexchange.com/a/723818&quot;&gt;https://unix.stackexchange.com/a/723818&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Selective org inline image toggle</title>
    <link href="https://17070415.xyz/blog/selective-org-inline-image-toggle.html"/>
    <updated>4025-01-07T06:52:00Z</updated>
    <id>https://17070415.xyz/blog/selective-org-inline-image-toggle.html</id>
    <content type="html">&lt;p&gt;
Today while working on &lt;a href=&quot;https://17070415.xyz/blog/flameshot-+-emacs-+-dbus.html&quot;&gt;my flameshot article&lt;/a&gt;, I wanted to toggle
inline images only where my cursor was. I was piling a ton of images and didn&#39;t want to wade through each of them.
&lt;/p&gt;


&lt;figure id=&quot;orgfbba399&quot;&gt;
&lt;img src=&quot;file:///home/furaro/src/my-site/src/content/data/c6/8b39f2-abf8-4379-acbb-910aeb9f037c/output-2025-01-07-10:44:50.gif&quot; alt=&quot;output-2025-01-07-10:44:50.gif&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 1: &lt;/span&gt;animation of toggling inline images at point&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
Here&#39;s the same image in html that I toggle on org mode:
&lt;/p&gt;


&lt;figure id=&quot;org228cf9b&quot;&gt;
&lt;img src=&quot;file:///home/furaro/src/my-site/src/content/data/c6/8b39f2-abf8-4379-acbb-910aeb9f037c/clipboard-20250107T090717.png&quot; alt=&quot;clipboard-20250107T090717.png&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 2: &lt;/span&gt;An image for toggling 1&lt;/figcaption&gt;
&lt;/figure&gt;


&lt;figure id=&quot;org6174a7b&quot;&gt;
&lt;img src=&quot;file:///home/furaro/src/my-site/src/content/data/c6/8b39f2-abf8-4379-acbb-910aeb9f037c/clipboard-20250107T090717.png&quot; alt=&quot;clipboard-20250107T090717.png&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 3: &lt;/span&gt;An image for toggling 2&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
Luckily, &lt;code&gt;org-toggle-inline-images&lt;/code&gt; allows you to specify the beginning and end of a region:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-toggle-inline-images t 379 448&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And here&#39;s the code:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/toggle-image&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Toggle viewing the image from an org LINK at POINT if the LINK paths to
an image. Otherwise, toggle all images.

If the link is to an image but it does not exist, nothing will happen.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if-let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;link-at-point &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-in-regexp org-link-bracket-re 1&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if-let*&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;link-context &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-element-context&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;local-file? &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;member &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; link-context&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                                     &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;attachment&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;image? &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-file-image-p &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:path&lt;/span&gt; link-context&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
          &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-toggle-inline-images t &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;car link-at-point&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;cdr link-at-point&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-toggle-inline-images t&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-toggle-inline-images t&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;define-key org-mode-map &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-t&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; #&#39;jwow/toggle-image&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Most of the time taken to code was actually digging into &lt;code&gt;ol.el&lt;/code&gt; and &lt;code&gt;org.el&lt;/code&gt; to determine if 
something was a valid image link or not.
&lt;/p&gt;

&lt;p&gt;
Hope this helped!
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Org Attachment Investigation: Forced Absolute Paths on Export</title>
    <link href="https://17070415.xyz/blog/org-attachment-investigation:-forced-absolute-paths-on-export.html"/>
    <updated>4024-12-30T02:14:00Z</updated>
    <id>https://17070415.xyz/blog/org-attachment-investigation:-forced-absolute-paths-on-export.html</id>
    <content type="html">&lt;p&gt;
In this post I investigate how org attachments links behave on export. Mainly I care about how it renders html links, forcing absolute paths. I found it surprising, and abnormal.
&lt;/p&gt;

&lt;p&gt;
I&#39;m running emacs 30.0.50, an edge build, and I ran into a situation where 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&lt;a href=&quot;attachment:clipboard-20241230T022004.png&quot;&gt;attachment:clipboard-20241230T022004.png&lt;/a&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
exports this &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; html tag:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot;&gt;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;img&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;src&lt;/span&gt;=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;file:///home/furaro/src/my-site/src/content/data/7d/167a0f-5ae4-4f45-bd29-62ec6e464173/clipboard-20241230T022004.png&quot;&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;alt&lt;/span&gt;=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;clipboard-20241230T022004.png&quot;&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
But in html, your browser can&#39;t render that image. The link is broken and you would instead see the &lt;code&gt;alt&lt;/code&gt; text &quot;clipboard-20241230T022004.png&quot;
&lt;/p&gt;

&lt;p&gt;
What we&#39;d really like is just to change the &lt;code&gt;src&lt;/code&gt; attribute to something like
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;data/7d/167a0f-5ae4-4f45-bd29-62ec6e464173/clipboard-20241230T022004.png&quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
So that upon exporting, the &lt;code&gt;html&lt;/code&gt; file can look through the same path to find the image. I have not customized &lt;code&gt;org-attach&lt;/code&gt;. Others online say they get relative paths&amp;#x2013;and they struggled to get absolute paths (&lt;a href=&quot;https://red.artemislena.eu/r/emacs/comments/hfd8o3/org_mode_html_export_attachment_link_types/&quot;&gt;link&lt;/a&gt;).
&lt;/p&gt;

&lt;p&gt;
For this article, I consulted &lt;a href=&quot;https://orgmode.org/manual/Advanced-Export-Configuration.html&quot;&gt;https://orgmode.org/manual/Advanced-Export-Configuration.html&lt;/a&gt; a lot.
&lt;/p&gt;

&lt;p&gt;
Jump to &lt;a href=&quot;https://17070415.xyz/blog/org-attachment-investigation:-forced-absolute-paths-on-export.html#tl%3Bdr&quot;&gt;tl;dr&lt;/a&gt; for the reasons.
&lt;/p&gt;
&lt;div id=&quot;outline-container-Org%20Vocabulary&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Org%20Vocabulary&quot;&gt;Org Vocabulary&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Org%20Vocabulary&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;backend:&lt;/code&gt; this is the format org is being told to export to. Examples are html, odt, latex, and many others. Check all your loaded backends in &lt;code&gt;org-export-registered-backends&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AST&lt;/code&gt;: abstract syntax tree. This is a representation of an org document that&#39;s easy for lisp to manipulate. It&#39;s a tree datastructure.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parsing:&lt;/code&gt; this is the process of building the AST. Loosely, org copies your org buffer into a temporary buffer and certain actions like macro expansion, &lt;code&gt;#+includes&lt;/code&gt;, and comment removal happen on this temporary buffer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transcoder:&lt;/code&gt; a translater. It is a function that takes some element inside org mode (like a source block), and transforms it into a string that can be parsed by the backend.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;derived backend:&lt;/code&gt; is a backend that has a parent. You specify transcoders when creating a custom backend for export, falling back to the parent&#39;s transcoder, for say, a &lt;code&gt;link&lt;/code&gt;. When deriving a backend, one important keyword property is &lt;code&gt;:translate-alist&lt;/code&gt;, which is a list of the transcoders you specify.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-link-parameters:&lt;/code&gt; This is a list of link types and their behavior when certain actions are taken. Most commonly, you &lt;code&gt;:follow&lt;/code&gt; a link, and the follow function is then used. In our case, we mostly will care about the &lt;code&gt;:export&lt;/code&gt;. Read the help doc for the many more parameters.&lt;br /&gt;Here&#39;s an example of a link type for &lt;code&gt;[[nov:a-path-i-made-up]]&lt;/code&gt;
&lt;pre class=&quot;example&quot; id=&quot;org794844b&quot;&gt;
((&quot;nov&quot; :follow nov-org-link-follow :store nov-org-link-store)...)
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filters:&lt;/code&gt; are functions. They run after the transcoder is run and get the transcoded string. The positional arguments for a filter are &lt;code&gt;(text backend info)&lt;/code&gt;, where &lt;code&gt;info&lt;/code&gt; is a giant context object that gets populated during parsing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-tl%3Bdr&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;tl%3Bdr&quot;&gt;tl;dr&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-tl%3Bdr&quot;&gt;
&lt;p&gt;
&lt;code&gt;org-attach.el&lt;/code&gt; bypasses transcoders and the &lt;code&gt;org-link-parameter&lt;/code&gt; &lt;code&gt;:export&lt;/code&gt; functionality. Why it does this, I don&#39;t know.
&lt;/p&gt;

&lt;p&gt;
&lt;i&gt;How&lt;/i&gt; it does that is interesting:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This is the last line of code in org-attach.el
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-hook &#39;org-export-before-parsing-functions &#39;org-attach-expand-links&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;code&gt;org-attach.el&lt;/code&gt; decides to rewrite the temporary buffer before the AST is even parsed.
&lt;/p&gt;

&lt;p&gt;
When AST parsing happens, instead of 
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&lt;a href=&quot;attachment:clipboard-20241230T000706.png&quot;&gt;attachment:clipboard-20241230T000706.png&lt;/a&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
we get
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&lt;a href=&quot;file:///home/furaro/src/temp/data/80/943450-583e-4236-a2d1-1e926fbb15bd/clipboard-20241230T000706.png&quot;&gt;file:/home/furaro/src/temp/data/80/943450-583e-4236-a2d1-1e926fbb15bd/clipboard-20241230T000706.png&lt;/a&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Thus even the link type (attachment) is lost, and replaced with file.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-In%20depth&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;In%20depth&quot;&gt;In depth&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-In%20depth&quot;&gt;
&lt;p&gt;
Let&#39;s look at why certain solutions don&#39;t work. For that, let&#39;s see what the help says:
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;org08c2872&quot;&gt;
org-export-before-parsing-functions is a variable defined in ox.el.

Value
(org-attach-expand-links)

Documentation
Abnormal hook run before parsing an export buffer.

This is run after include keywords and macros have been expanded
and Babel code blocks executed, on a copy of the original buffer
being exported.
&lt;/pre&gt;

&lt;p&gt;
And we run &lt;code&gt;org-attach-expand-links&lt;/code&gt;, replacing the link with
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot;file:&quot;&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-attach-expand file&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And &lt;code&gt;org-attach-expand&lt;/code&gt; &lt;b&gt;always&lt;/b&gt; expands to a full file path.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;org-attach-expand&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;file&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Return the full path to the current entry&#39;s attachment file FILE.
Basically, this adds the path to the attachment directory.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;expand-file-name file &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-attach-dir&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The code execution cannot be influenced by a customization. Sigh.
&lt;/p&gt;

&lt;p&gt;
To recap: &lt;code&gt;org-attach.el&lt;/code&gt; &lt;b&gt;rewrites the temporary buffer&lt;/b&gt; that org uses, BEFORE parsing the temp buffer into its abstract syntax tree format. The transcoders run after the AST is built, explaining why methods that involve the transcoding phase, do not work. This means that even creating your own derived backend alone will work. Not unless you do something to influence the behavior of &lt;code&gt;org-export-before-parsing-functions&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Non%20solutions%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Non%20solutions%3A&quot;&gt;Non solutions:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Non%20solutions%3A&quot;&gt;
&lt;p&gt;
For this puzzle, these are the most likely approaches I think readers will attempt, which, at least as I&#39;ve coded them, won&#39;t work.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Don&#39;t use attachments&lt;br /&gt;This is fine, you can just use file: style links but that defeats the purpose of the investigation for people who rely on org attachments.&lt;/li&gt;

&lt;li&gt;Setting an &lt;code&gt;:export&lt;/code&gt; function for the attachment
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;my-fun&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;path desc backend info&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;message &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot;This is the link path: &quot;&lt;/span&gt; path&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;now do stuff to return the html string
&lt;/span&gt;  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Cannot snag on the debugger, message never happens
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-link-set-parameters &lt;span style=&quot;color: #677691;&quot;&gt;&quot;attachment&quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:export&lt;/span&gt; #&#39;my-fun&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If this function ran, &lt;code&gt;path&lt;/code&gt; would be &lt;code&gt;&quot;clipboard-20241230T022004.png&quot;&lt;/code&gt;, but this never triggers. This would be a rather clean solution as this specifically triggers only for &lt;code&gt;attachment:&lt;/code&gt; links. The org export machinery&#39;s backend should detect links with custom protocols using the built-in &lt;code&gt;org-export-custom-protocol-maybe&lt;/code&gt; function. ox-html does, for example.
&lt;/p&gt;

&lt;p&gt;
One caveat of this method is that you want to return a string specific to whatever the backend target is (latex, html, markdown, etc.) This is a hit for maintainability.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;Defining a custom transcoder (maybe in your own derived backend)&lt;br /&gt;for something like &lt;code&gt;(link . jwow/org-attach-link)&lt;/code&gt;

&lt;p&gt;
The AST gets passed to ox-html&#39;s &lt;code&gt;org-html-link&lt;/code&gt;, but the &lt;code&gt;:path&lt;/code&gt; will have been populated as an absolute path, of course because the input for the AST has already been changed.
&lt;/p&gt;

&lt;p&gt;
You can verify in &lt;code&gt;org-html-link&lt;/code&gt;, calling this line from edebug:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:path&lt;/span&gt; link&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You&#39;ll be able to detect the long UUID that&#39;s characteristic of an org attachment, but this is hacky.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;Operating after the transcoder, hooking into the &lt;code&gt;org-export-filter-link-functions&lt;/code&gt; mechanism. &lt;br /&gt;Again, like the last approach, you have to guess from the full file path that this WAS an attachment, then most likely do a string replace operation.
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;my-org-link-filter&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;text backend info&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;message text&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;do something to text
&lt;/span&gt;  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-to-list &#39;org-export-filter-link-functions #&#39;my-org-link-filter&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Text in this case is
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&amp;lt;img src=&quot;file:///home/furaro/src/temp/data/80/943450-583e-4236-a2d1-1e926fbb15bd/clipboard-20241230T000706.png&quot; alt=&quot;clipboard-20241230T000706.png&quot;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
It is fair to note that deciding on a custom string/directory for org attach to use can work, and you can regexp replace, with that coupling of systems.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-One%20solution&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;One%20solution&quot;&gt;One solution&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-One%20solution&quot;&gt;
&lt;p&gt;
I thought a solution was best found by removing this behavior of expanding links before parsing:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;remove-hook &#39;org-export-before-parsing-functions &#39;org-attach-expand-links&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
After that, a lot of reasonable approaches are possible.
&lt;/p&gt;

&lt;p&gt;
But let me tell you why I decided against that.
&lt;/p&gt;

&lt;p&gt;
I didn&#39;t want to maintain different &lt;code&gt;:export&lt;/code&gt; backend targets, and I wasn&#39;t interested in tracing through how org decided to generate the html for attachments, in fact, I liked how images are just handled by probably one of the most used org-links. Can we hook into machinery for that?
&lt;/p&gt;

&lt;p&gt;
This was likely what led to the design decision in &lt;code&gt;org-attach.el&lt;/code&gt;&amp;#x2013;they didn&#39;t want to deal with a new link type having to bloat up the codebase to support, html, md, latex, odt, and others. Even the docs say &lt;b&gt;attachments should behave like files&lt;/b&gt;.
&lt;/p&gt;

&lt;p&gt;
I just wish there were a customization setting to specify whether the link should appear relative or absolute.
&lt;/p&gt;

&lt;p&gt;
So all I did was change &lt;code&gt;org-attach-expand&lt;/code&gt; after all:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/org-attach-expand&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;file&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Return an expanded relative file path for a FILE where
  links look like [[attachment:FILE]], relative to the org file
The return string may start with data/0a/39...&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;attachment-abs-path &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;expand-file-name file &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-attach-dir&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-file &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;buffer-file-name
                    &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:buffer&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-element-context&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-file-dir &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;file-name-directory org-file&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;file-relative-name attachment-abs-path org-file-dir&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Season to taste.
&lt;/p&gt;

&lt;p&gt;
One great thing is that &lt;code&gt;C-c C-o&lt;/code&gt; remains functional. This way, all exporters that already handle file links should continue working with your relative path.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;UPDATE 2025-01-07:&lt;/b&gt; I&#39;ve realized that this breaks &lt;code&gt;org-display-inline-images&lt;/code&gt;, so be careful about that&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/org-attachment-investigation:-forced-absolute-paths-on-export.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. The other options we discussed, like an export filter, would still work.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-It%20works%21&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;It%20works%21&quot;&gt;It works!&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-It%20works%21&quot;&gt;
&lt;p&gt;
If it works here&#39;s an image of this section before I added this sentence:
&lt;img src=&quot;file:///home/furaro/src/my-site/src/content/data/0a/6dcc10-8747-4cf7-b499-47047b447653/clipboard-20241230T053742.png&quot; alt=&quot;clipboard-20241230T053742.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;
I haven&#39;t tested this extensively, but it seems to work for now.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Explore%20more&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Explore%20more&quot;&gt;Explore more&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Explore%20more&quot;&gt;
&lt;p&gt;
Lastly, if you like what I&#39;m doing, please consider sponsoring me.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;John Kitchin wrote an article on easier facilities to extend org links (&lt;a href=&quot;https://kitchingroup.cheme.cmu.edu/blog/2018/05/09/Making-it-easier-to-extend-the-export-of-org-mode-links-with-generic-functions/&quot;&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Tony Aldon wrote a &lt;a href=&quot;https://github.com/tonyaldon/posts/blob/master/posts.org#2022-04-27-wed-full-example-of-org-mode-links-internal-links-and-search-options&quot;&gt;piece on links&lt;/a&gt; (also &lt;a href=&quot;https://safereddit.com/r/emacs/comments/ud75wt/full_example_of_orgmode_links_internal_links_and/&quot;&gt;on reddit&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/org-attachment-investigation:-forced-absolute-paths-on-export.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Which is odd in terms of its design, because &lt;code&gt;org-display-inline-images&lt;/code&gt;  has a check 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;label class=&quot;org-src-name&quot;&gt;&lt;span class=&quot;listing-number&quot;&gt;Listing 1: &lt;/span&gt;Found in /usr/share/emacs/31.0.50/lisp/org/org.el&lt;/label&gt;&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;and&lt;/span&gt; file &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;file-exists-p file&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p class=&quot;footpara&quot;&gt;
after the variable &lt;code&gt;file&lt;/code&gt; is bound. And relatives paths pass the &lt;code&gt;file-exists-p&lt;/code&gt; check.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Rewriting org links on export</title>
    <link href="https://17070415.xyz/blog/rewriting-org-links-on-export.html"/>
    <updated>4024-12-29T06:56:00Z</updated>
    <id>https://17070415.xyz/blog/rewriting-org-links-on-export.html</id>
    <content type="html">&lt;p&gt;
Skip to &lt;a href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#Solutions&quot;&gt;Solutions&lt;/a&gt; if you only care about approaches to rewriting org links on export. I recommend referring to &lt;a href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#Org%20Vocabulary&quot;&gt;Org Vocabulary&lt;/a&gt; if you&#39;re not sure what I&#39;m talking about.
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;
My images weren&#39;t linking properly so I had put off including images in my posts. Here&#39;s an image of my org doc:
&lt;/p&gt;


&lt;figure id=&quot;orgda90d38&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/changing-org-html-export,-plain-list/2024-12-29_04-43-19_screenshot.png&quot; alt=&quot;2024-12-29_04-43-19_screenshot.png&quot; /&gt;

&lt;/figure&gt;

&lt;p&gt;
Here&#39;s a small conundrum dear reader:
&lt;/p&gt;
&lt;div id=&quot;outline-container-Problem&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Problem&quot;&gt;Problem&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Problem&quot;&gt;
&lt;p&gt;
&lt;b&gt;Given this file link on org mode:&lt;/b&gt; 
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org75ac402&quot;&gt;
[[file:../assets/media/changing-org-html-export,-plain-list/2024-12-19_12-31-41_screenshot.png]]
&lt;/pre&gt;

&lt;p&gt;
&lt;b&gt;How would you change the path on html export to the following:&lt;/b&gt;
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org5ff012d&quot;&gt;
../../assets/media/changing-org-html-export,-plain-list/2024-12-19_12-31-41_screenshot.png
&lt;/pre&gt;
&lt;p&gt;
This is what we want the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag&#39;s &lt;code&gt;src&lt;/code&gt; to be. However, what we get is predictably:
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgac3e710&quot;&gt;
../assets/media/changing-org-html-export,-plain-list/2024-12-19_12-31-41_screenshot.png
&lt;/pre&gt;

&lt;p&gt;
&lt;b&gt;Context: A Tale of Two Directories&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
The blog layout I have isn&#39;t completely symmetric with the source files that generate the blog, because I don&#39;t generate a &lt;code&gt;&amp;lt;post-name&amp;gt;.html&lt;/code&gt;, &lt;i&gt;I have instead&lt;/i&gt; &lt;code&gt;&amp;lt;post-name&amp;gt;/index.html&lt;/code&gt;, meaning the relative paths &lt;span class=&quot;underline&quot;&gt;&lt;i&gt;must go up one more time&lt;/i&gt;&lt;/span&gt;.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s a concrete example of a post with an image:
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;orga960fdc&quot;&gt;
~/src/my-site/public/blog/changing-org-html-export,-plain-list/index.html
&lt;/pre&gt;

&lt;p&gt;
And the image is located in
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;org470f89f&quot;&gt;
~/src/my-site/public/assets/media/changing-org-html-export,-plain-list/2024-12-19_12-31-41_screenshot.png
&lt;/pre&gt;

&lt;p&gt;
Files in &lt;code&gt;public/&lt;/code&gt; are what get uploaded.
&lt;/p&gt;

&lt;p&gt;
So from a particular blog page (like this one), we would need to climb up twice (&lt;code&gt;../../&lt;/code&gt;), which brings us to &lt;code&gt;public&lt;/code&gt;, then we can access all those racy images of code.
&lt;/p&gt;

&lt;p&gt;
So dear reader, how would you approach this?
&lt;/p&gt;

&lt;p&gt;
Skip to &lt;a href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#Solutions&quot;&gt;Solutions&lt;/a&gt;. I&#39;ve included some vocabulary to facilitate discussion about org internals.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Org%20Vocabulary&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Org%20Vocabulary&quot;&gt;Org Vocabulary&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Org%20Vocabulary&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;backend:&lt;/code&gt; this is the format org is being told to export to. Examples are html, odt, latex, and many others. Check all your loaded backends in &lt;code&gt;org-export-registered-backends&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AST&lt;/code&gt;: abstract syntax tree. This is a representation of an org document that&#39;s easy for lisp to manipulate. It&#39;s a tree datastructure.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parsing:&lt;/code&gt; this is the process of building the AST. Loosely, org copies your org buffer into a temporary buffer and certain actions like macro expansion, &lt;code&gt;#+includes&lt;/code&gt;, and comment removal happen on this temporary buffer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transcoder:&lt;/code&gt; a translater. It is a function that takes some element inside org mode (like a source block), and transforms it into a string that can be parsed by the backend.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;derived backend:&lt;/code&gt; is a backend that has a parent. You specify transcoders when creating a custom backend for export, falling back to the parent&#39;s transcoder, for say, a &lt;code&gt;link&lt;/code&gt;. When deriving a backend, one important keyword property is &lt;code&gt;:translate-alist&lt;/code&gt;, which is a list of the transcoders you specify.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-link-parameters:&lt;/code&gt; This is a list of link types and their behavior when certain actions are taken. Most commonly, you &lt;code&gt;:follow&lt;/code&gt; a link, and the follow function is then used. In our case, we mostly will care about the &lt;code&gt;:export&lt;/code&gt;. Read the help doc for the many more parameters.&lt;br /&gt;Here&#39;s an example of a link type for &lt;code&gt;[[nov:a-path-i-made-up]]&lt;/code&gt;
&lt;pre class=&quot;example&quot; id=&quot;orgbbc39a5&quot;&gt;
((&quot;nov&quot; :follow nov-org-link-follow :store nov-org-link-store)...)
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filters:&lt;/code&gt; are functions. They run after the transcoder is run and get the transcoded string. The positional arguments for a filter are &lt;code&gt;(text backend info)&lt;/code&gt;, where &lt;code&gt;info&lt;/code&gt; is a giant context object that gets populated during parsing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Solutions&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Solutions&quot;&gt;Solutions&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Solutions&quot;&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Solution%201&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Solution%201&quot;&gt;Solution 1&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Solution%201&quot;&gt;
&lt;pre class=&quot;example&quot; id=&quot;orgfecb10d&quot;&gt;
postname/index.html -&amp;gt; postname.html
&lt;/pre&gt;

&lt;p&gt;
We can simply make a file, &lt;code&gt;&amp;lt;postname&amp;gt;.html&lt;/code&gt; and lose the directory above it. Then we have symmetry. But funnily enough, I didn&#39;t realize this until the end that my files were actually named &lt;code&gt;index.html&lt;/code&gt;&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, and that I had an asymmetric directory structure. Instead, I was trying so hard to get Solution 2 to work. Plus, I use 11ty to place these files and I didn&#39;t want to dig into it.
&lt;/p&gt;

&lt;p&gt;
Since writing the outline of this article I have actually chosen this solution&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;

&lt;p&gt;
Still, the other solutions are worthy considerations to have at your arsenal if you are a nerd, or you just deal with exporting to different targets arbitrarily.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Solution%202&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Solution%202&quot;&gt;Solution 2&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Solution%202&quot;&gt;
&lt;pre class=&quot;example&quot; id=&quot;org2d86f79&quot;&gt;
../assets -&amp;gt; /assets
&lt;/pre&gt;

&lt;p&gt;
I think assets should be located from the root serving directory, so I&#39;d prefer a prefix of &lt;code&gt;/assets/&lt;/code&gt;. In the org document, &lt;code&gt;../assets&lt;/code&gt; must remain so we can follow the link on our filesystem using &lt;code&gt;C-c C-o&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
What about a custom transcoder, where we modify the link to be an absolute path, then pass it into &lt;code&gt;org-html-link&lt;/code&gt;, which translates those file links in org mode to html?
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;This didn&#39;t work&lt;/b&gt;&amp;#x2013;at least using this idea alone doesn&#39;t.
&lt;/p&gt;

&lt;p&gt;
The problem when you do that is inside &lt;code&gt;org-html-link&lt;/code&gt;, there is a call to &lt;code&gt;org-export-file-uri&lt;/code&gt;, which will transform a path&#39;s prefix into
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org8b81108&quot;&gt;
../assets -&amp;gt; file:///assets
&lt;/pre&gt;

&lt;p&gt;
When looking up a &lt;a href=&quot;file:///&quot;&gt;file://&lt;/a&gt;, the browser will attempt to look up something on the user&#39;s computer (and likely the browser will stop that from happening), not the image from the web server.
&lt;/p&gt;

&lt;p&gt;
At this point, I gave up on absolute pathing from the webserver because messing with too much org machinery won&#39;t be maintainable. See &lt;a href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#Solution%205&quot;&gt;Solution 5&lt;/a&gt; for a different way to do this.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Solution%203&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Solution%203&quot;&gt;Solution 3&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Solution%203&quot;&gt;
&lt;pre class=&quot;example&quot; id=&quot;org2b708c6&quot;&gt;
../assets -&amp;gt; ../../assets
&lt;/pre&gt;

&lt;p&gt;
After trying to make solution 2 work, I had edebugged &lt;code&gt;org-html-link&lt;/code&gt; and &lt;code&gt;org-publish-file-relative-name&lt;/code&gt; and knew how to rewrite the paths. I just needed to make sure the machinery wouldn&#39;t do something unexpected.
&lt;/p&gt;

&lt;p&gt;
Working from Solution 2, I rewrote the export path using pretty much the same code, the only difference was how to handle string replacement.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/org-html-link&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;link desc info&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Transcode a LINK node from an Org AST to HTML.
DESC is the description of the link and can be empty
INFO is a giant context object of the export that&#39;s decorated with a ton
of data, and metadata with things like the buffer name, input file, etc.&quot;&lt;/span&gt;
        &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;type &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; link&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
              &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;raw-path &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:path&lt;/span&gt; link&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;rewrite ../assets -&amp;gt; ../../assets
&lt;/span&gt;    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;and&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;string= &lt;span style=&quot;color: #677691;&quot;&gt;&quot;file&quot;&lt;/span&gt; type&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
             &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;string-prefix-p &lt;span style=&quot;color: #677691;&quot;&gt;&quot;../&quot;&lt;/span&gt; raw-path&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;modified-path &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;replace-regexp-in-string
                              &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I used re-builder to come up with this regexp
&lt;/span&gt;                              &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#92;&#92;.&#92;&#92;./&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;+assets&quot;&lt;/span&gt;
                              &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;1../assets&quot;&lt;/span&gt;
                              raw-path&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
          &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-html-link &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-element-put-property link &lt;span style=&quot;color: #81A1C1;&quot;&gt;:path&lt;/span&gt; modified-path&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                         desc info&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-html-link link desc info&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The key bit is the &lt;code&gt;replace-regexp-in-string&lt;/code&gt;, where we simply tack on one more &lt;code&gt;../&lt;/code&gt;. And it worked!&lt;sup&gt;&lt;a id=&quot;fnr.3&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#fn.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; 
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Solution%204&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Solution%204&quot;&gt;Solution 4&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Solution%204&quot;&gt;
&lt;p&gt;
If you read &lt;a href=&quot;org-attachment-investigation:-forced-absolute-paths-on-export.html&quot;&gt;my article on investigating attachment links&lt;/a&gt;, you&#39;ll also know that we could vary Solution 2 and 3, but slap on an export filter instead.
&lt;/p&gt;

&lt;p&gt;
Specifically, add a function to &lt;code&gt;org-export-filter-link-functions&lt;/code&gt; to regexp replace the strings and make them relative.
&lt;/p&gt;

&lt;p&gt;
This doesn&#39;t feel right to me because of the indirection&amp;#x2013;the org object has already been made into html. 
&lt;/p&gt;

&lt;p&gt;
For this approach, you&#39;d care about not polluting the export functionality in other projects. For this you should use a &lt;code&gt;.dir-local&lt;/code&gt;, or file local variable depending on how big your project is, and how often you need this link export code path to happen. See my &lt;a href=&quot;https://17070415.xyz/blog/project-specific-on-save-hooks-in-emacs.html&quot;&gt;article on .dir-locals&lt;/a&gt; for more.
&lt;/p&gt;

&lt;p&gt;
You can also ensure the filter happens ONLY in a file&lt;sup&gt;&lt;a id=&quot;fnr.4&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#fn.4&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; using a function you define in an org src-block.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Solution%205&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Solution%205&quot;&gt;Solution 5&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Solution%205&quot;&gt;
&lt;p&gt;
Use an &lt;code&gt;#+ATTR_HTML&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org2599e34&quot;&gt;
#+ATTR_HTML: :src /assets/media/changing-org-html-export,-plain-list/2024-12-29_04-43-19_screenshot.png
[[file:../assets/media/changing-org-html-export,-plain-list/2024-12-29_04-43-19_screenshot.png]]
&lt;/pre&gt;
&lt;p&gt;
&lt;i&gt;from isamert on &lt;a href=&quot;https://stackoverflow.com/questions/14684263/how-to-org-mode-image-absolute-path-of-export-html&quot;&gt;stackoverflow&lt;/a&gt;&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
This is the img I&#39;ve exported:
&lt;/p&gt;


&lt;figure id=&quot;orgf8fa73e&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/changing-org-html-export,-plain-list/2024-12-29_04-43-19_screenshot.png&quot; alt=&quot;2024-12-29_04-43-19_screenshot.png&quot; /&gt;

&lt;/figure&gt;

&lt;p&gt;
Check the img src attribute, it&#39;s absolute!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Solution%206&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Solution%206&quot;&gt;Solution 6&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Solution%206&quot;&gt;
&lt;p&gt;
Create a custom link type for
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;org86b3e73&quot;&gt;
../assets -&amp;gt; ../../assets
&lt;/pre&gt;

&lt;p&gt;
This solution comes from the revered Kris Jenkins mentioned in the &lt;a href=&quot;https://stackoverflow.com/questions/14684263/how-to-org-mode-image-absolute-path-of-export-html/14841597#14841597&quot;&gt;same stackoverflow post&lt;/a&gt; as isamert.
&lt;/p&gt;

&lt;p&gt;
For this solution you would no longer use the file type, instead, something like img in your markup: &lt;code&gt;[[img:../assets/img.png]]&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
For this problem, one could write
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-add-link-type
 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;img&quot;&lt;/span&gt;
 &#39;org-custom-link-img-follow
 &#39;org-custom-link-img-export&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;omitted the follow definition
&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;org-custom-link-img-export&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;path desc backend info&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;replace-regexp-in-string
   &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#92;&#92;.&#92;&#92;./&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;+assets&quot;&lt;/span&gt;
   &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;&#92;1../assets&quot;&lt;/span&gt;
   path&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
This defines only follow and export functions. Look into &lt;code&gt;(org-link-set-parameters TYPE &amp;amp;rest PARAMETERS)&lt;/code&gt; if you want to further define link behavior, especially if you care about using &lt;code&gt;org-store-link&lt;/code&gt; capabilities.
&lt;/p&gt;

&lt;p&gt;
One drawback is you might need to change a bunch of your org links from file -&amp;gt; img. This can be done by matching on an image suffix on files. Further, you have to implement 3 functions for export, store, and follow.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Conclusion&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Conclusion&quot;&gt;
&lt;p&gt;
There is a surprising amount of logic in links. At this time, I have other broken features in my edge build, reproducible with &lt;code&gt;emacs -Q&lt;/code&gt;. 
&lt;/p&gt;

&lt;p&gt;
In the future I&#39;ll most likely need to work on linking between different articles as well.
&lt;/p&gt;

&lt;p&gt;
The org element api is really powerful, and learning the ins and outs of a tool you use for hours every day can help you build a more flexible, custom workflow for spreading conspiracy theories. I recommend you try it.
&lt;/p&gt;

&lt;p&gt;
If this post helped you, please consider sponsoring me or helping me find work in software development or adjacent fields. Your help allows me to walk into grocery stores as a proud emacs user.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Hey, I started this blog on December of Earth Year 2023, then&amp;#x2026;well a lot of things happened and I forgot how I set up this project.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
modifying my 11ty build was a bit painful to do this. Check out &lt;a href=&quot;https://github.com/11ty/eleventy/issues/584&quot;&gt;https://github.com/11ty/eleventy/issues/584&lt;/a&gt;.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.3&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#fnr.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Readers should make note that this involves also swapping out the trancoder to use &lt;code&gt;jwow/org-html-link&lt;/code&gt;. In this case once you realize this works, you&#39;d likely create a new derived backend from html. See the &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/org.html#Advanced-Export-Configuration&quot;&gt;org manual for examples&lt;/a&gt;.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.4&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/rewriting-org-links-on-export.html#fnr.4&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
The &lt;code&gt;#+BIND&lt;/code&gt; toplevel keyword, details in &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/org.html#Advanced-Export-Configuration&quot;&gt;the org manual&lt;/a&gt;. It might be possible to define different BINDs in property drawers on subtrees too, so you can super localize how links in one subtree are exported if you need to.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>You Want To Modify Exported Footnotes In Org Mode</title>
    <link href="https://17070415.xyz/blog/you-want-to-modify-exported-footnotes-in-org-mode.html"/>
    <updated>4024-12-29T01:13:00Z</updated>
    <id>https://17070415.xyz/blog/you-want-to-modify-exported-footnotes-in-org-mode.html</id>
    <content type="html">&lt;p&gt;
Today I had been struggling with org&#39;s footnotes, and I&#39;d like to share how I&#39;ve done them up on this site.
&lt;/p&gt;

&lt;p&gt;
I wanted them to look more like in &lt;a href=&quot;https://karthinks.com/software/avy-can-do-anything/#fn:6&quot;&gt;Karthink&#39;s excellent blog&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
And now I&#39;m satisfied enough, though my html structure is different.
&lt;/p&gt;


&lt;figure id=&quot;org199b6e9&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/you-want-to-modify-exported-footnotes-in-org-mode/2024-12-29_00-08-46_screenshot.png&quot; alt=&quot;2024-12-29_00-08-46_screenshot.png&quot; /&gt;

&lt;/figure&gt;

&lt;p&gt;
The info manual doesn&#39;t list out the options in one place&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/you-want-to-modify-exported-footnotes-in-org-mode.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, so I had to. Further, a lot of the names were so similar as to be confusing.
&lt;/p&gt;

&lt;p&gt;
I didn&#39;t override &lt;code&gt;org-html-footnote-section&lt;/code&gt;, but others have.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;org-html-footnotes-section&lt;/code&gt; is format string of html that declares an header (by default an &amp;lt;h2&amp;gt;), and prominently displays a visible &lt;code&gt;&quot;Footnotes&quot;&lt;/code&gt; on default settings.

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;By default it is set to:
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot;&gt;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;div&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;id&lt;/span&gt;=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;footnotes&quot;&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;h2&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;class&lt;/span&gt;=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;footnotes&quot;&lt;/span&gt;&amp;gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold; text-decoration: underline;&quot;&gt;%s:&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold; text-decoration: underline;&quot;&gt;
    &lt;/span&gt;&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;h2&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;div&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;id&lt;/span&gt;=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;text-footnotes&quot;&lt;/span&gt;&amp;gt;
        &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;%s&lt;/span&gt;
    &amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;div&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;div&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;org-footnote-section&lt;/code&gt;, a string (mine is the string &lt;code&gt;&quot;Footnotes&quot;&lt;/code&gt;​), will substitute for the first &lt;code&gt;%s&lt;/code&gt;, in the format string &lt;code&gt;org-html-footnotes-section&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;The second &lt;code&gt;%s&lt;/code&gt; will be individual footnote items.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;org-html-footnote-section&lt;/code&gt;, a function, is what controls the html structure that wraps around each footnote definition.

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;it is responsible for the hardcoded &lt;code&gt;footnum&lt;/code&gt;, &lt;code&gt;footdef&lt;/code&gt;, and &lt;code&gt;footpara&lt;/code&gt; css classes, and the placement of &lt;code&gt;div&lt;/code&gt;​s and &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;​s. There is no built in facility to change the structure:

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org46d26f1&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;contents &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-trim &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-export-data def info&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #88090B;&quot;&gt;)&lt;/span&gt;
               &lt;span style=&quot;color: #88090B;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;div class=&#92;&quot;footdef&#92;&quot;&amp;gt;%s %s&amp;lt;/div&amp;gt;&#92;n&quot;&lt;/span&gt;
                       &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plist-get info &lt;span style=&quot;color: #81A1C1;&quot;&gt;:html-footnote-format&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; anchor&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                       &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;div class=&#92;&quot;footpara&#92;&quot; role=&#92;&quot;doc-footnote&#92;&quot;&amp;gt;%s&amp;lt;/div&amp;gt;&quot;&lt;/span&gt;
                               &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;not inline?&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; contents
                                 &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;p class=&#92;&quot;footpara&#92;&quot;&amp;gt;%s&amp;lt;/p&amp;gt;&quot;&lt;/span&gt;
                                         contents&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #88090B;&quot;&gt;)))))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;org-export-collect-footnote-definitions&lt;/code&gt;, a function, collects footnote definitions from the rest of the org doc. It is only called by exporters in the mainline codebase, like by &lt;code&gt;org-html-footnote-section&lt;/code&gt;. You shouldn&#39;t need to touch this unless you&#39;re doing something fancy, or want to put footnotes in custom places.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;org-html-footnote-format&lt;/code&gt;, a string, is by default &lt;code&gt;&quot;&amp;lt;sup&amp;gt;%s&amp;lt;/sup&amp;gt;&quot;&lt;/code&gt;, this is the html used for listing your wrapping the numbered anchor tags in the footnote section.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;org-html-footnote-separator&lt;/code&gt;, a string, is what separates your footnotes in the main body of your text. Mine just puts a &quot;,&quot;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;
From the image at the top of the post, I have
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;#text-Footnotes.footdef&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
then &lt;code&gt;sup&lt;/code&gt; and &lt;code&gt;.footpara&lt;/code&gt; appear for every footnote.
&lt;/p&gt;


&lt;p&gt;
The CSS, I modified from &lt;a href=&quot;https://redlib.catsarch.com/r/orgmode/comments/9jcs0j/html_export_better_looking_footnotes/&quot;&gt;this post&lt;/a&gt;. The key issue was that my posts have a footer, and thus I needed the well-known CSS clearfix hack.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-css&quot;&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;div.footdef::after&lt;/span&gt; {
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;content&lt;/span&gt;: &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&quot;&lt;/span&gt;;
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;clear&lt;/span&gt;: both;
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;display&lt;/span&gt;: table;
}

&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;.footpara&lt;/span&gt; {
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;width&lt;/span&gt;: 99%;
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;text-align&lt;/span&gt;: left;
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;float&lt;/span&gt;: right;
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;padding&lt;/span&gt;: 0;
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;margin&lt;/span&gt;: 0;
}

&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;.footpara&lt;/span&gt; {
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;display&lt;/span&gt;: inline-block;
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;font-size&lt;/span&gt;: 1.1rem;
}

&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;.footdef&lt;/span&gt;  {
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;margin-bottom&lt;/span&gt;: 0.5rem; 
    &lt;span style=&quot;color: #81A1C1;&quot;&gt;line-height&lt;/span&gt;: 2em;
}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If you disable any rule in &lt;code&gt;div.footdef::after&lt;/code&gt; , you&#39;ll see what I mean:
&lt;/p&gt;

&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/you-want-to-modify-exported-footnotes-in-org-mode/need-clearfix.mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;
I was tired and confused about all the variable names when I first did this, but I&#39;ll probably reach for flexbox or CSS grid next time. There&#39;s no reason to use floats with these better options.
&lt;/p&gt;

&lt;p&gt;
Alternatively, I could have just used different transcoders for the footnotes, like &lt;a href=&quot;https://github.com/pdixon/emacs.d/blob/dc9d8dcdd37335488944e56300afb8048bd8e852/lisp/pd-html.el#L34-L63&quot;&gt;pdixon&lt;/a&gt;.
&lt;/p&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/you-want-to-modify-exported-footnotes-in-org-mode.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I just wanted to have a footnote in this post.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
&lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/org.html#Creating-Footnotes&quot;&gt;org#Creating Footnotes&lt;/a&gt; mentions how you create them, disable them, and minor notes on some display features. 
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
&lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/org.html#CSS-support&quot;&gt;org#CSS support&lt;/a&gt; mentions CSS styling. And that&#39;s about it in the manual.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
The rest was gathered through looking at help docs.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Bookmark that rg</title>
    <link href="https://17070415.xyz/blog/bookmark-that-rg.html"/>
    <updated>4024-12-25T07:12:00Z</updated>
    <id>https://17070415.xyz/blog/bookmark-that-rg.html</id>
    <content type="html">&lt;p&gt;
I like bookmarks, don&#39;t you? But something missing was an ability to save a bookmark for an &lt;code&gt;rg.el&lt;/code&gt; search&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/bookmark-that-rg.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;, &lt;/sup&gt;&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/bookmark-that-rg.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;

&lt;p&gt;
Here is my solution after digging into the rg lib:
&lt;/p&gt;
&lt;div id=&quot;outline-container-Code&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Code&quot;&gt;Code&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Code&quot;&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;Define a function to serialize the bookmark&lt;br /&gt;To find your way back, you&#39;ll need to record information. Bookmarks will jam all your data into a big list.

&lt;p&gt;
What data to record? Here, I had to search for local variables that mached &lt;code&gt;^rg-&lt;/code&gt; . Check out using &lt;code&gt;(buffer-local-variables)&lt;/code&gt; (originally I did this the slow way of using &lt;code&gt;C-h v&lt;/code&gt;). Then I realized it was a struct, and traced through the code to find out what function to be called (&lt;code&gt;rg-run&lt;/code&gt;) and record data to pass into to it:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orga201e30&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;rg-bookmark-make-record&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Make a bookmark record for the current rg buffer.&quot;&lt;/span&gt;
  `&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;,&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;rg: &#92;&quot;%s&#92;&quot; &amp;#8715; %s &amp;#8704; %s&quot;&lt;/span&gt;
             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-pattern rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-dir rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-files rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;pattern is a synonym of query in rg.el
&lt;/span&gt;    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;pattern . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-pattern rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;files . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-files rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;dir . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-dir rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;literal . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-literal rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Found some state in the source code; 
&lt;/span&gt;    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I don&#39;t think these are needed, but they are present 
&lt;/span&gt;    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(search-cfg ,(rg-set-search-defaults (cdr body)))
&lt;/span&gt;    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(local-bindings (rg-search-parse-local-bindings search-cfg))
&lt;/span&gt;    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(iargs (rg-search-parse-interactive-args search-cfg))
&lt;/span&gt;    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;flags . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-flags rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;handler . rg-bookmark-handler&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;

&lt;li&gt;Now we need a way to read that stored data and jump to the bookmark
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org67c9ac9&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;rg-bookmark-handler&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;record&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Jump to a bookmark&#39;s url with bookmarked location.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;query &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;pattern&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;files &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;files&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;dir &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;dir&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;literal &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;literal&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;flags &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;flags&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;rg-run query files dir literal nil flags&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
We could shorten this code since there&#39;s so much repitition, but let&#39;s keep the simplicity for now.
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;And finally, bookmark-make-record-function must be overridden in the buffer-local vars for the mode:

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org96caf98&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;rg-set-bookmark-handler&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Assigns `&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;bookmark-make-record-function&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#39; to a custom function.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;set &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;make-local-variable &#39;bookmark-make-record-function&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       #&#39;rg-bookmark-make-record&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-hook &#39;rg-mode-hook #&#39;rg-set-bookmark-handler&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Test&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Test&quot;&gt;Test&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Test&quot;&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;I activate a rg search for the regexp &lt;code&gt;version: draft&lt;/code&gt; and tweak a flag.&lt;/li&gt;
&lt;li&gt;I &lt;code&gt;M-x bookmark-set&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The prompt shows 
&lt;pre class=&quot;example&quot; id=&quot;orgb2980c2&quot;&gt;
Set bookmark named (default rg: &quot;version: draft&quot; ∋ /home/refurb/src/my-site/ ∀ org):
&lt;/pre&gt;
&lt;p&gt;
I press &lt;code&gt;&amp;lt;Enter&amp;gt;&lt;/code&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;I inspected the saved bookmark:
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;rg: &#92;&quot;version: draft&#92;&quot; &amp;#8715; /home/refurb/src/my-site/src/content/ &amp;#8704; org&quot;&lt;/span&gt;
 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;pattern . &lt;span style=&quot;color: #677691;&quot;&gt;&quot;version: draft&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;files . &lt;span style=&quot;color: #677691;&quot;&gt;&quot;org&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;dir . &lt;span style=&quot;color: #677691;&quot;&gt;&quot;/home/refurb/src/my-site/src/content/&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;literal&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;flags&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;handler . rg-bookmark-handler&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Close the ripgrep buffer.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;M-x bookmark-jump&lt;/code&gt;, I can jump and see the ripgrep search I just saved, the buffer loads up, I see my results!&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Conclusion&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Conclusion&quot;&gt;
&lt;p&gt;
Now you&#39;ve got another person (me) telling you how great bookmarks are in emacs. Give it a shot and start making your own bookmark types!
&lt;/p&gt;

&lt;p&gt;
I did not cover making a &quot;category&quot; of bookmarks. &lt;a href=&quot;https://emacs.stackexchange.com/questions/74445/how-to-create-new-bookmark-type-for-use-with-bookmark&quot;&gt;Drew covers it here&lt;/a&gt; on emacs.stackexchange.
&lt;/p&gt;

&lt;p&gt;
The search hits were sparse when I looked for what this use case of bookmarks. Maybe I&#39;m alone out here.
&lt;/p&gt;

&lt;p&gt;
If this post looks similar to one by overvale, it&#39;s because I read one of their articles: &lt;a href=&quot;https://www.overvale.com/emacs/extending-emacs-bookmarks.html&quot;&gt;https://www.overvale.com/emacs/extending-emacs-bookmarks.html&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Merry Christmas!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Full%20code&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Full%20code&quot;&gt;Full code&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Full%20code&quot;&gt;
&lt;p&gt;
Maybe I should package this up?
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;rg-bookmark-make-record&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Make a bookmark record for the current rg buffer.&quot;&lt;/span&gt;
  `&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;,&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;rg: &#92;&quot;%s&#92;&quot; &amp;#8715; %s &amp;#8704; %s&quot;&lt;/span&gt;
             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-pattern rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-dir rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-files rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;pattern is a synonym of query in rg.el
&lt;/span&gt;    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;pattern . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-pattern rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;files . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-files rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;dir . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-dir rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;literal . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-literal rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Found some state in the source code; 
&lt;/span&gt;    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I don&#39;t think these are needed, but they are present 
&lt;/span&gt;    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(search-cfg ,(rg-set-search-defaults (cdr body)))
&lt;/span&gt;    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(local-bindings (rg-search-parse-local-bindings search-cfg))
&lt;/span&gt;    &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(iargs (rg-search-parse-interactive-args search-cfg))
&lt;/span&gt;    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;flags . ,&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;rg-search-flags rg-cur-search&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;handler . rg-bookmark-handler&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;rg-bookmark-handler&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;record&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Jump to a bookmark&#39;s url with bookmarked location.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;query &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;pattern&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;files &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;files&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;dir &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;dir&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;literal &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;literal&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;flags &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;bookmark-prop-get record &#39;flags&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;rg-run query files dir literal nil flags&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;rg-set-bookmark-handler&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Assigns `&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;bookmark-make-record-function&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#39; to a custom function.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;set &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;make-local-variable &#39;bookmark-make-record-function&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
       #&#39;rg-bookmark-make-record&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-hook &#39;rg-mode-hook #&#39;rg-set-bookmark-handler&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/bookmark-that-rg.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
In my opinion, &lt;code&gt;rg.el&lt;/code&gt; doesn&#39;t have good support for &lt;a href=&quot;https://rgel.readthedocs.io/en/latest/configuration.html#function-rg-define-search&quot;&gt;persisting saved searches&lt;/a&gt; (nor should that be its focus).
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/bookmark-that-rg.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Update 2024-12-28, &lt;a href=&quot;https://github.com/alphapapa/burly.el&quot;&gt;burly.el&lt;/a&gt; can bookmark rg, but I&#39;ve found it doesn&#39;t restore window configuration properly with rg buffers.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>4024-12 In Review</title>
    <link href="https://17070415.xyz/blog/4024-12-in-review.html"/>
    <updated>4024-12-23T21:37:00Z</updated>
    <id>https://17070415.xyz/blog/4024-12-in-review.html</id>
    <content type="html">&lt;div id=&quot;outline-container-My%20meaningful%20achievements%20this%20month%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;My%20meaningful%20achievements%20this%20month%3A&quot;&gt;My meaningful achievements this month:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-My%20meaningful%20achievements%20this%20month%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;I completed 16 blog articles.&lt;/b&gt; Which is 4 months worth of blog posts. More are on the way, because I actually worked on 21 blog posts.&lt;/li&gt;
&lt;li&gt;Solved technical problems for this blog, people can now experience audio, video, pictures.&lt;/li&gt;
&lt;li&gt;Wrote a letter of recommendation for a student.&lt;/li&gt;
&lt;li&gt;Decided to not be on nixOS&amp;#x2013;it&#39;s wonderful to be back on manjaro for developing.&lt;/li&gt;
&lt;li&gt;Did 1 unit of Duolingo per day. The time it takes is around 2-2.5h/day now. Noise disrupts me greatly.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Edit: I got knocked out of diamond league; I prioritized writing blog posts the last week of the year.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Daily leetcode. Got my 2024 annual badge.&lt;/li&gt;
&lt;li&gt;Volunteered at a blood donation place, and it&#39;s also good I realized that particular place did not need me.&lt;/li&gt;
&lt;li&gt;Began volunteering at nonprofits. Technically accepted a position at 2 of them so far. Another is interested.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I have been so busy with debugging things that I haven&#39;t given them too much time however.&lt;/li&gt;
&lt;li&gt;My first PR at a nonprofit got merged, second one on the way.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Coding related
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;linux
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Got a better understanding of how linux permissions work.&lt;/li&gt;
&lt;li&gt;Played with dbus more.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;org
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Learned how to use the org-mode AST, wrote a short function to call codeblocks.&lt;/li&gt;
&lt;li&gt;It&#39;s so silly, but &lt;code&gt;#+begin_export html&lt;/code&gt; was not something I realized was a thing. But now I&#39;ve simplified one of my pages quite a bit. The mixture of &lt;code&gt;org&lt;/code&gt;, &lt;code&gt;nunjucks&lt;/code&gt;, and &lt;code&gt;11ty&lt;/code&gt; feels more manageable this way.&lt;/li&gt;
&lt;li&gt;Learned the org export process deep enough to feel like I can wield it like a baseball bat in a china shop, then reverse time, and finely stich the structure of destroyed china back in place, with my mind.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Well, I&#39;m not that good yet.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Shipped &lt;a href=&quot;https://codeberg.org/MegaJ/request-pad.org&quot;&gt;my template&lt;/a&gt; for debugging web service requests. Helped me review noweb.&lt;/li&gt;
&lt;li&gt;I learned a lot about org. I mean, just check out this month&#39;s blog posts!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;php
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Finished &quot;PHP In Easy Steps&quot; (Maybe I did this last month?)&lt;/li&gt;
&lt;li&gt;Finished &quot;Wordpress for Dummies 9th edition&quot; and got a handle on wordpress. I understand how to manipulate old themes at least&lt;/li&gt;
&lt;li&gt;Wrote a php package &lt;a href=&quot;https://codeberg.org/MegaJ/php-binary-index-tree&quot;&gt;php-binary-index-tree&lt;/a&gt;, and it&#39;s on &lt;a href=&quot;https://packagist.org/packages/megaj/binary-index-tree&quot;&gt;packagist&lt;/a&gt;.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;This was very painful coming from a position where I didn&#39;t know php, but I learned the most from it&lt;/li&gt;
&lt;li&gt;PHP unit is also bizarre coming from BDD frameworks where tests are organized into suites and can be nested.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Tried out &lt;a href=&quot;https://github.com/svaante/dape/issues&quot;&gt;dape&lt;/a&gt;, even put up an issue I was facing.&lt;/li&gt;
&lt;li&gt;Set up a php dev environment for myself, to be ready to volunteer doing wordpress + php based frameworks.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I hooked up eglot, php-ts-mode, php-mode, web-mode, phpactor, dape, company, and xdebug.&lt;/li&gt;
&lt;li&gt;I also managed to fix some issues on my own about packages bringing in conflicting dependencies (this also involved me upgrading to an edge build of emacs)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;more emacs
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Built a working prototype of an &lt;a href=&quot;https://codeberg.org/MegaJ/leetcode-archive&quot;&gt;elisp webapp&lt;/a&gt; (hope to finish next month). It uses &lt;code&gt;elnode&lt;/code&gt;, which is now 10+ years old. I don&#39;t know if I want to do this over the top and add an unecessarily complex storage layer. It would be fun to practice using the emacs pg library, but completely uneccessary.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Finally learned &lt;code&gt;sxml&lt;/code&gt; from &lt;a href=&quot;https://github.com/tali713/esxml&quot;&gt;esxml&lt;/a&gt;, and it is actually really nice to have html as s-expressions.&lt;/li&gt;
&lt;li&gt;Couldn&#39;t find out from searching online how to add literal html (it kept escaping). But there is a way: &lt;code&gt;*RAW-STRING*&lt;/code&gt;. I only found the &lt;a href=&quot;https://github.com/tali713/esxml/issues/34&quot;&gt;github issue&lt;/a&gt; after debugging into the source code.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;How does daviwil not use a &lt;code&gt;raw-string&lt;/code&gt; right now in his source for systemcrafters?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Got used to/aware of &lt;code&gt;rg.el&lt;/code&gt;&#39;s more advanced capabilities (the transient, setting custom searches, history).&lt;/li&gt;
&lt;li&gt;Debugged a ton of elisp, fixed some of my own issues with transients surprisingly.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Every time I debug a tool, I feel more confident about using it.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Prototyped a way fill emacs with the system clipboard using dbus. It works enough, but it&#39;d be nice if I packaged it.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It has issues and I want it to translate image clipboard data well.&lt;/li&gt;
&lt;li&gt;It relies on &lt;code&gt;clipnotify&lt;/code&gt;. Which is X only. But I run X on Wayland. Still not sure how this window environment stuff works.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Read more about state charts, which have a charm to them. Started thinking about implementing a State Charts library in elisp. I want my cursor to be in different colors depending on different mode states, and this is too complicated to deal with without state management.&lt;/li&gt;
&lt;li&gt;Have export on save as a &lt;code&gt;.dir-local&lt;/code&gt; has saved a bunch of time writing articles.&lt;/li&gt;
&lt;li&gt;Creating a custom hydra to do various blog actions, like renaming files, starting a local server, quick making a new post, etc..&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Keybindings
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Retooled some keybindings; discovered the joy of &lt;code&gt;project.el&lt;/code&gt; and how &lt;code&gt;project-switch-project&lt;/code&gt; can save me time, as well as &lt;code&gt;helm-projectile-find-file&lt;/code&gt; (I use a mix of helm and simple completing-read).
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I usually have a mass of unrelated files with similar file names that makes completing more difficult.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Meaningful%20losses%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Meaningful%20losses%3A&quot;&gt;Meaningful losses:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Meaningful%20losses%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Not eating enough. Not getting up early enough to buy eggs on discount.&lt;/li&gt;
&lt;li&gt;Got sick. Heart pain.&lt;/li&gt;
&lt;li&gt;Loss of sleep due to noise, sickness, and even excitement.&lt;/li&gt;
&lt;li&gt;Spending less time with people than I maybe should.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-What%20I%27m%20grateful%20for%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;What%20I%27m%20grateful%20for%3A&quot;&gt;What I&#39;m grateful for:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-What%20I%27m%20grateful%20for%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;My friend letting me stay with him&lt;/li&gt;
&lt;li&gt;eggs&lt;/li&gt;
&lt;li&gt;Leftovers (there were a lot).&lt;/li&gt;
&lt;li&gt;Local public library&lt;/li&gt;
&lt;li&gt;I actually had a Thanksgiving, and the food was really good.&lt;/li&gt;
&lt;li&gt;I&#39;m writing; I don&#39;t know why I&#39;m so motivated. Maybe because it&#39;s about emacs, workflow, productivity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Looking%20ahead%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Looking%20ahead%3A&quot;&gt;Looking ahead:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Looking%20ahead%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;More unemployment / lack of housing&lt;/li&gt;
&lt;li&gt;Rising price of eggs&lt;/li&gt;
&lt;li&gt;Increased health risks due to not seeing a doctor&lt;/li&gt;
&lt;li&gt;An increased focus on trying to build engineering cultures across dimensions.&lt;/li&gt;
&lt;li&gt;Not sure if I&#39;ll replace 11ty, I like the flexibility it gives me with tags/index pages, but I also want org file cross linking to translate properly.&lt;/li&gt;
&lt;li&gt;I have a ton of hobby projects to release as hinted above. I want to look back, and see that I followed through.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>How You Do Project Euler in Emacs Lisp</title>
    <link href="https://17070415.xyz/blog/how-you-do-project-euler-in-emacs-lisp.html"/>
    <updated>4024-12-21T05:41:00Z</updated>
    <id>https://17070415.xyz/blog/how-you-do-project-euler-in-emacs-lisp.html</id>
    <content type="html">&lt;p&gt;
Upon the late summer of 2023, I finished problems I&#39;d missed from project euler 1-100 in emacs lisp&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/how-you-do-project-euler-in-emacs-lisp.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; just before my life fell apart. I knew I&#39;d be ok though, seeing as I would live 2000+ years into the future to write this blog post.
&lt;/p&gt;

&lt;p&gt;
The two things I kept using repeatedly were
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;&lt;code&gt;edebug&lt;/code&gt;: step through capabilities! &lt;br /&gt;&lt;a href=&quot;https://endlessparentheses.com/debugging-emacs-lisp-part-1-earn-your-independence.html&quot;&gt;This tutorial&lt;/a&gt; by endlessparenthesis was helpful. 

&lt;p&gt;
And &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/eintr.html#edebug&quot;&gt;the manual&lt;/a&gt; is seriously worth reading.
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cl-loop&lt;/code&gt;: for the most expressive looping I&#39;ve ever experienced in my life&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/how-you-do-project-euler-in-emacs-lisp.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
I didn&#39;t find anyone else who published their emacs lisp solutions up to 100. But there were of course lispers who had done far more. I was definitely inspired by a few others before I started:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;someone else had a collection of a few dozen of their solutions posted as a giant file of HTML on their blog. (They were from Mexico? I don&#39;t remember)&lt;/li&gt;
&lt;/ul&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;skeeto&#39;s commmon lisp solutions, and a lot were just loop macros. He might have even remarked about this on his blog.&lt;/li&gt;
&lt;li&gt;I also watched an emacs youtuber, who did common lisp, talk about how they loved the loop macro so much.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Anyway, &lt;code&gt;cl-loop&lt;/code&gt; is a super power. You can read about it in the &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/cl.html#Loop-Facility&quot;&gt;cl-lib info manual&lt;/a&gt;. Once you get used to the DSL, you can rip through a lot of earlier problems! It&#39;s really performant for elisp.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s just a function to generate a hash table from an input list:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org7cdc3bb&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/list-to-hash-table&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;input-list&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;cl-loop&lt;/span&gt; for &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;k v&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; in input-list
                                         with ht = &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;make-hash-table &lt;span style=&quot;color: #81A1C1;&quot;&gt;:test&lt;/span&gt; #&#39;equal&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                                         do &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;puthash k v ht&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                                         finally return ht&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
I find this more expressive and faster to grasp than using a mapping function with a lambda:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;yaml--alist-to-hash-table&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;l&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;ommitted...
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;h &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;make-hash-table&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;seq-map &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;cpair&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
               &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;k &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;car cpair&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                      &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;v &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;alist-get k l&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;puthash k v h&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
             l&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    h&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/how-you-do-project-euler-in-emacs-lisp.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
The notebook is too messy to be of easy value &lt;a href=&quot;https://codeberg.org/MegaJ/euler-elisp&quot;&gt;https://codeberg.org/MegaJ/euler-elisp&lt;/a&gt;. It&#39;s also not very readble unless you&#39;re opening up my notebook in org mode. Still, I consider it a major achievement! Might brush it up to make it more comprehensible some day.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/how-you-do-project-euler-in-emacs-lisp.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I wonder if this article is just an ad for &lt;code&gt;cl-loop&lt;/code&gt;, it&#39;s just so good! Maybe this should be a short series where I actually show some solutions to project euler.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Org Babel Evaluation From Afar</title>
    <link href="https://17070415.xyz/blog/org-babel-evaluation-from-afar.html"/>
    <updated>4024-12-21T04:54:00Z</updated>
    <id>https://17070415.xyz/blog/org-babel-evaluation-from-afar.html</id>
    <content type="html">&lt;p&gt;
I often write many &lt;code&gt;src-block&lt;/code&gt;​s; I prototype a lot of things. And I love seeing what my code spits out &lt;i&gt;a lot&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;tl;dr: I built an auto-completion to evaluate source blocks in an org buffer.&lt;/b&gt;
&lt;/p&gt;


&lt;figure id=&quot;org5b2b6d0&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/org-babel-evaluation-from-afar/output-2025-01-08-16:58:03.gif&quot; alt=&quot;output-2025-01-08-16:58:03.gif&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 1: &lt;/span&gt;animation of executing a block when point is not on block&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
In an hour&#39;s time of prototyping I can&#39;t avoid having a bunch of blocks in a big, structured mess. In fact, this blog post was originally just a sandbox for trying to build a &lt;code&gt;completing-read&lt;/code&gt; interface to evalaute &lt;code&gt;src-block&lt;/code&gt;​s.
&lt;/p&gt;

&lt;p&gt;
What I&#39;ve done up till now when I&#39;m somewhere in the buffer is
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;isearch for the block, be it the code in the body of the &lt;code&gt;#+begin_src&lt;/code&gt; or the name of the block if I&#39;ve done that&lt;/li&gt;
&lt;li&gt;go through isearch candidates until I find the one&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-c C-c&lt;/code&gt; to evaluate the block&lt;/li&gt;
&lt;li&gt;then pop mark until I&#39;m back to where I was&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
And it&#39;s &lt;b&gt;too slow!&lt;/b&gt; I never felt like I was able enough to find more flow in this, but then
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I was reading around to try and change &lt;code&gt;ox-html&lt;/code&gt;&#39;s rendering for my plain-list&lt;/li&gt;
&lt;li&gt;found &lt;a href=&quot;http://xahlee.info/emacs/emacs/elisp_parse_org_mode.html&quot;&gt;Xah Lee&#39;s small tutorial&lt;/a&gt; (more of a showcase really) on org&#39;s element API,&lt;/li&gt;
&lt;li&gt;and today I bounced over to &lt;a href=&quot;https://orgmode.org/worg/dev/org-element-api.html&quot;&gt;Org&#39;s official docs for Org Element API&lt;/a&gt;,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
and I just realized&amp;#x2026;yeah I can fix that.
&lt;/p&gt;

&lt;p&gt;
I&#39;ve just gotten gradually much better at elisp over time than when I started, maybe around 2015.
&lt;/p&gt;

&lt;p&gt;
So here&#39;s what we&#39;ll do:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Ask org to give us an AST&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/org-babel-evaluation-from-afar.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;,&lt;/li&gt;
&lt;li&gt;use AST helper methods to grab source blocks and their data&lt;/li&gt;
&lt;li&gt;build candidates from relevant nodes of the tree&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;completing-read&lt;/code&gt;, the minibuffer completion mechanism, to let to user select which code block to run&lt;/li&gt;
&lt;li&gt;finally, execute the block&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
and we didn&#39;t need to move our cursor!
&lt;/p&gt;

&lt;div class=&quot;note&quot; id=&quot;org3995fb9&quot;&gt;
&lt;p&gt;
I debated whether to write this blog post to show you how to debug and figure this out on your own, but it didn&#39;t come out that way this time. That&#39;s one thing I think is lacking&amp;#x2013;those lispers don&#39;t show their process!
&lt;/p&gt;

&lt;/div&gt;
&lt;div id=&quot;outline-container-Inspiration&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Inspiration&quot;&gt;Inspiration&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Inspiration&quot;&gt;
&lt;p&gt;
This is the piece of code that inspired me from &lt;a href=&quot;https://orgmode.org/worg/dev/org-element-api.html&quot;&gt;worg&lt;/a&gt;. Maybe it&#39;ll inspire you in how easy it is to work with org&#39;s abstract syntax tree:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgd5d285a&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-map &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-element-parse-buffer&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &#39;item
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;item&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;eq &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:checkbox&lt;/span&gt; item&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt; &#39;on&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  nil t&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
(Don&#39;t forget to read the docs on those arguments!)&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/org-babel-evaluation-from-afar.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Code&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Code&quot;&gt;Code&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Code&quot;&gt;
&lt;p&gt;
Anyway, here are the goodies.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-An%20example%20block&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;An%20example%20block&quot;&gt;An example block&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-An%20example%20block&quot;&gt;
&lt;p&gt;
First I need a &lt;code&gt;src-block&lt;/code&gt; in this org document that I&#39;ll call for this tutorial:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org2334333&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;message &lt;span style=&quot;color: #677691;&quot;&gt;&quot;running my block&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;%s&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;I&#39;m currently looking for work&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-The%20function%20called%20by%20~org-element-map~&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;The%20function%20called%20by%20~org-element-map~&quot;&gt;The function called by &lt;code&gt;org-element-map&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-The%20function%20called%20by%20~org-element-map~&quot;&gt;
&lt;p&gt;
I create a list of two-element lists. The first element is for display, the second element is for the point position.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orge47c6d0&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/transform-src-block-candidates&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;item&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;name &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:name&lt;/span&gt; item&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;begin &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-property &lt;span style=&quot;color: #81A1C1;&quot;&gt;:begin&lt;/span&gt; item&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;data `&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;,&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;%s:L%s&quot;&lt;/span&gt; name &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;line-number-at-pos begin&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; ,begin&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    data&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Why do I want the point position? Because I plan to call &lt;code&gt;org-babel-execute-src-block&lt;/code&gt;&lt;sup&gt;&lt;a id=&quot;fnr.3&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/org-babel-evaluation-from-afar.html#fn.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. Next let&#39;s see the results from using &lt;code&gt;org-element-map&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Using%20org-element-map&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Using%20org-element-map&quot;&gt;Using org-element-map&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Using%20org-element-map&quot;&gt;
&lt;p&gt;
There are multiple types of source blocks; I don&#39;t use the inline ones at all, but I included them:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orge4f9278&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-map &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-element-parse-buffer&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;src-block inline-src-block&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  #&#39;jwow/transform-src-block-candidates&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgbe2c426&quot;&gt;
| inspiration from org element api:L46          | 2316 |
| the block I&#39;ll call:L60                       | 2709 |
| jwow/get-src-block-candidates:L72             | 3069 |
| org-element-map example:L93                   | 3991 |
| completing read example:L117                  | 4838 |
| finished code, find-src-blocks-in-buffer:L129 | 5180 |
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Autocompleting%20candidates&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Autocompleting%20candidates&quot;&gt;Autocompleting candidates&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Autocompleting%20candidates&quot;&gt;
&lt;p&gt;
I began prototyping this separately. Now I needed to show candidates that the lambda returned. 
&lt;/p&gt;

&lt;p&gt;
Prototyping completing read is super easy:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgbf15827&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Completed for this: %s&quot;&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;completing-read &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Execute block: &quot;&lt;/span&gt; &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;foo boo roo&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Yields:
&lt;/p&gt;

&lt;figure id=&quot;orgd0f7442&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/org-babel-evaluation-from-afar/2025-01-08_15-57-57_screenshot.png&quot; alt=&quot;2025-01-08_15-57-57_screenshot.png&quot; /&gt;

&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Org%20Src%20Run&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Org%20Src%20Run&quot;&gt;Org Src Run&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Org%20Src%20Run&quot;&gt;
&lt;p&gt;
Try running this in one of your org buffers and try to run a piece of code.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org0b6646e&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/org-src-run&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
      &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;found-src-blocks  &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-map
                                &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-element-parse-buffer&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                                &#39;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;src-block inline-src-block&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                              #&#39;jwow/transform-src-block-candidates&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;chosen-block &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;completing-read
                        &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Execute block: &quot;&lt;/span&gt;
                        found-src-blocks&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;block-start &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;cadr &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;assoc chosen-block found-src-blocks&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;save-excursion&lt;/span&gt; 
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;goto-char block-start&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-babel-execute-src-block nil
                                   &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-babel-get-src-block-info&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Takes about a second to get completing read loadaed for a 7k line org file on my box.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-More%20efficiently%3F&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;More%20efficiently%3F&quot;&gt;More efficiently?&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-More%20efficiently%3F&quot;&gt;
&lt;p&gt;
Of course I thought of making the code faster.
&lt;/p&gt;

&lt;p&gt;
One thing that could be improved is avoid using &lt;code&gt;assoc&lt;/code&gt;, which is a linear walk through a linked list. For repeat calls, we might be able to use a hash table mapping src-block names to point positions.
&lt;/p&gt;

&lt;p&gt;
But that creates the issue of stale cache (the block position in the buffer changes as you type). We could save the AST for the block, to call functions on it&amp;#x2013;but then the code might change too.
&lt;/p&gt;

&lt;p&gt;
This introduces way more complexity. And it&#39;s good enough for now.
&lt;/p&gt;

&lt;p&gt;
I&#39;ve learned I should spend more time communicating vs less time tweaking code.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/org-babel-evaluation-from-afar.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I avoid using regexp; asking org to parse is slower, but more accurate. Parsing is much better if your use case covers other elements than just src-blocks.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/org-babel-evaluation-from-afar.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I didn&#39;t read what the last argument (here it&#39;s &lt;code&gt;t&lt;/code&gt;) did, so I kept wondering why it was exiting only after listing one element. Once I removed it, I saw my lamda fire for each matching element. 
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.3&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/org-babel-evaluation-from-afar.html#fnr.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Found by looking through &lt;code&gt;C-h k&lt;/code&gt; &lt;code&gt;C-c C-c&lt;/code&gt; to find &lt;code&gt;org-ctrl-c-ctrl-c&lt;/code&gt; jump to source, find out some functions there, then jump to some more.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Embedding audio/video in org html export</title>
    <link href="https://17070415.xyz/blog/embedding-audio-in-org-html-export.html"/>
    <updated>4024-12-19T22:28:00Z</updated>
    <id>https://17070415.xyz/blog/embedding-audio-in-org-html-export.html</id>
    <content type="html">&lt;p&gt;
Embed whatever you want through org mode export.
&lt;/p&gt;

&lt;p&gt;
Despite the title, the strategies presented work to any export format, not just html. I use the lens of exporting some media in org mode to highlight some of org&#39;s features and some nifty integrations you should consider!
&lt;/p&gt;

&lt;p&gt;
Let&#39;s talk about &lt;b&gt;building speed in an org workflow for inserting some markup for media assets&lt;/b&gt;.
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;
You&#39;re one of those or audio/visual/writing people&lt;sup&gt;&lt;a id=&quot;fnr.or-anyone-else&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fn.or-anyone-else&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. You make content. And you use emacs. And you&#39;ve heard about org mode, and you heard about generating static html files. Maybe you even make a static site using org mode like this one. All is well. You are in the right place.
&lt;/p&gt;

&lt;p&gt;
You go along and discover some pretty things, some convenient things, and they taste exquisite. You start wondering about gathering more strength, more velocity, more followers, more brand deals, more estates, more politicians, more armies, more nukes, more moon colonies&amp;#x2026;.
&lt;/p&gt;

&lt;p&gt;
But first you want to embed &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; in html. Or &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; for that matter. Or some custom tag. Ultimately you need it in html in some way or form. Well, you&#39;ve got options:
&lt;/p&gt;
&lt;div id=&quot;outline-container-Methods&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Methods&quot;&gt;Methods&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Methods&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;use an &lt;code&gt;#+EXPORT_HTML&lt;/code&gt; block.&lt;br /&gt;You write your html inside it, you export.

&lt;p&gt;
This option works. It&#39;s a bit verbose to use each time. Even with the shorthand
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;@@​html: my custom &amp;lt;audio&amp;gt;&amp;lt;audio/&amp;gt; @@&lt;/code&gt;, 
&lt;/p&gt;

&lt;p&gt;
this is a drag. Even if you make some autocomplete for the dang thing. Really the only thing that changes is the audio file usually.
&lt;/p&gt;

&lt;p&gt;
And if that&#39;s so&amp;#x2026;
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;use a macro that expands to content of an &lt;code&gt;#+export_html&lt;/code&gt; block.&lt;br /&gt;It&#39;s reusable, it encapsulates what changes&amp;#x2013;probably the url or filename you use to serve the audio. You set it up once, and you have clean looking org documents. Begone, clutter!

&lt;p&gt;
But you may not like the syntax of calling an inline macro: 

&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;A podcast about deep sea exploration puns: {{{ my_macro(&quot;../audio/my-podcast.mp3&quot; }}}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;

And what&#39;s more, you have to make sure that macro is defined in every org doc you write so that you can use it. That&#39;s kind of a pain if you use the &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/org.html#Include-Files&quot;&gt;#+includes feature&lt;/a&gt; for this.
&lt;/p&gt;

&lt;p&gt;
But is there an easy mechanism making macros available without having to write extra markup in your document each time?
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;Global macros

&lt;p&gt;
Ha! Of course there is: &lt;code&gt;org-export-global-macros&lt;/code&gt;. I didn&#39;t go for this but it would work for me, and probably you. There aren&#39;t many downsides but you might want them on a per-project basis to make sure they don&#39;t clash. You can have a buffer local variable to set this for every org buffer of your project.
&lt;/p&gt;

&lt;p&gt;
Macros are certainly flexible, reusable, and great! 
&lt;/p&gt;

&lt;p&gt;
But I didn&#39;t go that route. I used something more specific&amp;#x2026;something that hooks up to some other nice emacs mechanisms that we&#39;ll talk about&amp;#x2026;
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;Drag and drop your file

&lt;p&gt;
Drop a file into an org buffer and boom, the link us automatically in your org markup.
&lt;/p&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/embedding-audio-in-org-html-export/Screencast%20From%202025-01-01%2006-24-32.mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;
You can even customize drag and drop capability, which we don&#39;t explore right now&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, and generate custom markup upon dropping.
&lt;/p&gt;

&lt;p&gt;
What you say, you don&#39;t use your mouse and you prefer mostly keyboard? Or maybe the file isn&#39;t local, and you dragging and dropping sounds like the aftermath of a hard drug to you&amp;#x2026;
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;Use a user-defined org-link, like &lt;code&gt;[[audio:../audio/my-podcast.mp3]]&lt;/code&gt;.&lt;br /&gt;&lt;a href=&quot;https://codeberg.org/SystemCrafters/systemcrafters-site/src/commit/dd3dd07/publish.el#L107-L117&quot;&gt;Systemcrafters does it that way&lt;/a&gt;.

&lt;p&gt;
Now just like any other org link, you can jump to it, specify its export behavior, and even its &lt;code&gt;org-store-link&lt;/code&gt; functionality.
&lt;/p&gt;

&lt;p&gt;
Native ones exist:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&lt;a href=&quot;file://~/Downloads/fe3h%20mural%20tapestry.jpg&quot;&gt;file://~/Downloads/fe3h mural tapestry.jpg&lt;/a&gt;&lt;/span&gt;
&lt;span style=&quot;color: #81A1C1;&quot;&gt;&lt;a href=&quot;info:Org&quot;&gt;info:Org&lt;/a&gt;&lt;/span&gt;
&lt;span style=&quot;color: #81A1C1;&quot;&gt;&lt;a href=&quot;https://17070415.xyz/blog/&quot;&gt;[this blog&lt;/a&gt;&lt;/span&gt;
&lt;span style=&quot;color: #81A1C1;&quot;&gt;&lt;a href=&quot;elisp:(message &amp;quot;What&#39;s the price of eggs today?%22)&quot;&gt;elisp:(message &quot;What&#39;s the price of eggs today?&quot;)&lt;/a&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You can click on these in org mode! Or move point over and &lt;code&gt;C-c C-o&lt;/code&gt; to open the links.
&lt;/p&gt;

&lt;p&gt;
If you want to create your own link for &lt;code&gt;[[audio:../audio/my-podcast.mp3]]&lt;/code&gt;
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;For this example we only care about format being html
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;if you were exporting to say, md, or something else,
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;you&#39;d have to handle that 
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Also omitted is adding text for a11y 
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/audio-link-export&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;path desc format&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;audio controls src=&#92;&quot;%s&#92;&quot; &amp;gt;
Your browser does not support the audio element.
&amp;lt;/audio&amp;gt;&quot;&lt;/span&gt;
          path&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-link-set-parameters &lt;span style=&quot;color: #677691;&quot;&gt;&quot;audio&quot;&lt;/span&gt;
                         &lt;span style=&quot;color: #81A1C1;&quot;&gt;:follow&lt;/span&gt; #&#39;org-link-open-as-file
                         &lt;span style=&quot;color: #81A1C1;&quot;&gt;:export&lt;/span&gt; #&#39;jwow/audio-link-export&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&lt;a href=&quot;audio:../assets/media/embedding-audio-in-org-html-export/t-rex-roar.mp3&quot;&gt;audio:../assets/media/embedding-audio-in-org-html-export/t-rex-roar.mp3&lt;/a&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
exports to this:
&lt;/p&gt;

&lt;p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://17070415.xyz/assets/media/embedding-audio-in-org-html-export/t-rex-roar.mp3&quot;&gt;
    Your browser does not support the audio element.
    &lt;/audio&gt;
&lt;/p&gt;

&lt;p&gt;
This is great but it still seems I&#39;m typing a ton of characters! All that &quot;[[&quot; and &quot;audio&quot; and the path of the file!
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;So let&#39;s autocomplete for the link, starting with the link type

&lt;div class=&quot;note&quot; id=&quot;org750aaf9&quot;&gt;
&lt;p&gt;
There&#39;s a lot of different methods you can customize for auto complete. You can use a various completion framework like completing read, helm, company, corfu, counsel, and others. Or make a quick expandable template using yasnippets. To keep this section focused, let&#39;s build on a link strategy.
&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;
How do we complete for an audio link?
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;C-c C-l&lt;/code&gt; in an org buffer:
&lt;/p&gt;
&lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://17070415.xyz/assets/media/embedding-audio-in-org-html-export/audio-link-autocomplete-720.mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;
Here&#39;s the code that makes that possible:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I have a buffer local variable that defines my dir dynamically
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I&#39;m hard coding it for this demo for transparency, and so you can change it
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defvar&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;audio-dir&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;~/src/my-site/src/assets/media/embedding-audio-in-org-html-export/&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Also my post is an org file inside ~/my-site/src/content/, which is 
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;important for building a relative file link
&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/org-audio-complete-link&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Bring up autocomplete for audio files in a specific directory.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;file &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;read-file-name &lt;span style=&quot;color: #677691;&quot;&gt;&quot;File: &quot;&lt;/span&gt; audio-dir&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;pwd-relative &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;file-relative-name file default-directory&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot;audio:&quot;&lt;/span&gt; pwd-relative&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-link-set-parameters &lt;span style=&quot;color: #677691;&quot;&gt;&quot;audio&quot;&lt;/span&gt;
                         &lt;span style=&quot;color: #81A1C1;&quot;&gt;:complete&lt;/span&gt; #&#39;jwow/org-audio-complete-link&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Sources say you can also complete for link abbreviations &lt;sup&gt;&lt;a id=&quot;fnr.3&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fn.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;, &lt;/sup&gt;&lt;sup&gt;&lt;a id=&quot;fnr.4&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fn.4&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;, though I&#39;ve had no luck with it. &lt;code&gt;complete-symbol&lt;/code&gt; is what gets called, but I have 0 results with my cursor in front of &lt;code&gt;[[&lt;/code&gt;. If I have &lt;code&gt;[[a&lt;/code&gt; typed and then complete, I have an ispell error.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;Completion for a non local resource 

&lt;p&gt;
For example, if you want to autocomplete for a youtube video by asking youtube for the video ids, you&#39;re going to hook into that corporation&#39;s custom api.
&lt;/p&gt;

&lt;p&gt;
We won&#39;t explore that here because every API is different, but it&#39;s entirely possible you want to embed someone else&#39;s content, and make your meta content commentary. Emacs is more than capable.
&lt;/p&gt;

&lt;p&gt;
Check out &lt;a href=&quot;https://github.com/atheriel/helm-twitch&quot;&gt;https://github.com/atheriel/helm-twitch&lt;/a&gt; for an example of completing for twitch streams using helm. (This was also featured in an emacs conf talk).
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;You&#39;ve succeeded

&lt;p&gt;
Months pass by, you gain quadrillions of followers. Like me, you become a guarded king secluded from his own dominion, cursed with an-all-too-outrageous-success with his interstellar, intertemporal blog.
&lt;/p&gt;

&lt;p&gt;
Then suddenly you get an email mentioning how your content has been banned/flagged/lost in the corporate dungeons of VROnlyTubelrSoundXCloudArtBookSyAIHub. It was your most liked piece of genius on the web! Oh no!
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;Renaming links

&lt;p&gt;
You reupload material for your fans. But now the corporation gives you a new video id. Now you&#39;ve got to replace &lt;i&gt;all&lt;/i&gt; those links in org mode!
&lt;/p&gt;

&lt;p&gt;
You can&#39;t bear the tedium of doing it manually. So what do you do?
&lt;/p&gt;

&lt;p&gt;
If you program enough you probably have tools you go and use for this already. Since you&#39;re on org mode though, I&#39;ll point you to
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;M-x project-query-replace-regexp&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
I&#39;d recommend tracking your project with version control then do this. You can one-shot all the replacements across all files by pressing &quot;Y&quot;.
&lt;/p&gt;

&lt;p&gt;
Boom.
&lt;/p&gt;

&lt;p&gt;
An alternate way to avoid this problem is to use your own unique IDs to resources, and have your link type map to the video id&lt;sup&gt;&lt;a id=&quot;fnr.5&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fn.5&quot; role=&quot;doc-backlink&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;

&lt;p&gt;
But for now, just replace your links using a project-wide replace function. Keep it simple until you get those brand deals.
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Let%27s%20stop%20for%20now&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Let%27s%20stop%20for%20now&quot;&gt;Let&#39;s stop for now&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Let%27s%20stop%20for%20now&quot;&gt;
&lt;p&gt;
This could go on and on. There a lot of neat workflow tricks, things you can do with RSS, CI/CD, org-publish, defining an org export mode, etc.. See other articles on this blog for more! I&#39;m sure someone has done something using the embark package that I haven&#39;t had time to test yet.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Conclusion&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Conclusion&quot;&gt;
&lt;p&gt;
Org mode provides the speed-hungry with the most drugged up concoction of stimulants to bring your emacs fueled creator journey to the next, next, next, level. 
&lt;/p&gt;

&lt;p&gt;
At any point you could have stopped. Any of those solutions work to a quick workflow of inserting a simple link would work. It just depends on what you&#39;re looking for, and how you want to design your workflow.
&lt;/p&gt;

&lt;p&gt;
I&#39;d also love to know if you have any tips of your own, or anything you&#39;d like to share. I&#39;m also at this time looking for work in software development, or just being paid to eat chips. Please get in touch at &lt;code&gt;jwow@17070415.xyz&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Lastly, though I chose the path of org links, reach for macros when needed. If you need higher degrees of parameterization (you have more varying settings; for example at times wanting to use &lt;code&gt;ogg&lt;/code&gt; format, but falling back to &lt;code&gt;mp3&lt;/code&gt;, but sometimes there&#39;s no &lt;code&gt;ogg&lt;/code&gt; or &lt;code&gt;mp3&lt;/code&gt;, you can do that in the &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; tag natively in html with more than one &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; tag. Your macro can take multiple parameters, where as in a link there isn&#39;t an obvious interface to do that).
&lt;/p&gt;

&lt;p&gt;
Thanks for reading!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.or-anyone-else&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fnr.or-anyone-else&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Hyper-optimization, or self-improvement, or rampant note-taking types will also fit in.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
&lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/elisp/Drag-and-Drop.html&quot;&gt;The manual&lt;/a&gt; notes the most important variable is &lt;code&gt;dnd-protocol-alist&lt;/code&gt;, a list of &lt;code&gt;(protocol . action)&lt;/code&gt; I think a great package to see how to customize drag and drop is &lt;a href=&quot;https://github.com/abo-abo/org-download&quot;&gt;org-download&lt;/a&gt;. 
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
You can check buffer local variables in an org buffer. I have  &lt;code&gt;org--dnd-multi-local-file-handler&lt;/code&gt;, defined by org.el. This function eventually calls this function to give that menu to attach, insert, or insert file link.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;org--dnd-local-file-handler&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;url action &lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;optional&lt;/span&gt; separator&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Handle file URL as per ACTION.
SEPARATOR is the string to insert after each link.  It may be nil
in which case, space is inserted.&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unless&lt;/span&gt; separator
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; separator &lt;span style=&quot;color: #677691;&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;method &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;eq org-yank-dnd-method &#39;ask&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                    &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org--dnd-rmc
                     &lt;span style=&quot;color: #677691;&quot;&gt;&quot;What to do with file?&quot;&lt;/span&gt;
                     &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;?a &lt;span style=&quot;color: #677691;&quot;&gt;&quot;attach&quot;&lt;/span&gt; attach&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                       &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;?o &lt;span style=&quot;color: #677691;&quot;&gt;&quot;open&quot;&lt;/span&gt; open&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                       &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;?f &lt;span style=&quot;color: #677691;&quot;&gt;&quot;insert file: link&quot;&lt;/span&gt; file-link&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                  org-yank-dnd-method&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;pcase&lt;/span&gt; method
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;`attach &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org--dnd-attach-file url action separator&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;`open &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;dnd-open-local-file url action&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;`file-link
       &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;filename &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;dnd-get-local-file-name url&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;insert &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-link-make-string &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot;file:&quot;&lt;/span&gt; filename&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; separator&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p class=&quot;footpara&quot;&gt;
Which should mean, you could actually make a new menu item. 
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
If your function can&#39;t handle the request of what&#39;s being dropped, you can call &lt;code&gt;org-download-dnd-fallback&lt;/code&gt; like &lt;code&gt;org-download&lt;/code&gt; does (&lt;a href=&quot;https://github.com/abo-abo/org-download/blob/c8be2611786d1d8d666b7b4f73582de1093f25ac/org-download.el#L679-L680&quot;&gt;link&lt;/a&gt;).
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.3&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fnr.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
See &lt;a href=&quot;https://orgmode.org/manual/Completion.html&quot;&gt;Completion&lt;/a&gt;. This is the generic completion in org mode which you can do in front of other elements too.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.4&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fnr.4&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
(or &lt;code&gt;M-TAB&lt;/code&gt;? I don&#39;t know anyone who doesn&#39;t have that as actually &lt;code&gt;Alt-TAB~/~Cmd-TAB&lt;/code&gt; for switching desktop windows) The point is, fire a command to trigger auto-complete. &lt;code&gt;M-x pcomplete&lt;/code&gt; should work. But make sure you have &lt;code&gt;org-link-abbrev-alist&lt;/code&gt; with some candidates or there&#39;s nothing to complete.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.5&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/embedding-audio-in-org-html-export.html#fnr.5&quot; role=&quot;doc-backlink&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Then in the export function, look up some mapping for ID to video link/token string. That way when video tokens don&#39;t work, you just change the ID-to-video-link association in one place. Re-export and you&#39;re good to go!.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Changing Org HTML Export, plain-list</title>
    <link href="https://17070415.xyz/blog/changing-org-html-export,-plain-list.html"/>
    <updated>4024-12-19T11:08:00Z</updated>
    <id>https://17070415.xyz/blog/changing-org-html-export,-plain-list.html</id>
    <content type="html">&lt;p&gt;
Have you ever wished your plain-lists in org mode felt more visually similar to the html rendering? I did. In one small spot.
&lt;/p&gt;

&lt;p&gt;
I&#39;ll walk through my debug process, or you can skip straight to &lt;a href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#Results&quot;&gt;Results&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
A few days ago, I went inside org html export code in &lt;code&gt;ox-html.el&lt;/code&gt; and fixed something that had long bothered me: &lt;b&gt;&lt;i&gt;Inconsistent visual line breaks&lt;/i&gt;&lt;/b&gt;&lt;sup&gt;&lt;a id=&quot;fnr.org-export-preserve-breaks&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fn.org-export-preserve-breaks&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;

&lt;p&gt;
This is better demonstrated with a sample.
&lt;/p&gt;

&lt;p&gt;
This:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot; id=&quot;org32b5b1a&quot;&gt;- line item head 1
  this line will be conjoined in html with &quot;line item head 1&quot;

- line item head 2

  this line forces &quot;line item head 2&quot; to be wrapped in a &amp;lt;p&amp;gt;. This line will also be wrapped in a &amp;lt;p&amp;gt;.
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Renders this:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot; id=&quot;org3e751c7&quot;&gt;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;ul&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;class&lt;/span&gt;=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-ul&quot;&lt;/span&gt;&amp;gt;
&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;line item head 1
this line will be conjoined in html with &quot;line item head 1&quot;&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;

&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;
line item head 2
&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;

&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;
this line forces &quot;line item head 2&quot; to be wrapped in a &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;lt;&lt;/span&gt;p&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;gt;&lt;/span&gt;. This line will also be wrapped in a &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;lt;&lt;/span&gt;p&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;gt;&lt;/span&gt;.
&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Then the browser renders this:
&lt;/p&gt;

&lt;figure id=&quot;org8f75441&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/changing-org-html-export,-plain-list/2024-12-19_12-31-41_screenshot.png&quot; alt=&quot;2024-12-19_12-31-41_screenshot.png&quot; /&gt;

&lt;/figure&gt;

&lt;p&gt;
The picture is from a basic org file without CSS. Of course on this blog I do have CSS, so the extra &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; causes more unexpectedness in such cases.
&lt;/p&gt;

&lt;p&gt;
I wanted instead:
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;A &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; for the &lt;code&gt;&quot;&#92;n&quot;&lt;/code&gt; line item head 1, so I visually saw a separate line (&lt;code&gt;&quot;&#92;n&quot;&lt;/code&gt; isn&#39;t rendered in HTML)&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; s to not wrap the line item head, pretty much ever. Maybe I&#39;m a rube for wanting that. I can solve some visual issues with CSS targetting, but semantically this makes less sense to me.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
I spent one long night debugging this.
&lt;/p&gt;
&lt;div id=&quot;outline-container-tl%3Bdr%2C%20the%20%22fix%22&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;tl%3Bdr%2C%20the%20%22fix%22&quot;&gt;tl;dr, the &quot;fix&quot;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-tl%3Bdr%2C%20the%20%22fix%22&quot;&gt;
&lt;p&gt;
I copied &lt;code&gt;org-html-paragraph&lt;/code&gt; from &lt;code&gt;ox-html.el&lt;/code&gt;, and used my own export backend&lt;sup&gt;&lt;a id=&quot;fnr.3&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fn.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; that I use with this blog.
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;Copy &lt;code&gt;org-html-paragraph&lt;/code&gt; to &lt;code&gt;jwow/org-html-paragraph&lt;/code&gt; and modify code&lt;sup&gt;&lt;a id=&quot;fnr.full-code&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fn.full-code&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. I changed one branch of the &lt;code&gt;cond&lt;/code&gt;.
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;and&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;eq parent-type &#39;item&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                 &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Not sure if this previous element condition is needed; might be extraneous
&lt;/span&gt;     &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;not &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-export-get-previous-element paragraph info&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;string-match-p &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt; contents&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; 
                                 &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;string-replace &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;br&amp;gt;&quot;&lt;/span&gt; contents&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                         contents&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;

&lt;li&gt;Update the function used for paragraph transformation to &lt;code&gt;jwow/org-html-paragraph&lt;/code&gt; in my derived backend.
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org2fbe4e1&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;a keyword argument to org-export-define-derived-backend
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;when a paragraph in the org ast is found, we call our function
&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:translate-alist&lt;/span&gt; &#39;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;paragraph . jwow/org-html-paragraph&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
This fix is more of an opinion on what should happen. The original html export code was very intententional about when &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; insertion behavior happened, but no comments explained why.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-%2A%2FUpdate%204024-12-23%3A%2F%2A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;%2A%2FUpdate%204024-12-23%3A%2F%2A&quot;&gt;&lt;b&gt;&lt;i&gt;Update 4024-12-23:&lt;/i&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-%2A%2FUpdate%204024-12-23%3A%2F%2A&quot;&gt;
&lt;p&gt;
I found that I didn&#39;t like every line getting a new line. Here&#39;s what I mean:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;1. plain-list para
   new line 1
   new line 2
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
became 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot;&gt;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;plain-list para&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;br&lt;/span&gt;&amp;gt;new line 1
&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;br&lt;/span&gt;&amp;gt;new line 2&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
This visually makes &lt;code&gt;new line 1&lt;/code&gt; appear separate from &lt;code&gt;new line 2&lt;/code&gt;. I realized I was used to org&#39;s handling of paragraphs where you could write text on a line immediately following the last, and it would be joined into one paragraph.
&lt;/p&gt;

&lt;p&gt;
So changed the regex replacement to this (this matches the first &lt;code&gt;&#92;n&lt;/code&gt; found, and only it gets replaced; other &lt;code&gt;&#92;n&lt;/code&gt; are untouched)&lt;sup&gt;&lt;a id=&quot;fnr.regex&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fn.regex&quot; role=&quot;doc-backlink&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;replace-regexp-in-string &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#92;n&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&#92;n&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;*&#92;&#92;&#39;&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;br&amp;gt;&quot;&lt;/span&gt; contents nil nil 1&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now the same org snippet gives
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot;&gt;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;plain-list para&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;br&lt;/span&gt;&amp;gt;new line 1
new line 2&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now the subsequent lines are just how a paragraph would render when one has one line after another.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Debugging%20Process&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Debugging%20Process&quot;&gt;Debugging Process&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Debugging%20Process&quot;&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-%2AFind%20out%20where%20to%20snag%20the%20debugger%2A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;%2AFind%20out%20where%20to%20snag%20the%20debugger%2A&quot;&gt;&lt;b&gt;Find out where to snag the debugger&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-%2AFind%20out%20where%20to%20snag%20the%20debugger%2A&quot;&gt;
&lt;p&gt;
I knew I was exporting to html, and &lt;code&gt;ox-html.el&lt;/code&gt; was responsible. 
&lt;/p&gt;

&lt;p&gt;
I found the line
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plain-list . org-html-plain-list&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
So that should be it I thought, try and snag that.
&lt;/p&gt;

&lt;p&gt;
I ran &lt;code&gt;edebug-defun&lt;/code&gt; on the transcoder. Then I highlighted a region and ran &lt;code&gt;org-export-region-to-html&lt;/code&gt; over line item head 2. 
&lt;/p&gt;

&lt;p&gt;
When the breakpoint snagged, I pressed &lt;code&gt;e&lt;/code&gt; and ran
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgbeea6c8&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;substring-no-properties contents&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
which showed
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot; id=&quot;org368eaff&quot;&gt;&quot;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;&#92;nline item head 2&#92;n&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;&#92;n&#92;n&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;&#92;nthis line forces &#92;&quot;line item head 2&#92;&quot; to be wrapped in a &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;lt;&lt;/span&gt;p&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;gt;&lt;/span&gt;. This line will also be wrapped in a &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;lt;&lt;/span&gt;p&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;gt;&lt;/span&gt;.&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;&#92;n&quot;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
At this point I was confused&amp;#x2013;it was already in HTML by the time I got here.
&lt;/p&gt;

&lt;p&gt;
The stacktrace showed calls like this:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org53b77d1&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plist-put attributes &lt;span style=&quot;color: #81A1C1;&quot;&gt;:class&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-
&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-html--make-attribute-string &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;%s %s&amp;gt;&#92;n%s&amp;lt;/%s&amp;gt;&quot;&lt;/span&gt; type &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;o
&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;type &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;val &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-elem
org-html-plain-list&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plain-list &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;:
org-export-data&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;plain-list &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:stan&lt;/span&gt;
#f&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;compiled-function &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;element&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&amp;lt;b
mapconcat&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;#f&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;compiled-function &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;el
org-export-data&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;section &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standar&lt;/span&gt;
#f&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;compiled-function &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;element&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; #&amp;lt;b
mapconcat&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;#f&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;compiled-function &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;el
org-export-data&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-data &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standa&lt;/span&gt;
org-export-as&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;html nil nil t nil&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; 
org-export-string-as&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;#&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;- line ite
org-export-replace-region-by(html)
org-export-region-to-html()       &lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-%2AIt%20was%20the%20wrong%20place%2A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;%2AIt%20was%20the%20wrong%20place%2A&quot;&gt;&lt;b&gt;It was the wrong place&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-%2AIt%20was%20the%20wrong%20place%2A&quot;&gt;
&lt;p&gt;
Confused, I wondered what else was responsible for rendering a plain-list. A search in the same file showed hits in &lt;code&gt;org-html-paragraph&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-%2ASo%20I%20instrumented%20org-html-paragraph%2A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;%2ASo%20I%20instrumented%20org-html-paragraph%2A&quot;&gt;&lt;b&gt;So I instrumented org-html-paragraph&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-%2ASo%20I%20instrumented%20org-html-paragraph%2A&quot;&gt;
&lt;p&gt;
With my breakpoint on &lt;code&gt;org-html-paragraph&lt;/code&gt;, it ran before &lt;code&gt;org-html-plain-list&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
I also printed out the &lt;code&gt;(substring-no-properties contents)&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org711bc6b&quot;&gt;
&quot;line item head 2&#92;n&quot;
&lt;/pre&gt;

&lt;p&gt;
It&#39;s not in html yet. This must be it! 
&lt;/p&gt;

&lt;p&gt;
But what? Where was the paragraph in &quot;- line item head 2&quot;? It looked like a bullet heading to me. What was the relationship between the plain list and a paragraph?
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-%2AThe%20AST%2A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;%2AThe%20AST%2A&quot;&gt;&lt;b&gt;The AST&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-%2AThe%20AST%2A&quot;&gt;
&lt;p&gt;
To answer that question, we need to see what org parsed as the abstract syntax tree.
&lt;/p&gt;

&lt;p&gt;
Each of the transcoders gets as input, an AST node as the first positional argument. That&#39;s what I wanted to see.
&lt;/p&gt;

&lt;p&gt;
I didn&#39;t find any built in tools to dump it into a format to see the relationships between elements&lt;sup&gt;&lt;a id=&quot;fnr.6&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fn.6&quot; role=&quot;doc-backlink&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;

&lt;p&gt;
It was only until I found the screenshot on the readme of &lt;a href=&quot;https://github.com/tomalexander/org_mode_ast_investigation_tool&quot;&gt;org_mode_ast_investigation_tool&lt;/a&gt; that I realized a plainlist contained an item, and an item contained a paragraph, which was the level in the tree I actually cared about.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-%2AMaking%20changes%2A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;%2AMaking%20changes%2A&quot;&gt;&lt;b&gt;Making changes&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-%2AMaking%20changes%2A&quot;&gt;
&lt;p&gt;
The rest is in &lt;a href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#tl%3Bdr%2C%20the%20%22fix%22&quot;&gt;tl;dr, the &quot;fix&quot;&lt;/a&gt;, where I did some string manipulation..
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Results&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Results&quot;&gt;Results&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Results&quot;&gt;
&lt;p&gt;
This:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot; id=&quot;org133fa7e&quot;&gt;- line item head 1
  this line will be conjoined in html with &quot;line item head 1&quot;

- line item head 2

  this line forces &quot;line item head 2&quot; to be wrapped in a &amp;lt;p&amp;gt;. This line will also be wrapped in a &amp;lt;p&amp;gt;.
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Renders this:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot; id=&quot;orgf767240&quot;&gt;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;ul&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;class&lt;/span&gt;=&lt;span style=&quot;color: #677691;&quot;&gt;&quot;org-ul&quot;&lt;/span&gt;&amp;gt;
&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;line item head 1&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;br&lt;/span&gt;/&amp;gt;this line will be conjoined in html with &quot;line item head 1&quot;&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;br&lt;/span&gt;/&amp;gt;&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;

&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;line item head 2&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;br&lt;/span&gt;/&amp;gt;

&amp;lt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;
this line forces &quot;line item head 2&quot; to be wrapped in a &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;lt;&lt;/span&gt;p&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;gt;&lt;/span&gt;. This line will also be wrapped in a &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;lt;&lt;/span&gt;p&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&amp;amp;gt;&lt;/span&gt;.
&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;p&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;li&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Then the browser renders this:
&lt;/p&gt;

&lt;figure id=&quot;org3227ff9&quot;&gt;
&lt;img src=&quot;https://17070415.xyz/assets/media/changing-org-html-export,-plain-list/2024-12-19_12-54-46_screenshot.png&quot; alt=&quot;2024-12-19_12-54-46_screenshot.png&quot; /&gt;

&lt;/figure&gt;

&lt;p&gt;
🚀&lt;sup&gt;&lt;a id=&quot;fnr.7&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fn.7&quot; role=&quot;doc-backlink&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Final%20Thoughts&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Final%20Thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Final%20Thoughts&quot;&gt;
&lt;p&gt;
It would be great if the AST in org mode were easier to visualize within emacs, using its own built in tools. I couldn&#39;t make sense of it with the giant print out easily. 
&lt;/p&gt;

&lt;p&gt;
I&#39;m not the best with introspecting objects, so I got stuck on what was considered a &quot;paragraph.&quot;
&lt;/p&gt;

&lt;p&gt;
Is there also no stacktrace ability to jump to source of caller? This can be a little difficult with macros, but for standard functions this should be possible. I couldn&#39;t find this ability anywhere in edebug&#39;s docs. Discord also was crickets.
&lt;/p&gt;

&lt;p&gt;
I also really like the manual, and I think certain sections deserve an update. Export mostly just works.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.org-export-preserve-breaks&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fnr.org-export-preserve-breaks&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
I didn&#39;t want the behavior of &lt;a href=&quot;help:org-export-preserve-breaks&quot;&gt;org-export-preserve-breaks&lt;/a&gt;.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
To visually render a newline, you need a line break element: &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;. It looks like org mode intentionally kept the &lt;code&gt;&quot;&#92;n&quot;&lt;/code&gt;. I say this because other elements like paragraphs in org actually remove the new lines. I like it because this is good for source control. &lt;i&gt;(Try it!)&lt;/i&gt;
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.3&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fnr.3&quot; role=&quot;doc-backlink&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
See &lt;a href=&quot;https://17070415.xyz/templates/org-vocabulary.html&quot;&gt;org vocabulary&lt;/a&gt; for definitions.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.full-code&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fnr.full-code&quot; role=&quot;doc-backlink&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgb144372&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/org-html-paragraph&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;paragraph contents info&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Transcode a PARAGRAPH element from Org to HTML.
    CONTENTS is the contents of the paragraph, as a string.  INFO is
    the plist used as a communication channel.
    Same as org-html-paragraph, but list items render 
    &quot;&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let*&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;parent &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-parent paragraph&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;parent-type &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-element-type parent&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;style &#39;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;footnote-definition &lt;span style=&quot;color: #677691;&quot;&gt;&quot; class=&#92;&quot;footpara&#92;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-data &lt;span style=&quot;color: #677691;&quot;&gt;&quot; class=&#92;&quot;footpara&#92;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;attributes &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-html--make-attribute-string
                      &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-export-read-attribute &lt;span style=&quot;color: #81A1C1;&quot;&gt;:attr_html&lt;/span&gt; paragraph&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
         &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;extra &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;or&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;cadr &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;assq parent-type style&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;cond&lt;/span&gt;
     &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;
      &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This condition is when the paragraph is actually the text of the line item in the AST
&lt;/span&gt;      &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Then we simply return contents but replace newlines with &amp;lt;br&amp;gt;
&lt;/span&gt;      &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;and&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;eq parent-type &#39;item&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                                         &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Not sure if this condition is needed; might be extraneous
&lt;/span&gt;           &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;not &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-export-get-previous-element paragraph info&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
           &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(let ((followers (org-export-get-next-element paragraph info 2)))
&lt;/span&gt;           &lt;span style=&quot;color: #677691;&quot;&gt;;;   &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(and (not (cdr followers))
&lt;/span&gt;           &lt;span style=&quot;color: #677691;&quot;&gt;;;        &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(org-element-type-p (car followers) &#39;(nil plain-list paragraph))))
&lt;/span&gt;                                 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;First paragraph in an item has no tag if it is alone or
&lt;/span&gt;      &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;followed, at most, by a sub-list.
&lt;/span&gt;                &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;string-match-p &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt; contents&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; 
                                &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;string-replace &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;br&amp;gt;&quot;&lt;/span&gt; contents&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                        contents&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
     &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-html-standalone-image-p paragraph info&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Standalone image.
&lt;/span&gt;      &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;caption
             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;raw &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-export-data
                         &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-export-get-caption paragraph&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; info&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                   &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-html-standalone-image-predicate
                    #&#39;org-html--has-caption-p&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
               &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;not &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-string-nw-p raw&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; raw
                 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;span class=&#92;&quot;figure-number&#92;&quot;&amp;gt;&quot;&lt;/span&gt;
                         &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-html--translate &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Figure %d:&quot;&lt;/span&gt; info&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                                 &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-export-get-ordinal
                                  &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-element-map paragraph &#39;link
                                    #&#39;identity info t&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                                  info nil #&#39;org-html-standalone-image-p&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                         &lt;span style=&quot;color: #677691;&quot;&gt;&quot; &amp;lt;/span&amp;gt;&quot;&lt;/span&gt;
                         raw&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
            &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;label &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;org-html--reference paragraph info&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;org-html--wrap-image contents info caption label&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
     &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Regular paragraph.
&lt;/span&gt;     &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;t &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&amp;lt;p%s%s&amp;gt;&#92;n%s&amp;lt;/p&amp;gt;&quot;&lt;/span&gt;
                &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-string-nw-p attributes&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;concat &lt;span style=&quot;color: #677691;&quot;&gt;&quot; &quot;&lt;/span&gt; attributes&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                extra contents&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.regex&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fnr.regex&quot; role=&quot;doc-backlink&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Nothing humbling like regexp. I totally forgot &quot;.&quot; wouldn&#39;t match on a literal &quot;&#92;n&quot; in the string, which is why it&#39;s &lt;code&gt;or&lt;/code&gt;​ed with a newline. The &lt;code&gt;&#92;&#92;&#39;&lt;/code&gt; in the regexp is special to &lt;code&gt;(replace-regexp-in-string)&lt;/code&gt;, as it allows you to replace only the first match. Check the help. &lt;code&gt;C-h v replace-regexp-in-string&lt;/code&gt;.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.6&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fnr.6&quot; role=&quot;doc-backlink&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Edebug and the backtrace can help some.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
When in edebug, I pressed &lt;code&gt;d&lt;/code&gt;, which pops us into the &lt;code&gt;*Edebug Backtrace*&lt;/code&gt; buffer.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
The stacktrace was not very readable for this snippet:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org17988eb&quot;&gt;org-html-paragraph&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;paragraph &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;[&lt;/span&gt;3 3 3 20 21 1 nil nil nil nil nil nil nil nil #&amp;lt;buffer  *temp*-992987-822380&amp;gt; nil nil ...&lt;span style=&quot;color: #97b098;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p class=&quot;footpara&quot;&gt;
Pressing &lt;code&gt;+&lt;/code&gt; calls &lt;code&gt;backtrace-multi-line&lt;/code&gt; at the start of an expression can expand properties. Pressing &lt;code&gt;Enter&lt;/code&gt; on ellipses can show
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;orgf315e2c&quot;&gt;org-html-paragraph&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;paragraph
                    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt;
                     &lt;span style=&quot;color: #97b098;&quot;&gt;[&lt;/span&gt;3 3 3 20 21 1 nil nil nil nil nil nil nil nil #&amp;lt;buffer  *temp*-984820-519693&amp;gt; nil nil
                        &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;item
                         &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt;
                          &lt;span style=&quot;color: #b0b1a3;&quot;&gt;[&lt;/span&gt;1 1 3 123 123 0 &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:tag&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt; item nil nil nil nil nil nil #&amp;lt;buffer  *temp*-984820-519693&amp;gt; nil
                             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;1 0 &lt;span style=&quot;color: #677691;&quot;&gt;&quot;- &quot;&lt;/span&gt; nil nil nil 123&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                             &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;plain-list
                              &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt;
                               &lt;span style=&quot;color: #8c8c8c;&quot;&gt;[&lt;/span&gt;1 1 1 123 123 0 nil top-comment nil nil nil nil nil nil #&amp;lt;buffer
                                  *temp*-984820-519693&amp;gt; nil &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;...&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;section ... #11&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;]&lt;/span&gt;
                               &lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; unordered&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
                              #6&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;]&lt;/span&gt;
                          &lt;span style=&quot;color: #81A1C1;&quot;&gt;:bullet&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;- &quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:checkbox&lt;/span&gt; nil &lt;span style=&quot;color: #81A1C1;&quot;&gt;:counter&lt;/span&gt; nil &lt;span style=&quot;color: #81A1C1;&quot;&gt;:pre-blank&lt;/span&gt; 0 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:tag&lt;/span&gt; nil&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                         &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;paragraph &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt; #5&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt; #&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;line item head 2&#92;n&quot;&lt;/span&gt; 0 17 &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:parent&lt;/span&gt; #9&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
                         &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;paragraph
                          &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt;
                           &lt;span style=&quot;color: #97b098;&quot;&gt;[&lt;/span&gt;21 21 21 123 123 0 nil nil nil nil nil nil nil nil #&amp;lt;buffer  *temp*-984820-519693&amp;gt; nil nil
                               #6&lt;span style=&quot;color: #97b098;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                          #&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;  this line forces &#92;&quot;line item head 2&#92;&quot; to be wrapped in a &amp;lt;p&amp;gt;. This line will also be wrapped in a &amp;lt;p&amp;gt;.&quot;&lt;/span&gt;
                            0 102 &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:parent&lt;/span&gt; #10&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                    #&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;line item head 2&#92;n&quot;&lt;/span&gt; 0 17 &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:parent&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;paragraph &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;[&lt;/span&gt;3 3 3 20 21 1 nil nil nil nil nil nil nil nil #&amp;lt;buffer  *temp*-984820-519693&amp;gt; nil nil &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;item &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt; &lt;span style=&quot;color: #8c8c8c;&quot;&gt;[&lt;/span&gt;1 1 3 123 123 0 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:tag&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; item nil nil nil nil nil nil #&amp;lt;buffer  *temp*-984820-519693&amp;gt; nil &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;...&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;plain-list ... #12&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:bullet&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;- &quot;&lt;/span&gt; &lt;span style=&quot;color: #81A1C1;&quot;&gt;:checkbox&lt;/span&gt; nil &lt;span style=&quot;color: #81A1C1;&quot;&gt;:counter&lt;/span&gt; nil &lt;span style=&quot;color: #81A1C1;&quot;&gt;:pre-blank&lt;/span&gt; 0 &lt;span style=&quot;color: #81A1C1;&quot;&gt;:tag&lt;/span&gt; nil&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; #7 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;paragraph &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:standard-properties&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;[&lt;/span&gt;21 21 21 123 123 0 nil nil nil nil nil nil nil nil #&amp;lt;buffer  *temp*-984820-519693&amp;gt; nil nil #12&lt;span style=&quot;color: #93a8c6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt; #&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;&quot;  this line forces &#92;&quot;line item head 2&#92;&quot; to be wrapped in a &amp;lt;p&amp;gt;. This line will also be wrapped in a &amp;lt;p&amp;gt;.&quot;&lt;/span&gt; 0 102 &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:parent&lt;/span&gt; #16&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; #4&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p class=&quot;footpara&quot;&gt;
This gave clues, but wasn&#39;t easy to comprehend. The &lt;code&gt;:standard-properties&lt;/code&gt; are hard to parse out, as they&#39;re in a vector and I had no idea what each position meant.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.7&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/changing-org-html-export,-plain-list.html#fnr.7&quot; role=&quot;doc-backlink&quot;&gt;7&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
If you&#39;re paying super close attention, you&#39;ll notice that in the org, theres a newline after &quot;this line will be conjoined&amp;#x2026;&quot; but no visual new line in the browser render. That&#39;s ok for me. Most newlines in an org doc don&#39;t warrant a visual new line. I often have paragraphs of comments to myself on how to reword a section, or scratch notes, which are spaced with new lines.
&lt;/p&gt;

&lt;p class=&quot;footpara&quot;&gt;
If I need to force a newline just for rendering, I&#39;d type &lt;code&gt;&quot;&#92;&#92; &quot;&lt;/code&gt; at the end of my line in org mode which will convert to a &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>A Transient Matter</title>
    <link href="https://17070415.xyz/blog/a-transient-matter.html"/>
    <updated>4024-12-18T05:20:00Z</updated>
    <id>https://17070415.xyz/blog/a-transient-matter.html</id>
    <content type="html">&lt;p&gt;
2000 years ago, I wrote this for my present self:
&lt;/p&gt;
&lt;hr /&gt;

&lt;p&gt;
It&#39;s 5:20 AM and I have been debugging for what has been 2 or maybe some odd hours while tired. My sleep schedule is no more. Seriously, why didn&#39;t you reach out with a hand that can traverse temporal dimensions and stop me from doing this? All for ergonomic keybindings. The calculus is unjustified. I&#39;m going to bed and I&#39;ll finish this post later.
&lt;/p&gt;

&lt;p&gt;
This is obscure. It applies to users of &lt;code&gt;xah-fly-keys&lt;/code&gt; and actions on a &lt;code&gt;transient&lt;/code&gt;.
&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;
&lt;a href=&quot;https://17070415.xyz/blog/a-transient-matter.html#tl%3Bdr&quot;&gt;Jump to tl;dr if you&#39;d like&lt;/a&gt;
&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;
What&#39;s the problem I couldn&#39;t tear away from aeons ago? The transient UI in &lt;code&gt;rg.el&lt;/code&gt;&amp;#x2013;I&#39;ve had this installed for probably close to a decade yet I never realized it came with a transient UI. In this UI, you can set flags. An example: typing &lt;code&gt;- m&lt;/code&gt; lets you change the &lt;code&gt;--max-count&lt;/code&gt; flag to only get that many matches per file. You&#39;re dandily presented a minibuffer with &lt;code&gt;--max-count=&lt;/code&gt; as a prompt. You type in &lt;code&gt;2&lt;/code&gt;, because you only want two matches per file.
&lt;/p&gt;

&lt;p&gt;
I pressed &lt;code&gt;&amp;lt;Enter&amp;gt;&lt;/code&gt;. And this is where suffering begins&amp;#x2026;
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;
Look behind you! How did you get here? What walls &amp;#x2013; wha? You were out simply noodling with your fishing rod off by the village pond, with your &lt;code&gt;evil&lt;/code&gt; vim-loser friend friend trying to tell you about how great Rust is, and how you should rewrite all your programs in Rust!
&lt;/p&gt;

&lt;p&gt;
But these walls. How long have they been there, these mossy, dust covered slabs? A summon spell must have brought you here. Well, into the dark maze you go then. As you step into sure abyss, you lean one hand on the wall for stability. Wait. Runes? You touch the stonework for a closer look. A magic panel lights up! Oooh&amp;#x2013;quickly! Touch all the buttons!
&lt;/p&gt;

&lt;p&gt;
You hear what must be fated rumbling. An inevitability you&#39;ve activated. Is it the low hum of menace? Is it a growl of a bear? Mayhap a god or spirit or troglodyte you&#39;ve angered. You try to turn on the light to see clearly. In the middle of twiddling with a wet match, you hear a squeak escape your throat.
&lt;/p&gt;

&lt;p&gt;
&lt;i&gt;&quot;Oh. Fs&quot;&lt;/i&gt; You hear demon song:
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgef329d1&quot;&gt;
Unbound suffix: ‘g’ (Use ‘C-g’ to abort, ‘?’ for help) [set-mark-command] [5 times]
&lt;/pre&gt;

&lt;p&gt;
Why isn&#39;t it working? The runes&amp;#x2013;there&amp;#x2013;&#39;g&#39; means &lt;code&gt;go&lt;/code&gt;. &lt;i&gt;I&#39;m &#39;g&#39;ing!&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
The bass section of the demon chant grows louder. Somewhere in the labyrinth you think you hear an undead angel soprano singing the sweeping melody.
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;org29486a4&quot;&gt;
Unbound suffix: ‘r’ (Use ‘C-g’ to abort, ‘?’ for help) [open-line]
Unbound suffix: ‘t’ (Use ‘C-g’ to abort, ‘?’ for help) [xah-fly-insert-mode-activate]
Unbound suffix: ‘f’ (Use ‘C-g’ to abort, ‘?’ for help) [backward-kill-word]
Unbound suffix: ‘d’ (Use ‘C-g’ to abort, ‘?’ for help) [xah-delete-current-text-block]
Unbound suffix: ‘b’ (Use ‘C-g’ to abort, ‘?’ for help) [xah-toggle-letter-case]
Unbound suffix: ‘w’ (Use ‘C-g’ to abort, ‘?’ for help) [xah-shrink-whitespaces]
&lt;/pre&gt;

&lt;p&gt;
Your jaw clenches. The adrenaline jolts your heart like a flat punch. For the first moment in your life you wonder if it would matter if you died, if anyone besides your pet goldfish would ever care.
&lt;/p&gt;

&lt;p&gt;
You&#39;ve bought all these democracies, set other countries to war for profit, destroyed the healthcare system for trillions, and this is this how you die?
&lt;/p&gt;

&lt;p&gt;
No time to think&amp;#x2013;once more with feeling! 
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgc448743&quot;&gt;
Unbound suffix: ‘e’ (Use ‘C-g’ to abort, ‘?’ for help) [wgrep-change-to-wgrep-mode]
&lt;/pre&gt;

&lt;p&gt;
With your mistap &lt;code&gt;wgrep&lt;/code&gt; squirms out of your pocket. You shove it back in, thankful the safety mechanism prevented it from discharging over your buffers. It had cost your grandmother&#39;s life to tame that beast, trap it in a jar, and distill its vengeful spirit in a homunculus fashionably bound to your &#39;e&#39;. Like a piece of bijoux.
&lt;/p&gt;

&lt;p&gt;
Keep calm! Keep cool! 
&lt;/p&gt;

&lt;p&gt;
What about &lt;code&gt;C-h k&lt;/code&gt;?
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgac6d661&quot;&gt;
Unbound suffix: ‘k’ (Use ‘C-g’ to abort, ‘?’ for help) [isearch-forward]
&lt;/pre&gt;

&lt;p&gt;
&lt;code&gt;k&lt;/code&gt;? Why had it been orphaned from &lt;code&gt;C-h&lt;/code&gt;?
&lt;/p&gt;

&lt;p&gt;
Keep calm! Keep cool!
&lt;/p&gt;

&lt;p&gt;
You&#39;ll &lt;code&gt;C-h m&lt;/code&gt; and see what&amp;#x2013;.
&lt;/p&gt;

&lt;p&gt;
You&#39;re brought to a man page for &lt;code&gt;rg&lt;/code&gt;. &lt;i&gt;No! Quit! How&#39;d you get here, manpage?&lt;/i&gt; 
&lt;/p&gt;

&lt;p&gt;
You successfully quit the man page, but why was your trusty &lt;code&gt;C-h m&lt;/code&gt; not working? Was it caused by a flipped bit from gamma radiation? You try again. 
&lt;/p&gt;

&lt;p&gt;
&lt;i&gt;Oh no! It won&#39;t stop!&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
Your beloved &lt;code&gt;C-h m&lt;/code&gt; (&lt;code&gt;describe-mode&lt;/code&gt;)! Not even help can be summoned!
&lt;/p&gt;

&lt;p&gt;
You thrash your fingers in counter rhythm to the doomful dirge. Something, you have a feeling, wants your bones and organs. Wants them more badly than you do. A stroke of panic invades every cell in your body. Screw what the &lt;code&gt;rg&lt;/code&gt; runes say!
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;org39519d2&quot;&gt;
Unbound suffix: ‘e’ (Use ‘C-g’ to abort, ‘?’ for help) [wgrep-change-to-wgrep-mode]
Unbound suffix: ‘n’ (Use ‘C-g’ to abort, ‘?’ for help) [next-error-no-select]
Unbound suffix: ‘i’ (Use ‘C-g’ to abort, ‘?’ for help) [rg-rerun-toggle-ignore]
Unbound suffix: ‘u’ (Use ‘C-g’ to abort, ‘?’ for help) [self-insert-command]
Unbound suffix: ‘e’ (Use ‘C-g’ to abort, ‘?’ for help) [wgrep-change-to-wgrep-mode]
Unbound suffix: ‘i’ (Use ‘C-g’ to abort, ‘?’ for help) [rg-rerun-toggle-ignore]
Unbound suffix: ‘n’ (Use ‘C-g’ to abort, ‘?’ for help) [next-error-no-select]
&lt;/pre&gt;

&lt;p&gt;
But your legs are pinned. The inverted T navigation keys prove no use. A crimson light floods the hall, dialates your pupils into saucers, blinds you. A dark shadow clad in glowing rune armor begins sprinting at you from about a hundred meters away. You know only from sound. The rumbling deepens; you feel the hollowness of your chest vibrating. The floor quakes from each footstep and dust from the ceiling irritates your eyes. Your whole body tightens and your forearms flex like steel cables as you pull out your enchanted nunchucks. You don&#39;t know how dicey this is going to get, but there is no way, not through all the recursion-depth-limit-exceeded hell you&#39;ve been through, that you&#39;re going to press abort.
&lt;/p&gt;

&lt;p&gt;
Your trump card!
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgd3d6752&quot;&gt;
Unbound suffix: ‘&amp;lt;esc&amp;gt;’ (Use ‘C-g’ to abort, ‘?’ for help) [xah-fly-command-mode-activate] [3 times]
&lt;/pre&gt;
&lt;p&gt;
You hear the sinister voice mock you.
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org7f5c443&quot;&gt;
You cannot escape from me! Your spell chest is mine! Mwahahaha...! Without your spells you would be a spec of dust, a
life sentenced to the drudgery of working paycheck to paycheck! Soon your people will be devoured, they will--
&lt;/pre&gt;

&lt;p&gt;
Blast! But before you have time to scrounge into your pocket, the demon has zipped a spear through space-time through your abdomen. Oddly you don&#39;t feel physical pain.
&lt;/p&gt;

&lt;p&gt;
You look down and see the dark knight lifting your impaled body at the hilt. Your senses start to warp; you taste pain, smell light, hear death. 
&lt;/p&gt;

&lt;p&gt;
&quot;Hey! Are you still there? Don&#39;t die on me,&quot; you hear from me, the narrator.
&lt;/p&gt;

&lt;p&gt;
Your eyes start to float gently away from your skull as you see your hand feebly itching for one last motion.
&lt;/p&gt;

&lt;p&gt;
You think to cast the forbidden emergency town portal: &lt;code&gt;C-g&lt;/code&gt;. Is it pride, luck, or complete discombobulation? Your ring finger slips and &lt;code&gt;C-z&lt;/code&gt; activates. The shadow is gone with nothing but quiet remaining. You find yourself panting, unsure if your heart was going to explode. You take a moment to read through &lt;code&gt;*Messages*&lt;/code&gt; as you bleed out. It&#39;s cold, but it&#39;ll be over soon.
&lt;/p&gt;

&lt;p&gt;
&quot;Take the rest of me, Death&quot; you declare. You check &lt;code&gt;C-h l&lt;/code&gt; for your spell history, which seems to work. Ahah, there!
&lt;/p&gt;

&lt;pre&gt;C-z            ;; transient-suspend&lt;/pre&gt;

&lt;p&gt;
&quot;Suspend? So that which has stripped me of all my glory yet still lives.&quot; You lose consciousness. Softly as you fade, you become aware of a jolly tune by Mariah Carrey.
&lt;/p&gt;

&lt;p&gt;
You skip the scene where death delays your passing because of a bureaucratic Christmas technicality. Unfortunately the Death judiciary has slowed dramatically to curb &quot;illegal immigration.&quot; You may not seek asylum, and awaiting trial will at least a few years. You skip this story until this paragraph:
&lt;/p&gt;

&lt;p&gt;
You finally escape the labyrinthian world of clashing mode maps, where the swerve of emacs physics was fast melting your hands and eyes. Catch your breath. Recompose. Echoes of your dead spells haunt your mind. You are only a few of the survivors of the Ritual of Unbound Suffix, nemesis of all holy and just.
&lt;/p&gt;

&lt;p&gt;
How would you, dear reader, belay this labyrinth, and bring balance to Emacs Land?
&lt;/p&gt;
&lt;div id=&quot;outline-container-tl%3Bdr&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;tl%3Bdr&quot;&gt;tl;dr&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-tl%3Bdr&quot;&gt;
&lt;p&gt;
For those who use &lt;code&gt;xah-fly-keys&lt;/code&gt; (there&#39;s less than 200 of you on planet Earth), and you struggle with transients messing with your keybindings, I&#39;ve found a temporary solution to get around the issue of the keys being snagged.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;UPDATED 
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;2024-12-25, I found some bugs that I fixed
&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;If you want to add this code to your config, you want to make sure
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;xfk is loaded FIRST, because we need to remove a hook that it adds
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(xah-fly-keys 1)
&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;xfk adds this hook in library, you want to remove it since it triggers command mode on ANY minibuffer exit
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;and when it happens in transients, you get stuck. You want to be in insert mode still
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;remove-hook &#39;minibuffer-exit-hook &#39;xah-fly-command-mode-activate&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-hook &#39;minibuffer-exit-hook #&#39;jwow/transient-aware-activate-xfk&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This variable transien--showp actually is truthy when transient is activet.
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;So if it is active, we don&#39;t want to switch out of insert mode
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;In all other cases, this is just activating command hook on minibuffer exit
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/transient-aware-activate-xfk&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;when&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;not transient--showp&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;xah-fly-command-mode-activate&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;The transient-exti/setup hooks are are optional, 
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;they don&#39;t always do the most convenient thing
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Bring yourself back to command mode once ALL transients are popped out of
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;don&#39;t use xah-fly-command-mode-activate, as leaving a nested transient will exit
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;into command mode when you&#39;re in the parent transient
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-hook &#39;transient-exit-hook #&#39;jwow/transient-aware-activate-xfk&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Always switch to insert when activating a transient
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;add-hook &#39;transient-setup-buffer-hook #&#39;xah-fly-insert-mode-activate&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;git-commit from magit for example, will put you into command mode when you&#39;re in the
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;git commit buffer, you can use this if desired:
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(add-hook &#39;git-commit-mode-hook #&#39;xah-fly-insert-mode-activate)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;code&gt;transient--showp&lt;/code&gt; is a private variable, but it comes with a doc string so this should be relatively safe to use externally for now. 
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;orged57b94&quot;&gt;
Whether to show the transient popup buffer.
&lt;/pre&gt;

&lt;p&gt;
Does it enable popup buffers? When is it truthy? I wasn&#39;t sure if it was it, so I had to just try it.
&lt;/p&gt;

&lt;p&gt;
How did I verify that this was the variable to use among all of transient variables? I instrumented &lt;code&gt;jwow/transient-aware-activate-xfk&lt;/code&gt; with &lt;code&gt;edebug&lt;/code&gt;, used my workflow for &lt;code&gt;rg&lt;/code&gt;, the breakpoint snagged, and this let me look for all variables matching &lt;code&gt;^transient-&lt;/code&gt; and check their state &lt;i&gt;during&lt;/i&gt; the transient&#39;s activation. After exiting the transient, I then refreshed each help buffer for each variable. Yep, mildly painful.
&lt;/p&gt;

&lt;p&gt;
Anyway that&#39;s all. Frankly I&#39;m surprised I solved this issue. Time to sleep, and hopefully to dream, free from the Curse of the Unbound Suffix :D.
&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;
In the shadows, magit-transient promises to avenge its fallen kin&amp;#x2026;&lt;br /&gt;
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;
&lt;b&gt;&lt;i&gt;UPDATE 2024-12-25:&lt;/i&gt;&lt;/b&gt; Changed some code. I ran into a nested transient issue (try magit, ?, M), which brings up the remote transient, after the help transient. I got stuck in command mode but needed to be in insert mode.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Fast Workaround for Conflicting Project Dependency Loading In Emacs</title>
    <link href="https://17070415.xyz/blog/fast-workaround-for-conflicting-project-dependency-loading-in-emacs.html"/>
    <updated>4024-12-16T22:20:00Z</updated>
    <id>https://17070415.xyz/blog/fast-workaround-for-conflicting-project-dependency-loading-in-emacs.html</id>
    <content type="html">&lt;p&gt;
This error message is new to the bleeding edge of emacs, but the error itself, the loading of dependencies of the same name, is not:
&lt;/p&gt;
&lt;pre class=&quot;example&quot; id=&quot;org9479321&quot;&gt;
condition-case: Eager macro-expansion failure: (error &quot;Feature ‘project’ loaded from &#92;&quot;/usr/share/emacs/31.0.50/lisp/progmodes/project.elc&#92;&quot; is now provided by &#92;&quot;~/.emacs.d/straight/build/project/project.elc&#92;&quot;&quot;)
&lt;/pre&gt;

&lt;p&gt;
I had this error in dealing with &lt;code&gt;eglot&lt;/code&gt; and &lt;code&gt;dape&lt;/code&gt; loading in certain packages, one from &lt;code&gt;straight&lt;/code&gt;, and one that&#39;s built in.
&lt;/p&gt;
&lt;div id=&quot;outline-container-tl%3Bdr&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;tl%3Bdr&quot;&gt;tl;dr&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-tl%3Bdr&quot;&gt;
&lt;p&gt;
Each time I have a conflicted load, I&#39;ve done this &lt;b&gt;before loading in any other package in my init.el&lt;/b&gt;:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; project
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:straight&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; built-in&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; xref
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:straight&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; built-in&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; jsonrpc
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:straight&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:type&lt;/span&gt; built-in&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Working ok so far. Of course, I&#39;m on bleeding edge emacs, which has &lt;code&gt;jsonrpc 1.0.25&lt;/code&gt;, so &lt;code&gt;dape&lt;/code&gt; can use it. If you&#39;re on emacs 29.4, the built in is still &lt;code&gt;1.0.24&lt;/code&gt;. In which case, you might want to specify to use your most up to date version of &lt;code&gt;jsonrpc&lt;/code&gt;:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; jsonrpc
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:straight&lt;/span&gt; &#39;t&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Describe Mode Outline</title>
    <link href="https://17070415.xyz/blog/describe-mode-outline.html"/>
    <updated>4024-12-14T01:03:00Z</updated>
    <id>https://17070415.xyz/blog/describe-mode-outline.html</id>
    <content type="html">&lt;p&gt;
I learn keys using &lt;code&gt;C-h m&lt;/code&gt;, bound to &lt;code&gt;describe-mode&lt;/code&gt;. And I also check what modes I&#39;m in if I certain keybindings don&#39;t seem to be working. It&#39;s this latter case that in an edge build of emacs (30.0.50), something has changed. 
&lt;/p&gt;

&lt;p&gt;
Before, &lt;code&gt;describe-mode&lt;/code&gt; would helpfully list all active modes up front&amp;#x2013;easy to scan.
&lt;/p&gt;
&lt;hr /&gt;
&lt;p class=&quot;verse&quot;&gt;
Minor modes enabled in this buffer: Auto-Save Centered-Cursor&lt;br /&gt;
Company-Box Company Font-Lock Org-Bullets Org-Indent Visual-Line Yas&lt;br /&gt;
&lt;br /&gt;
The major mode is Org mode defined in org.el:&lt;br /&gt;
&lt;br /&gt;
Outline-based notes management and organizer, alias&lt;br /&gt;
&quot;Carsten’s outline-mode for keeping track of everything.&quot;&lt;br /&gt;
&lt;/p&gt;
&lt;hr /&gt;

&lt;p&gt;
But now this text that shows all modes is gone. I&#39;m not sure if it&#39;s because I upgraded emacs 30 or something else, but describe mode now has an outline. I found the variable by autocompleting for &lt;code&gt;describe-&lt;/code&gt;  and found &lt;code&gt;describe-mode-outline&lt;/code&gt;, which you can customize and turn it off. Phew. 
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Docker Container Volume Not Writable</title>
    <link href="https://17070415.xyz/blog/docker-container-volume-not-writable.html"/>
    <updated>4024-12-14T00:15:00Z</updated>
    <id>https://17070415.xyz/blog/docker-container-volume-not-writable.html</id>
    <content type="html">&lt;p&gt;
Say you clone a repo, you run &lt;code&gt;docker-compose up&lt;/code&gt;, it pulls down packages, and you finally visit the app on localhost.
&lt;/p&gt;

&lt;p&gt;
And then disaster strikes&amp;#x2013;500 errors. It turns out &lt;b&gt;some directory isn&#39;t writable&lt;/b&gt; from the app. In my case, codeigniter needed to write a cache file to the mounted volume.
&lt;/p&gt;
&lt;div id=&quot;outline-container-tl%3Bdr&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;tl%3Bdr&quot;&gt;tl;dr&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-tl%3Bdr&quot;&gt;
&lt;p&gt;
&lt;b&gt;tl;dr&lt;/b&gt; the remedy I used was to
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;Shell into the container: &lt;code&gt;docker exec &amp;lt;container-name&amp;gt; -it sh&lt;/code&gt;

&lt;p&gt;
Once you&#39;re inside the container like this, I was root in the subvolume. You can run the rest of the commands from the container. Of course, you can do it outside of the container too.
&lt;/p&gt;

&lt;p&gt;
(Note this doesn&#39;t always work because not all containers will have a shell&amp;#x2013;but they usually do.)
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;Find the user running the process in question (read thru the docker entrypoint file of the container)
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;this lists the user who owns the process on the left-most column
&lt;/span&gt;ps aux | grep &amp;lt;program-name&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If &lt;code&gt;ps&lt;/code&gt; isn&#39;t installed, this might not work, in which case you can read docs on what the user would be by looking through the &lt;code&gt;dockerfile&lt;/code&gt; for the image of the container. You can also &lt;code&gt;cat /etc/passwd&lt;/code&gt; if that helps you narrow things down.
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;Find what group the user was in, and set the group for all files recursively
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;id &amp;lt;user-name&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Should return something like &lt;code&gt;uid=33(http) gid=33(http) groups=33(http)&lt;/code&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;Change the group for your repository
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;chgrp -R &amp;lt;group-name&amp;gt; /path/to/subvolume
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Set the rwx group permissions
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-zsh&quot;&gt;chmod g+rwx /path/to/subvolume
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
And then I had no errors! 
&lt;/p&gt;

&lt;p&gt;
Interestingly I had a user called &lt;code&gt;http&lt;/code&gt; since I run &lt;code&gt;apache2&lt;/code&gt; (also called &lt;code&gt;httpd&lt;/code&gt;) outside container. And in the container had a user called &lt;code&gt;www-data&lt;/code&gt;. When I ran &lt;code&gt;ls -la&lt;/code&gt; from my host machine, I saw the group was &lt;code&gt;http&lt;/code&gt;. When I ran the same command inside the container, I saw the group was &lt;code&gt;www-data&lt;/code&gt;, which was interesting. 
&lt;/p&gt;

&lt;p&gt;
Anyway, hope this helped.
&lt;/p&gt;

&lt;p&gt;
(FWIW I don&#39;t remember having this problem on mac, so this might be something you tend to run into while in linux.)
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Emacs Line length annoyances</title>
    <link href="https://17070415.xyz/blog/emacs-line-length-annoyances.html"/>
    <updated>4024-12-11T04:55:00Z</updated>
    <id>https://17070415.xyz/blog/emacs-line-length-annoyances.html</id>
    <content type="html">&lt;p&gt;
Emacs truncates messages when I&#39;m debugging elisp. It has always annoyed me. I never found the setting to not truncate because I always included &lt;code&gt;&quot;message&quot;&lt;/code&gt; as part of the string, thinking it was an echo area / messages buffer setting.
&lt;/p&gt;

&lt;p&gt;
The default emacs line length variables should just be higher by default.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;eval-expression-print-length&lt;/code&gt; defaults at &lt;code&gt;12&lt;/code&gt;! That&#39;s borderline unusable when dealing with strings and file paths.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edebug-print-length&lt;/code&gt; defaults to &lt;code&gt;50&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Setting those to at least &lt;code&gt;120&lt;/code&gt; offers me some sanity back.
&lt;/p&gt;

&lt;p&gt;
I&#39;m glad I found &lt;a href=&quot;https://emacs.stackexchange.com/questions/46186/how-to-expand-truncated-information-displayed-in-the-echo-area&quot;&gt;this post on emacs.stackexchange.com&lt;/a&gt;. Maybe I should use &lt;code&gt;apropos&lt;/code&gt; more.
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Project-specific On-Save Hooks in Emacs</title>
    <link href="https://17070415.xyz/blog/project-specific-on-save-hooks-in-emacs.html"/>
    <updated>4024-12-10T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/project-specific-on-save-hooks-in-emacs.html</id>
    <content type="html">&lt;p&gt;
Imagine if you wanted some process to run automatically, tailored to your project, after you saved your changes. For me it&#39;s exporting an org-mode file to a file 11ty can render. How is that done in emacs?
&lt;/p&gt;
&lt;div id=&quot;outline-container-tl%3Bdr&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;tl%3Bdr&quot;&gt;tl;dr&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-tl%3Bdr&quot;&gt;
&lt;p&gt;
Get a &lt;code&gt;.dir-locals.el&lt;/code&gt; file that holds dotted pairs like this:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org7b4ef74&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;org-mode . &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;eval . &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;add-hook &#39;after-save-hook #&#39;org-11ty-export-to-11tydata-and-html nil t&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Explanation&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Explanation&quot;&gt;Explanation&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Explanation&quot;&gt;
&lt;p&gt;
Dir local variables are inherited by nested directories. So at the top level of a project, all files and files in directories under the &lt;code&gt;.dir-locals.el&lt;/code&gt; will have trigger my command on save.
&lt;/p&gt;

&lt;p&gt;
This means that in all my org mode buffers, exporting the org file happens automatically after I save. In my case, I generate files that 11ty uses. (As for why I&#39;m using 11ty AND org-mode to make the site and not just one or the other, it&#39;s technical debt).
&lt;/p&gt;

&lt;p&gt;
These variables of course, don&#39;t have to introduce runnable code (via the &lt;code&gt;eval&lt;/code&gt;). They can just hold state:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This just sets a variable org-confirm-babel-evaluate to nil for all modes
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;nil . &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;org-confirm-babel-evaluate . nil&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Read more in the manual: &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/emacs.html#Directory-Variables&quot;&gt;emacs#Directory Variables&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Ergonomics&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Ergonomics&quot;&gt;Ergonomics&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Ergonomics&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;add-dir-local-variable&lt;/code&gt;: You can interactively add dir-local variables instead of manually editing the &lt;code&gt;.dir-locals.el&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;copy-file-locals-to-dir-locals&lt;/code&gt;: When you specify file specific variables, you can just have emacs put them into &lt;code&gt;.dir-locals.el&lt;/code&gt; for you.

&lt;p&gt;
Example:
&lt;/p&gt;

&lt;p&gt;
I often have local file variables like below, under a commented header so it doesn&#39;t export. I can run the command to have this variable put into &lt;code&gt;.dir-locals.el&lt;/code&gt; for me:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;color: #677691; font-weight: bold;&quot;&gt;COMMENT&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt; Local Variables&lt;/span&gt;
;; Local Variables&amp;#58;
;; flycheck-disabled-checkers: (proselint vale)
;; End:
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-More&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;More&quot;&gt;More&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-More&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Endless parenthesis &lt;a href=&quot;https://endlessparentheses.com/a-quick-guide-to-directory-local-variables.html&quot;&gt;covered this topic too&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;.dir-locals-2.el&lt;/code&gt; if &lt;code&gt;.dir-locals.el&lt;/code&gt; is committed to a repository and you don&#39;t like dangling changes. Found this tidbit in the manual.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>PHP in Leetcode</title>
    <link href="https://17070415.xyz/blog/php-leetcode.html"/>
    <updated>4024-12-06T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/php-leetcode.html</id>
    <content type="html">&lt;p&gt;
Today marks my 300th day streak in leetcode. I did today&#39;s problem in &lt;b&gt;PHP&lt;/b&gt; because I want to volunteer for nonprofits. A lot of nonprofits use PHP (and frameworks on top of PHP like wordpress).
&lt;/p&gt;

&lt;p&gt;
This post about my experience using PHP in leetcode, not actually the algorithms.
&lt;/p&gt;

&lt;p&gt;
Anyway, how is PHP on leetcode? &lt;b&gt;It&#39;s awful&lt;/b&gt;. I find that when I make submissions I beat 100% of all users because no one else submits in PHP, and I realized why.
&lt;/p&gt;

&lt;p&gt;
Let&#39;s just look at some code for the daily on 2024-12-06:
&lt;a href=&quot;https://leetcode.com/problems/minimum-limit-of-balls-in-a-bag/description/?envType=daily-question&amp;amp;envId=2024-12-07&quot;&gt;1760. Minimum Limit of Balls in a Bag&lt;/a&gt;
&lt;/p&gt;
&lt;div id=&quot;outline-container-The%20Problem&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;The%20Problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-The%20Problem&quot;&gt;
&lt;p&gt;
Cutting to the chase, binary searching over the solution space is the recommended approach. I wasn&#39;t able to come up with a heap solution, but if I did, I would reach for a &lt;code&gt;new SplMaxHeap()&lt;/code&gt;. The standard library is thankfully loaded, so no need to fuss with importing.
&lt;/p&gt;

&lt;p&gt;
Below I assume you&#39;re familiar with this technique. If not, it&#39;s basically 2 things:
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;A validation function to check if the guess is correct&lt;/li&gt;
&lt;li&gt;A binary search that uses the validation function&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
The invariant used for the problem is monotonicity (monotonicicity isn&#39;t always the invariant used in binary search, but probably the most common. Just check out the &lt;a href=&quot;https://leetcode.com/problems/find-peak-element/&quot;&gt;find-peak-element problem&lt;/a&gt; as a canonical example of an invariant that isn&#39;t monotonicity).
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Code&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Code&quot;&gt;Code&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Code&quot;&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Setting%20up%20the%20validation%20function&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Setting%20up%20the%20validation%20function&quot;&gt;Setting up the validation function&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Setting%20up%20the%20validation%20function&quot;&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-php&quot;&gt;
class Solution {

    /**
     * @param Integer[] $nums
     * @param Integer $maxOperations
     * @return Integer
     */
    function minimumSize($nums, $maxOperations) {
        $check = function (int $allowedSize) use (&amp;amp;$nums, $maxOperations) {
            $ops = 0;
            foreach($nums as $num) {
                // echo &#39; adding: &#39;, ceil($num / $allowedSize) - 1, PHP_EOL;
                $ops += ceil($num / $allowedSize) - 1;
            }
            // echo &#39;ops: &#39; . $ops . &#39; &#39; . $maxOperations . PHP_EOL;
            return $ops &amp;lt;= $maxOperations ;
        };
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
This problem reminded me of how explicit you have to be with closures. It&#39;s the &lt;code&gt;use(&amp;amp;$nums, $maxOperations)&lt;/code&gt; that allows the anonymous function to reference those variables from the outer lexical scope. Coming from ruby, python, javascript, lisps, (even java lambdas), this just seems really unecessary.
&lt;/p&gt;

&lt;p&gt;
What&#39;s also horrible on the leetcode platform is that if you don&#39;t have a variable defined, no exception will throw. It took me a few minutes to realize from &lt;code&gt;echo&lt;/code&gt; ing that in fact, &lt;code&gt;$nums&lt;/code&gt; and &lt;code&gt;$maxOperations&lt;/code&gt; were both nullish (if that&#39;s the correct term in php&amp;#x2013;they don&#39;t print anything). I had to use the &lt;code&gt;use&lt;/code&gt; syntax.
&lt;/p&gt;

&lt;p&gt;
I also ran into this newbie gotcha&amp;#x2013;I couldn&#39;t declare an inner function like this:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-php&quot;&gt;function check (int $allowedSize)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
because on running other test cases, the interpreter errored out saying &lt;code&gt;check&lt;/code&gt; was already defined. Yes, functions have global scope, don&#39;t expect lexical scoping to kick in here.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Writing%20a%20binary%20search&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Writing%20a%20binary%20search&quot;&gt;Writing a binary search&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Writing%20a%20binary%20search&quot;&gt;
&lt;p&gt;
I follow a standard binary search template. I like this one the most because it&#39;s symmetric unlike other templates. I use &lt;code&gt;$check&lt;/code&gt; as my validation function to see if the current guess works, and move &lt;code&gt;$hi&lt;/code&gt; or &lt;code&gt;$lo&lt;/code&gt; accordingly.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-php&quot;&gt;        $lo = 1;
        $hi = 1e9;
        $best = $hi;
        while ($lo &amp;lt;= $hi) {
            $mid = $lo + floor(($hi - $lo) / 2);
            // echo &#39;mid: &#39; . $mid . PHP_EOL;
            if ($check($mid)) {
                $hi = $mid - 1;
                $best = $mid;
            } else {
                $lo = $mid + 1;
            }
        }
        return $best;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Issues&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Issues&quot;&gt;Issues&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Issues&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It&#39;s not ergonomic to &lt;code&gt;echo PHP_EOL&lt;/code&gt; when you want to debug via printing. People seem really hesitant to add some kind of &lt;code&gt;println&lt;/code&gt; utility to the language. Sigh.&lt;/li&gt;
&lt;li&gt;PHP provides no built-in binary search :(. I wouldn&#39;t have used it anyway for this problem though since we&#39;re not binary searching over an array, but an abstract search space.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.leetcode.com/hc/en-us/articles/360011833974-What-are-the-environments-for-the-programming-languages&quot;&gt;Leetcode also doesn&#39;t add any useful libraries&lt;/a&gt; that would help. The only module included is &lt;a href=&quot;https://www.php.net/manual/en/book.bc.php&quot;&gt;bcmath&lt;/a&gt;, which&amp;#x2026;is not helpful in the slightest for almost all problems on the platform. Sometimes you just want an ordered map&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/php-leetcode.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; (balanced binary trees implement this).&lt;/li&gt;
&lt;li&gt;PHP feels more like a templating language still, rather than an application server language, making it not a preferred fit for leetcode.&lt;/li&gt;
&lt;li&gt;PHP has a lot of surprises in its own functions
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Like argument order of very related functions
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;array_map&lt;/code&gt; takes the callback first
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-php&quot;&gt;function array_map(?callable $callback, array $array, array $arrays = unknown): array
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
and ugh, ok ok, its variadic to how many arrays you pass in so the callable comes first, but this was totally unexpected.
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;array_reduce&lt;/code&gt; takes the array first
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-php&quot;&gt;function array_reduce(array $array, callable $callback, mixed $initial = null): ?mixed
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;the naming of functions themselves: &lt;code&gt;strlen&lt;/code&gt; vs &lt;code&gt;str_pad&lt;/code&gt;, how do you reason about when underscores happen?.&lt;/li&gt;
&lt;li&gt;You cannot have a &lt;code&gt;callable&lt;/code&gt; as a type hint for an instance variable&amp;#x2026;.&lt;/li&gt;
&lt;li&gt;Passing functions around seems like an afterthought of the language. Maybe I&#39;ll get used to it? You either pass in a string, which references the name of a function, an anonymous function declared directly, or a formatted array (format varies depending on what you&#39;re calling).&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Conclusion&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Conclusion&quot;&gt;
&lt;p&gt;
I wrote a draft of this post days ago. I think I&#39;m beginning to kind of love php in a weird way. The tooling is there in emacs. Maybe I&#39;ll post about that later.
&lt;/p&gt;

&lt;p&gt;
Leetcode is a great platform to practice language syntax. I&#39;ve reviewed quite a few concepts just doing a few problems.
&lt;/p&gt;

&lt;p&gt;
You can try yourself, and reach for these datastructures on leetcode without importing anything:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-sh&quot;&gt;SplDoublyLinkedList  SplHeap              SplObserver          SplSubject
SplFileInfo          SplMaxHeap           SplPriorityQueue     SplTempFileObject
SplFileObject        SplMinHeap           SplQueue             
SplFixedArray        SplObjectStorage     SplStack
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
I also learned a lot by packaging a &lt;a href=&quot;https://codeberg.org/MegaJ/php-binary-index-tree&quot;&gt;php binary index tree&lt;/a&gt; (it&#39;s pretty alpha, I&#39;m still learning). One could argue one would not need a library for such a small data structure. But I made it anyway&amp;#x2013;no one else did for php, might as well. Also &lt;a href=&quot;https://packagist.org/packages/megaj/binary-index-tree&quot;&gt;on packagist&lt;/a&gt;, which is the popular(?) package repository for php.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Extra%20Problems&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Extra%20Problems&quot;&gt;Extra Problems&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Extra%20Problems&quot;&gt;
&lt;p&gt;
This section is for a cursory glance a few different uses of the Spl datastructures on leetcode, without explanation of the algorithms. PHP is pretty capable, but I&#39;ll stick with python usually.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://leetcode.com/problems/take-gifts-from-the-richest-pile/description/&quot;&gt;2558. Take Gifts From the Richest Pile&lt;/a&gt;

&lt;p&gt;
In this problem, you want a container with orderedness as you mutate it. Trees work (no builtin available). But heaps are faster. 
&lt;/p&gt;

&lt;p&gt;
PHP&#39;s built in heaps don&#39;t have a &lt;code&gt;heapify&lt;/code&gt; method like in python to turn an array into a heap in &lt;code&gt;O(n)&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
You also don&#39;t have something like &lt;code&gt;heappushpop&lt;/code&gt; or &lt;code&gt;heapreplace&lt;/code&gt;, which are faster than a single &lt;code&gt;heappop&lt;/code&gt;.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-php&quot;&gt;class Solution {

    /**
     * @param Integer[] $gifts
     * @param Integer $k
     * @return Integer
     */
    function pickGifts($gifts, $k) {
        $heap = new SplMaxHeap();
        foreach($gifts as $gift) {
            $heap-&amp;gt;insert($gift);
        }
        while($k &amp;gt; 0 and $heap-&amp;gt;top() &amp;gt; 1) {
            $max = $heap-&amp;gt;extract();
            $insert = (int)sqrt($max);
            // echo $max, &#39; &#39;, $insert, PHP_EOL;
            $heap-&amp;gt;insert($insert);
            $k--;
        }
        $res = 0;
        foreach($heap as $gift) {
            $res += $gift;
        }
        return $res;
    }
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=&quot;https://leetcode.com/problems/minimum-time-to-visit-a-cell-in-a-grid/description/&quot;&gt;2577. Minimum Time to Visit a Cell In a Grid&lt;/a&gt;

&lt;p&gt;
And you can of course do dijkstra with the &lt;code&gt;SplMinHeap&lt;/code&gt;. You can also solve this using Dial&#39;s algorithm, a dijkstra variant, by using &lt;code&gt;SplQueue&lt;/code&gt; or even &lt;code&gt;SplDoublyLinkedList&lt;/code&gt; if you want to go that route.
&lt;/p&gt;

&lt;p&gt;
Here my heap elements are &lt;code&gt;(curr_cost, row, column)&lt;/code&gt;. This shows you that the heap behaves like heaps in python. Elements will be compared index-wise. That&#39;s why I didn&#39;t need a custom comparator&amp;#x2013;just store more data in a heap node.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-php&quot;&gt;class Solution {
    /**
     * @param Integer[][] $grid
     * @return Integer
     */
    function minimumTime($grid) {
        $m = count($grid); $n = count($grid[0]);
        $able_to_visit = 0;
        if ($m != 1) {
            $able_to_visit += $grid[1][0] &amp;lt;= 1 ? 1 : 0;
        }
        if ($n != 1) {
            $able_to_visit += $grid[0][1] &amp;lt;= 1 ? 1 : 0;
        }
        if ($able_to_visit == 0){
            return ($n == 1 and $n == 1) ? 0 : -1;
        }
        $min_costs = array_fill(0, $m, array_fill(0, $n, PHP_INT_MAX));
        $min_costs[0][0] = 0;
        // var_dump($min_costs);
        $q = new &#92;SplMinHeap();
        $q-&amp;gt;insert([$grid[0][0], 0, 0]);
        while ($q) {
            [$curr_cost, $r, $c] = $q-&amp;gt;extract();
            if ($r == $m - 1 and $c == $n - 1) {
                return $curr_cost;
            }
            foreach ([[$r, $c + 1], [$r, $c - 1], [$r + 1, $c], [$r - 1, $c]] as [$next_r, $next_c]) {
                if ($next_r &amp;lt; 0 or $next_r == $m or $next_c &amp;lt; 0 or $next_c == $n) {
                    continue;
                }
                $next_cost = $grid[$next_r][$next_c];
                # take into account back,forward steps
                if ($curr_cost + 1 &amp;gt;= $next_cost) {
                    $next_cost = $curr_cost + 1;
                } else {
                    $next_cost += ($next_cost - ($curr_cost + 1)) % 2;
                }
                if ($next_cost &amp;lt; $min_costs[$next_r][$next_c]) {
                    $min_costs[$next_r][$next_c] = $next_cost;
                    $q-&amp;gt;insert([$next_cost, $next_r, $next_c]);
                }
            }
        }

        return -1;
    }
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/description/&quot;&gt;862. Shortest Subarray with Sum at Least K&lt;/a&gt;&lt;br /&gt;Finally we can also &lt;code&gt;SplDoublyLinkedList&lt;/code&gt; as a queue, stack, or in this case, a deque:

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-php&quot;&gt;class Solution {

    /**
     * @param Integer[] $nums
     * @param Integer $k
     * @return Integer
     */
    function shortestSubarray($nums, $k) {
        $res = PHP_INT_MAX;

        $prefix = new SplDoublyLinkedList();
        $acc = 0;
        foreach($nums as $i =&amp;gt; $num) {
            $acc += $num;
            if ($acc &amp;gt;= $k) {
                $res = min($res, $i + 1);
            }
            // We now check if we have a window where we made a sum &amp;gt;= k
            // if so, try trimming the deque from the left end until we&#39;re the window sum
            // is &amp;lt; k. Each step, we can record the window length.
            while ($prefix-&amp;gt;count() and $acc - $prefix[0][0] &amp;gt;= $k) {
                $res = min($res, $i - $prefix[0][1]);
                // remove from left end
                $prefix-&amp;gt;shift();
            }

            // Because of negative numbers, the running sum, acc, can be less than it was
            // We want our prefix window to be monotonically increasing so we pop from right
            while ($prefix-&amp;gt;count() and $acc &amp;lt;= $prefix-&amp;gt;top()[0]) {
                // remove from right end
                $prefix-&amp;gt;pop();
            }
            $prefix-&amp;gt;push([$acc,$i]);
        }

        if ($res != PHP_INT_MAX) {
            return $res;
        }
        return -1;
    }
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/php-leetcode.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
&quot;An array in PHP is actually an ordered map. &quot; &amp;#x2013; &lt;a href=&quot;https://www.php.net/manual/en/language.types.array.php&quot;&gt;from docs&lt;/a&gt;. However, I don&#39;t see any way to initialize one with a custom comparator to keep elements in sorted order AS THE ARRAY IS UPDATED. A java &lt;code&gt;TreeMap&lt;/code&gt; would let you do this.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>4024-10 In Review</title>
    <link href="https://17070415.xyz/blog/4024-10%20In%20Review.html"/>
    <updated>4024-10-17T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/4024-10%20In%20Review.html</id>
    <content type="html">&lt;div id=&quot;outline-container-My%20meaningful%20achievements%20this%20month%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;My%20meaningful%20achievements%20this%20month%3A&quot;&gt;My meaningful achievements this month:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-My%20meaningful%20achievements%20this%20month%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Being alive. Logistics of living continue to take a huge toll whenever I need to travel long distances.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Taking the metro in Paris to CDG was uncomfortable/sweaty/hectic. The traincars were so crammed. One of the trains stopped and asked us to please not smoke during the delay.&lt;/li&gt;
&lt;li&gt;Flying was ok. I appreciated the on flight meals. I also brought a ton of boiled eggs with me.&lt;/li&gt;
&lt;li&gt;I didn&#39;t feel horrible for losing a lot of money on missing my connection in LAX&amp;#x2026;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;I went on multi-hour bike rides to different castles, then had to bike home
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Château de Brissac&lt;/li&gt;
&lt;li&gt;Château de Brézé&lt;/li&gt;
&lt;li&gt;learned about falun (marine Cenozoic deposits) in Doué-la-Fontaine&lt;/li&gt;
&lt;li&gt;Went to a mushroom museum, sculpture museum, and medieval gardens&lt;/li&gt;
&lt;li&gt;Learned how sparkling wine was made in the region from visiting some cellars&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;My airbnb host this month was really nice. She wrote me a nice note after I left.&lt;/li&gt;
&lt;li&gt;Finished a Duolingo section. Maybe 10 years ago I finished French, and now it feels like there&#39;s more content or I&#39;ve just forgotten a whole bunch.&lt;/li&gt;
&lt;li&gt;Graded some exams for a little money on the side.&lt;/li&gt;
&lt;li&gt;I got really lost and the sun had set when I was out biking one day. I couldn&#39;t see. But I made it back.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Meaningful%20losses%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Meaningful%20losses%3A&quot;&gt;Meaningful losses:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Meaningful%20losses%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I haven&#39;t been writing&lt;/li&gt;
&lt;li&gt;No opportunity creation for myself for networking. It&#39;s hard to talk to people. I&#39;m also in the countryside.&lt;/li&gt;
&lt;li&gt;My self-connection in LAX didn&#39;t work out. I ended up missing my flight by maybe 10 minutes. I paid for a different plane ticket I couldn&#39;t afford. Makes me feel almost regretful to stop and help someone at the airport.&lt;/li&gt;
&lt;li&gt;Still no job/health insurance/income.&lt;/li&gt;
&lt;li&gt;I don&#39;t feel like myself in a lot of ways.&lt;/li&gt;
&lt;li&gt;I do not have income to feel comfortable replacing
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;my 9 year old phone&lt;/li&gt;
&lt;li&gt;my laptop&lt;/li&gt;
&lt;li&gt;a lot of things that are worn out now, but that I&#39;ll continue using&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;It is hard to enjoy things knowing there is little to nothing on the other side of France. No place to get a job and get medical insurance in the US. It&#39;s complicated.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-What%20I%27m%20grateful%20for%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;What%20I%27m%20grateful%20for%3A&quot;&gt;What I&#39;m grateful for:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-What%20I%27m%20grateful%20for%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Bicycles and bike lanes&lt;/li&gt;
&lt;li&gt;The helpful bicyclist on 2024-10-13 who stopped by the side of the road and asked if I needed any help when I was many km from familiarity&lt;/li&gt;
&lt;li&gt;Cool places to visit are in general &amp;lt; €12 (castles, caves, museums)&lt;/li&gt;
&lt;li&gt;The rain in Saumur reminds me of the rain patterns in Seattle.&lt;/li&gt;
&lt;li&gt;La Loire. It&#39;s beautiful enough to make a cartel-tourist business offering visits to the afterlife.&lt;/li&gt;
&lt;li&gt;The quietness of the countryside&lt;/li&gt;
&lt;li&gt;The efficacy of oatmeal + eggs for sustained energy&lt;/li&gt;
&lt;li&gt;Continued gratefulness for grocery prices (while finishing this post in the US, I am even more grateful. I miss it.)&lt;/li&gt;
&lt;li&gt;Discovered that I like Bordeaux wines. I probably drank a personal record amount of alcohol this month. Almost 4 bottles in a month, which is a lot for me.&lt;/li&gt;
&lt;li&gt;Discovered that I really really like this multi-grain bread sold by Intermarché.&lt;/li&gt;
&lt;li&gt;Dominos pizza Thursday deals. A medium was €9 and a large was €11, and you get really good cheeses on it. Shout out to both pizza au quatre fromages and pizza au cinq fromages.&lt;/li&gt;
&lt;li&gt;I had a chocolate stuffed beignet while biking home one day.&lt;/li&gt;
&lt;li&gt;The french policewoman decided to not fine me or arrest me. I was recording an audio note on my phone while biking on the road. I think she thought I was talking to someone else on the phone. I&#39;m not sure what the legal distinction for grounds of arrest would be between those two actions&amp;#x2026;&lt;/li&gt;
&lt;li&gt;Upon leaving, my host drove me to the train station so I didn&#39;t have to do the 1hr walk with all my bags that I had planned.&lt;/li&gt;
&lt;li&gt;My friend letting me stay for a while in the US, while I get my passport renewed&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Looking%20ahead%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Looking%20ahead%3A&quot;&gt;Looking ahead:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Looking%20ahead%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Paying a lot of money out of pocket for various medical care.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I tried to reach out to dentists by going to their office in person and leaving my number and email. I was discouraged after a couple attempts. No one reached back out to me. I did not press&amp;#x2013;after all I do not pay taxes to France to feel like I should press.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;At time of writing, I haven&#39;t returned to the United States, but I don&#39;t know what happens after that.&lt;/li&gt;
&lt;li&gt;United States Presidential election&amp;#x2026;I was hoping I would have a new job at the same time VP Harris would. Not sure if she&#39;ll win, but I really hope so.&lt;/li&gt;
&lt;li&gt;A continued dead job market for software engineers like myself.&lt;/li&gt;
&lt;li&gt;I still have yet to truly create an engine (a positive feedback loop) of connection, possibility, and meaning. I do not have the resource of other people. I don&#39;t have access to all the necessary raw ingredients in the US I think.&lt;/li&gt;
&lt;li&gt;I am and have been homeless for months now. Death does not scare me. Living does.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>4024-09 In Review</title>
    <link href="https://17070415.xyz/blog/4024-09%20In%20Review.html"/>
    <updated>4024-09-27T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/4024-09%20In%20Review.html</id>
    <content type="html">&lt;p&gt;
heyllo
Wow, I didn&#39;t write anything for this month? I thought I did. I&#39;ll update this. Probably because cloudflare very much rescinded an offer of employment.
&lt;/p&gt;
&lt;div id=&quot;outline-container-My%20meaningful%20achievements%20this%20month%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;My%20meaningful%20achievements%20this%20month%3A&quot;&gt;My meaningful achievements this month:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-My%20meaningful%20achievements%20this%20month%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Meaningful%20losses%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Meaningful%20losses%3A&quot;&gt;Meaningful losses:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Meaningful%20losses%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Like last month, I&#39;ve &lt;b&gt;lost lots of sleep&lt;/b&gt;. I think I can start recovering here though.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-What%20I%27m%20grateful%20for%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;What%20I%27m%20grateful%20for%3A&quot;&gt;What I&#39;m grateful for:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-What%20I%27m%20grateful%20for%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Looking%20ahead%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Looking%20ahead%3A&quot;&gt;Looking ahead:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Looking%20ahead%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Due to passport expiry, I will have to come back to the US.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>4024-08 In Review</title>
    <link href="https://17070415.xyz/blog/4024-08%20In%20Review.html"/>
    <updated>4024-08-31T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/4024-08%20In%20Review.html</id>
    <content type="html">&lt;div id=&quot;outline-container-My%20meaningful%20achievements%20this%20month%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;My%20meaningful%20achievements%20this%20month%3A&quot;&gt;My meaningful achievements this month:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-My%20meaningful%20achievements%20this%20month%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Staying alive in France, and doing on average, at least an hour of Duolingo daily.&lt;/li&gt;
&lt;li&gt;Presented, and edited a &lt;b&gt;video for Dynamic Programming recurrence relations&lt;/b&gt;, 
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;which took in total, over &lt;i&gt;20 hours just for the editing and re-recording&lt;/i&gt; of sections where I made mistakes. I&#39;m not going to count all the hours for this one. It was so much work!&lt;/li&gt;
&lt;li&gt;Making the slides, solving algorithm problems, and deciding how to categorize patterns took time that isn&#39;t counted here.&lt;/li&gt;
&lt;li&gt;The year is 4XXX and I still don&#39;t know how how to edit out my loud breathing, or prevent the mic from picking it up in the first place. I left my Shure mic in the Bay Area.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Finally Edited, and re-recorded my presentation on Dijkstra&#39;s Algorithm&lt;/b&gt; from the in-person seminar last month. 
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;This also took a long time, easily over 12 hours. I&#39;m grateful for KDEnlive, because I don&#39;t have a powerful machine to edit video.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Survived living with a chainsmoker for 11 hot summer days who refused to smoke outside. I still have some heart pain, but that will go away. Breathing was really difficult at times.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I found a cigarette butt on the kitchen floor. I have gazed upon no cigarette so demoralizing, so death-beckoning, so apathy-inspired as that one. I picked it up and threw it in the trash. I&#39;m not sure what I did afterward, but I had so many regrets about booking this place.&lt;/li&gt;
&lt;li&gt;I managed my productivity these days. Some things got done, just not as much as I&#39;d like.&lt;/li&gt;
&lt;li&gt;People would also smoke outside my window. I couldn&#39;t escape at times if I was indoors.&lt;/li&gt;
&lt;li&gt;I also cleaned out the fridge because he didn&#39;t when he left. For a 25-year-old man to live like this, it&#39;s usually because he didn&#39;t grow up with those who cared about him.&lt;/li&gt;
&lt;li&gt;I alerted property management, who came in on another day, and opened his door unnanounced while he was smoking. What followed was an angry scolding in French that was too fast for me to follow but definitely &quot;Tu fumais dans ta chambre&quot; was forcefully accused. The lady also brought a man, for backup mayhap? In case of altercation? It was loud, and lasted for at least 10 mins. I was in my room wondering if now was a good time to get my cheese from the fridge. It sounded like they were just outside my door. I waited for the storm to pass.&lt;/li&gt;
&lt;li&gt;I almost got him evicted, but told property management to not do that to him because I was aware he had a pretty bad injury. I wish I made no attempts at kindness sometimes. Oh well it&#39;s over and given enough time this will become comedy.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Another roomate moved in the day the chain smoker left. She had a 70% proc rate per morning for vehement screaming. I don&#39;t know at who. Maybe family, because most people would just end a call from that much screaming.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I love saving money&amp;#x2026;but sometimes that leads to situations with troubled youth who have no money. My incompetence in French prevents me from asking deep questions and being able to respond meaningfully.&lt;/li&gt;
&lt;li&gt;This is how I would awaken some days when she was there for 3 weeks. To screaming.&lt;/li&gt;
&lt;li&gt;Her voice would crack, and then she would try to hit higher decibels. She vaped and that affected my lungs and heart too, but was mostly out of the apartment until night time. She was otherwise nice to me. She told me she was on social assistance. I&#39;m glad France takes care of its citizens.&lt;/li&gt;
&lt;li&gt;She told me about how she wanted to move to the city we were in and she was from Dardogne, where people were not nice. I sensed a suggestion of violence and harassment, but had no idea how to express that up to Unit 4 in Duolingo&#39;s French course.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Did two rounds of &lt;b&gt;job applications&lt;/b&gt; to US companies between Aug 1 and Aug 14, while unable to breathe at my favored capacity, sleeping on the floor, and having loud interruptions.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Surprisingly, interviewed for a job&lt;/b&gt; between presenting lectures from my room in France, amidst the chaos woven with domestic peace.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Met with hiring manager&lt;/li&gt;
&lt;li&gt;Met with someone who gave me more of a code design assessment&lt;/li&gt;
&lt;li&gt;Got to onsite round and learned they&#39;d ask a system design round.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Scrambled to &lt;b&gt;cram system design&lt;/b&gt; that I learn is &lt;i&gt;happening the next day&lt;/i&gt; from the recruiter who sent out the email. I pushed aside all else and reviewed by
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;rewatching some videos / rereading on designing a stock exchange&lt;/li&gt;
&lt;li&gt;Review what makes cassandra so great&lt;/li&gt;
&lt;li&gt;Review leaderless replication&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Gave meaningful feedback to one of my student&#39;s for his presentation on Union Find.&lt;/li&gt;
&lt;li&gt;Continued practicing leetcode.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Though I had to look up the answer for one of the daily problems and straight up and almost copy it. I put in the work to understand why my recurrence relation was incorrect, found a minimal test case, and saw I didn&#39;t actually try all valid subproblems, and saw how the model solution handled it.&lt;/li&gt;
&lt;li&gt;My streak means consistent effort, and most days I get the problem without looking up a solution but may use hints. I try to limit myself to 2 hours of consistent effort before looking at the editorial. This month was harder than every month prior this year. I didn&#39;t give up on the hard that ended this month and it took me 4+ hours and plenty of wrong attempts to get a solve. I would have had no chance had I not reviewed Dijkstra earlier.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Lingering in France sounded good, in part because I don&#39;t have enough time to learn Spanish. I found a new place, cleaned my unit, picked up my bags.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Hey, a pound of brie is &amp;lt; $4. I think there must be a government regulation + subsidy, because no way can it be this cheap. That&#39;s enough to change anyone&#39;s mind to stay here just a little while longer.&lt;/li&gt;
&lt;li&gt;There are of course, more expensive bries, and they are also great.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;I&#39;m really good at looking lost and asking for directions somehow.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I think it&#39;s how I preface by asking if they speak English (they&#39;ll say no), then I proceed to try my best in French, which is usually enough.&lt;/li&gt;
&lt;li&gt;A cadre of guffawing hommes were standing outside the train station and helped me find the right bus. It turns out the guffawing hommes were all bus drivers, and one of them led me to the bus I was going to almost vomit in.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;I somehow mentally jujutsu&#39;d myself to &lt;i&gt;not vomit in a bus&lt;/i&gt;; it would have been too embarassing.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;We rode through wind after wind of a tortuous mountain pass. I hadn&#39;t eaten enough in the morning because I was cleaning and clearing out.&lt;/li&gt;
&lt;li&gt;I was worried I wouldn&#39;t be able to explain myself to anyone if I vomited during the ride. I walked up to the bus driver when we stopped at a stop and let him know I had &quot;mal à la voiture&quot; (thanks google translate). And sat up front, which helped. I think the other people on the ride were confused.&lt;/li&gt;
&lt;li&gt;It was agony. Feeling on the edge of vomiting for over an hour, clutching a plastic bag and sweating all over it as the nerves in my fingers tingled. Maybe I was hyperventilating too. I was nauseous.&lt;/li&gt;
&lt;li&gt;That&#39;s how the Auvergne-Rhône-Alpes region do, an earthen furrowed brow.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Sadly forgot my adapter at the place before the agony of vomit&amp;#x2013;so it was time to problem solve. If my laptop runs out of battery I won&#39;t be able to continue my leetcode streak.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I texted my current host where I could buy a new adapter. After visiting a store and not finding it, he unexpectedly offered to drive me to a store to find an adapter the same day.&lt;/li&gt;
&lt;li&gt;Problem solved at this place called Darty. &quot;Solvé,&quot; I heard my host say. He then dropped me off at a bakery and I bought some good bread. Walked back up a mountain. Yay. A good kind of strenuous. Still need to see a doctor one day so I can&#39;t overdo it.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Surprisingly am closer than ever to a job&lt;/b&gt; I had a call with the hiring manager who said &quot;You had a strong technical, and a strong behavioral,&quot; and that &quot;he wish he could send me the offer letter now.&quot; So&amp;#x2026;it&#39;s probably happening but I haven&#39;t heard word since the 28th. Until I start, I&#39;m assuming I still don&#39;t have anything. Companies may still rescind offers.&lt;/li&gt;
&lt;li&gt;Allow the world to show me what&#39;s next. Being open to possibility, meaning, and connection.&lt;/li&gt;
&lt;li&gt;For the first time in a long time, I&#39;m allowing myself peace. It&#39;s been hard since last September. Very little did I look forward to.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Meaningful%20losses%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Meaningful%20losses%3A&quot;&gt;Meaningful losses:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Meaningful%20losses%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;The loss of time due to my lack of focus. It is something that cannot be recovered. (I don&#39;t think this was a character error on my part; uncomfortable living situations are just hard to manage).&lt;/li&gt;
&lt;li&gt;Didn&#39;t:
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Put ob-libre-translate on melpa&lt;/li&gt;
&lt;li&gt;write more blog articles&lt;/li&gt;
&lt;li&gt;go to that meetup where French people spoke English. Missed it 3 times because they were all on interview days, or days before interview days.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Like last month, I&#39;ve &lt;b&gt;lost lots of sleep&lt;/b&gt;. I think I can start recovering here though.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-What%20I%27m%20grateful%20for%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;What%20I%27m%20grateful%20for%3A&quot;&gt;What I&#39;m grateful for:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-What%20I%27m%20grateful%20for%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;My students&lt;/b&gt;, I mentioned already he&#39;s presenting on Union Find! He&#39;s going to show off its classical use in Kruskal&#39;s algorithm as well as applications to leetcode problems.&lt;/li&gt;
&lt;li&gt;The chance to interview at that one company.&lt;/li&gt;
&lt;li&gt;The injection of insecurity from that &quot;Design S3&quot; system design interview I died on last year. It will only make me stronger.&lt;/li&gt;
&lt;li&gt;This star log as I careen through abyssal space-time. The hiring manager looked at this journal. Apparently this gave me some cred. Huh. It&#39;s almost like my plan has at least marginal success. (yay)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;France&lt;/b&gt;. No, the people are not friendly a lot of times, and a lot of them are not helpful, but there are always those that are. I am thankful for this country for not putting up barriers to my entry, and allowing me to repose.&lt;/li&gt;
&lt;li&gt;The &lt;b&gt;cost of living in France&lt;/b&gt; inspires the will to live. A man can be free here, unburdened by the orphan crushing machine of Les États-Units.&lt;/li&gt;
&lt;li&gt;The kindness of others suggesting I look abroad to live for a bit.&lt;/li&gt;
&lt;li&gt;My friend who kept my things safe for me in the Bay Area&lt;/li&gt;
&lt;li&gt;My Airbnb host in France.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Looking%20ahead%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Looking%20ahead%3A&quot;&gt;Looking ahead:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Looking%20ahead%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Still on the docket: Attempt to seriously write articles more.&lt;/li&gt;
&lt;li&gt;May need to find a place to stay in the US now.&lt;/li&gt;
&lt;li&gt;For the contacts I&#39;ve collected, I know I need to help some people.&lt;/li&gt;
&lt;li&gt;Think about setting up some resources or time aside to help the emacs community.&lt;/li&gt;
&lt;li&gt;Continue Duolingo to improve French. Meetup is not popular in France so I will&lt;/li&gt;
&lt;li&gt;Oddly enough, I didn&#39;t do any AI or Godot learning this month, like I thought I might this month. And the strategy turned out to be finding work, and&lt;/li&gt;
&lt;li&gt;Finding my way back to the US.&lt;/li&gt;

&lt;li&gt;I may know an old lady in France who might let me stay at her place if I work on her garden. Not really sure how that will play out, or if it will at all.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>4024-07 In Review</title>
    <link href="https://17070415.xyz/blog/4024-07%20In%20Review.html"/>
    <updated>4024-07-30T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/4024-07%20In%20Review.html</id>
    <content type="html">&lt;div id=&quot;outline-container-My%20meaningful%20achievements%20this%20month%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;My%20meaningful%20achievements%20this%20month%3A&quot;&gt;My meaningful achievements this month:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-My%20meaningful%20achievements%20this%20month%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;Couch surfed at a stranger&#39;s house!&lt;/b&gt; and it went well. And it was comfortable.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;Organized and led 3 algorithms lectures, one of which was in-person&lt;/b&gt;.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It would be 4, but my flight overlapped on that day, and I needed time to settle in.&lt;/li&gt;
&lt;li&gt;Went over Dijkstra&#39;s algorithm, and it&#39;s common implementation versus how it&#39;s traditionally taught with the &lt;code&gt;decrease_key&lt;/code&gt; operation in a priority queue. I still need to edit that video.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Went to an &lt;b&gt;Emacs SF&lt;/b&gt; meetup, and suprisingly, met someone and got their number without realizing I had been admiring their work in the Emacs community for many years!
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I wish I had more in common to start a fire or was staying longer to match on more interests.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Submitted a packet for the Onion fellowship and I know I won&#39;t get selected. I got good feedback from a friend who said to keep things shorter who probably will get selected, and I&#39;ll keep that in mind. I&#39;m glad I tried this writing exercise.&lt;/li&gt;
&lt;li&gt;Came (a bit begrudgingly) to &lt;b&gt;France, purely for cost of living&lt;/b&gt; savings. Not to have fun. Not to see the Olympics.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It turns out my worries about needing proof of subsistence weren&#39;t necessary. A US Passport gives you the benefit of the doubt in so many ways. I didn&#39;t need to produce any documentation about my stay. I don&#39;t even have a return flight.&lt;/li&gt;
&lt;li&gt;Schwab was down and I couldn&#39;t move any money from the bungled Crowdstrike deploy (who shipped to 100% of users without doing canary deploys or testing? What a company.). I was worried about being denied entry due to lack of funds in my bank account.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Second Place at an AI and Security themed hackathon&lt;/b&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;And I left before any winning was announced because I had to meet with a person I was couch surfing with.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Networked with people at the hackathon&lt;/b&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;But I need to go deeper! I need to help them outside of the hackathon.&lt;/li&gt;
&lt;li&gt;A couple people told me I should write on medium.&lt;/li&gt;
&lt;li&gt;I also didn&#39;t capitalize and really meet with as many people as I&#39;d like, but also my team needed me. The hackathon was chaos.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Helped someone, ever-so-slightly, understand just a bit more about lisp macros. When they asked, I had pretty bad diarrhea at a public library when the only stall was occupied.&lt;/li&gt;
&lt;li&gt;Took the TGV down to southern France. It&#39;s still really busy here though, lots of people here for the Olympic games.&lt;/li&gt;
&lt;li&gt;Survived some kind of diarrhea that plagued me for days.&lt;/li&gt;
&lt;li&gt;Not dying; not being sicker; not getting anyone else sick.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;timestamp-wrapper&quot;&gt;&lt;span class=&quot;timestamp&quot;&gt;&amp;lt;4024-08-10 Sat&amp;gt; &lt;/span&gt;&lt;/span&gt; Updates to this month:
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;Wrote &lt;a href=&quot;https://codeberg.org/MegaJ/ob-libre-translate&quot;&gt;ob-libre-translate&lt;/a&gt;&lt;/b&gt;, my first emacs package that I wrote on the 31st, after this article. It&#39;s a small one, and I had a template from &lt;a href=&quot;https://github.com/krisajenkins/ob-translate/&quot;&gt;ob-translate&lt;/a&gt;, but still; yay. I tried writing an article on it, but didn&#39;t finish in this month. I still need a piece of creative writing for it, and an image.&lt;/li&gt;
&lt;li&gt;Applied to some jobs this month. It&#39;s a slog to do that. And I secured one interview! Wow the chances are usually &amp;lt; 1% for each job application.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Meaningful%20losses%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Meaningful%20losses%3A&quot;&gt;Meaningful losses:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Meaningful%20losses%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Didn&#39;t hit month goal of 3 articles this month. This one counts. I&#39;m missing 2 others.&lt;/li&gt;
&lt;li&gt;Came to France, leaving my &lt;b&gt;life in America at a pause&lt;/b&gt;. I enjoyed the Bay Area and part of me didn&#39;t want to leave. I had roots here, until I uprooted myself more than a decade ago. Am I really able to network in France?&lt;/li&gt;
&lt;li&gt;Someone I know didn&#39;t have time to meet during the in-person seminar. I likely won&#39;t see her for a while. This didn&#39;t hurt emotionally, but it was a meaningful loss because I could have helped a student network for a job. (And maybe network for a job myself).&lt;/li&gt;
&lt;li&gt;I&#39;ve &lt;b&gt;lost lots of sleep&lt;/b&gt;. In addition I was hauling ~50lbs in hot weather and not eating much. The body has tiredness.&lt;/li&gt;
&lt;li&gt;The place where I&#39;m staying unsettles me because of
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;noise; there&#39;s 4 other people here. And lots of banging up stairs.&lt;/li&gt;
&lt;li&gt;people smoking indoors&lt;/li&gt;
&lt;li&gt;the place is dirty; I found a cigarette bud on the kitchen floor. It&#39;s a total guy-sty. Things feel greasy when I touch them.&lt;/li&gt;
&lt;li&gt;and I paid for a month. So I&#39;m locked in&amp;#x2026;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;My friend totally botched scheduling after I told him for months I needed a ride from Bay Area &lt;b&gt;TO&lt;/b&gt; Seattle. He kept thinking I was going the other way, and our roadtrip is effectively canceled, and I had to scramble for housing, kind of why I unexpectedly needed to travel ASAP.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Logistics&lt;/b&gt; eat so much time it&#39;s effectively an entire project to just get from place to place. I&#39;m grateful I can travel, but still.&lt;/li&gt;
&lt;li&gt;Got sick in the Bay Area. Not sure why. I got better just hours before getting on that flight to Paris, which was too close.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-What%20I%27m%20grateful%20for%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;What%20I%27m%20grateful%20for%3A&quot;&gt;What I&#39;m grateful for:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-What%20I%27m%20grateful%20for%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;My students&lt;/b&gt;. They&#39;ve connected me with the hackathon, which led to some connections in the Bay Area. I also got a free meal from one of my students and an apple.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;My friend who teaches math&lt;/b&gt; took me out for meals and I got to hear about the girl he&#39;s dating.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Put away a suitcase in his storage. That suitcase is half my life right now. Glad it&#39;s safe and I&#39;m not lugging it around.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;The host on couch surf. He let me do whatever I needed to do and didn&#39;t need me to hang out with him. I used his cooking utensils and his bed was cool during these summer nights.&lt;/li&gt;
&lt;li&gt;Oakland in general. I didn&#39;t realize there were such cool spots to hang out. I was too poor back then and trapped in violence to really see anything else than the people I wanted to hurt.&lt;/li&gt;
&lt;li&gt;AC transit. Unlike the olden days, I think AC transit has AC now. 51B was cool during a hot day.&lt;/li&gt;
&lt;li&gt;The shopkeeper in Paris from whom I bought &lt;b&gt;30 eggs&lt;/b&gt; from. I then proceeded to &lt;b&gt;hardboil&lt;/b&gt; 30 eggs and packed them in a ziplock bag. They were good snacks since I hadn&#39;t been eating much on the international flight; I also ate some on the TGV the next day. I&#39;m going to eat my 30th egg from that carton now.&lt;/li&gt;
&lt;li&gt;The &lt;b&gt;French cost of living!&lt;/b&gt; Buying weird cheeses that have some mold on them for a discount from the &quot;anti-gaspi&quot; section of the &quot;hypermarket.&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Peaches/nectarines are in season&lt;/b&gt; (and they&#39;re cheap!).&lt;/li&gt;
&lt;li&gt;The shopkeeper at Spar who helped me find laundry detergent and was amused by my kind of broken French.&lt;/li&gt;
&lt;li&gt;France doesn&#39;t really have air conditioning, and despite my grievances about my living space, it&#39;s cool enough to sleep. I&#39;m sleeping on the ground though instead of on the bed (it&#39;s complicated).&lt;/li&gt;
&lt;li&gt;A &lt;b&gt;friend&lt;/b&gt; from high school in the Bay Area let me stay with her and her husband. They had a really friendly cat that reminded me of my college days. Her husband also makes really good eggs and is a good chef in general.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Another friend&lt;/b&gt; from high school told me about a job opening at his friend&#39;s place. We went out to lunch in Oakland at a nice Thai restaurant. I enjoyed hearing about his life now. He&#39;s going to be a dad!&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Another friend&lt;/b&gt; from college talked to her parents and I got to stay at her parents&#39; place. They cooked good food and I told them also that they needn&#39;t cook for me. They&#39;ll welcome me back in the future too!&lt;/li&gt;
&lt;li&gt;Some guy stole a dozen eggs from me at Berkeley Public Library as I was using the restroom on the 2nd floor. I found him. Chased him. And I realized after seeing him, he&#39;s in a much worse spot than me. I&#39;m glad I let that go. He better enjoy those eggs!&lt;/li&gt;
&lt;li&gt;Okay, I think I kind of carried my team in terms of direction and helping everyone, but my hackathon teammates were cool people too.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Airplane bartering episode&lt;/b&gt;: I don&#39;t eat meat so I gave my in-flight meal to a guy in another aisle who then gave me double-stuffed oreos which I then gave to the French guy sitting next to me who gave me his thing of chickpeas earlier. And the other guy sitting next to me who tapped the other-aisle-guy on the shoulder so I could initiate. If only I could network like that for jobs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Looking%20ahead%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Looking%20ahead%3A&quot;&gt;Looking ahead:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Looking%20ahead%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Wrap up the algorithms seminar, covering up to either a first or second lecture on Dynamic Programming.&lt;/li&gt;
&lt;li&gt;Attempt to seriously write articles more.&lt;/li&gt;
&lt;li&gt;May try to &lt;b&gt;couch surf&lt;/b&gt; more in this town, or nearby towns. I&#39;m going to sleep at weird hours because it&#39;s so noisy. I think children run up and down upstairs. Lots of banging and sometimes wall shaking.&lt;/li&gt;
&lt;li&gt;I&#39;ve collected contacts&amp;#x2026;but I need to somehow create value for people here. Connect others.&lt;/li&gt;
&lt;li&gt;Where do I go from here? Berlin, Germany? Try to network in Paris? Lisbon, Portugal? Malaga, Spain?&lt;/li&gt;
&lt;li&gt;Je veux améliorer mon français.&lt;/li&gt;
&lt;li&gt;Either I study AI, or dedicate time to learning 3D Godot in August. I need to somehow find an opening in the job market, or create something to attract income.&lt;/li&gt;
&lt;li&gt;If I don&#39;t do either of the above, it&#39;ll most likely because of a software project I&#39;ll undertake. I don&#39;t know what that would be yet.&lt;/li&gt;
&lt;li&gt;Apply for jobs in the US. I want to return&amp;#x2026; but I might be able to chill in SE Asia for cheap after my stay in Europe. I don&#39;t like flying because of carbon emissions. If I had not failed so hard in acquiring income I would be sitting in Seattle.&lt;/li&gt;
&lt;li&gt;I may know an old lady in France who might let me stay at her place if I work on her garden. Not really sure how that will play out, or if it will at all.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>4024-06 In Review</title>
    <link href="https://17070415.xyz/blog/4024-06%20In%20Review.html"/>
    <updated>4024-06-30T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/4024-06%20In%20Review.html</id>
    <content type="html">&lt;div id=&quot;outline-container-My%20meaningful%20achievements%20this%20month%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;My%20meaningful%20achievements%20this%20month%3A&quot;&gt;My meaningful achievements this month:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-My%20meaningful%20achievements%20this%20month%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;b&gt;Organized and led 5 algorithms lectures&lt;/b&gt;, once each Saturday. I tallied my time. One lecture takes 10-16 hours of my time per week. I make slides in emacs, curate problems for the lecture, find real life applications, (re)solve problems so I can decide whether they&#39;re suitable, and dry-run my lectures.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;I have recorded lectures, but I only uploaded the &lt;a href=&quot;https://youtu.be/O8E9x1dcmwc&quot;&gt;most recent one to youtube&lt;/a&gt; so far. Yay binary search. I definitely had a choke moment. Wish it was shorter&amp;#x2026;it&#39;s actually in two parts.&lt;/li&gt;
&lt;li&gt;Getting started took a lot of time too: deciding on the technology to make slides, rendering to PDF, fixing bugs/tweaking things in the export.&lt;/li&gt;
&lt;li&gt;I also have been doing individual reach outs to students but I haven&#39;t gotten much of a response.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Started a book club and finished a book&lt;/b&gt;. And genuinely, I think the people that participated got something out of it.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It was Supercommunicators by Charles Duhigg&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Went to an &lt;b&gt;open mic&lt;/b&gt;, bombed, and met people that I later talked with outside of the event. Got 5 people&#39;s numbers, and I irregularly talk to 2 of those people now! Connected with one person in tech on linkedin but he isn&#39;t responsive.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;A complete stranger in the crowd went out of her way to tell me they enjoyed me going up there (they were being nice, I had no material).&lt;/li&gt;
&lt;li&gt;Got invited to another event by someone I met there, to attend a lesson on standup in LA. I ended up going and was able to listen and give my time and attention meaningfully to others.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Wrote a &lt;b&gt;prototype for a game&lt;/b&gt; based off of someone&#39;s idea from the open mic. Met up with them to show them. Made short video to show them what I built. I&#39;m glad I learned enough &lt;b&gt;Godot&lt;/b&gt; last year to just execute. This could be a deadend, but building it was cool anyway.&lt;/li&gt;
&lt;li&gt;Published &lt;b&gt;&lt;a href=&quot;https://www.npmjs.com/package/sequence-heap&quot;&gt;the first npm package of a sequence heap&lt;/a&gt;&lt;/b&gt;, added CI, linting, coverage, tests, &lt;b&gt;creative writing&lt;/b&gt;, and images. I had working code already 5-6 months ago, and all the things outside of pure execution took more than 2x the time. Learned enough Krita to do some image editing using masks and different brushes. Storyboarding the gif and the subsequent video took a nonnegligible amount of time as well.&lt;/li&gt;
&lt;li&gt;Learned enough Krita to make &lt;b&gt;&lt;a href=&quot;https://codeberg.org/MegaJ/sequence-heap.js#the-nerd-s-description&quot;&gt;a simple gif for the sequence-heap&lt;/a&gt;&lt;/b&gt; project. Embarassingly, it took me a long time to make the proofs of time complexity.&lt;/li&gt;
&lt;li&gt;Learned enough KDEnlive to do the &lt;b&gt;video editing&lt;/b&gt; to explain the sequence heap. Video editing took an immense amount of time. Re-recording is painful. I also don&#39;t have a GPU to help me out when rendering.
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Had a huge headache because the way it was built for my OS made rendering not work. So I had to find a specific older version to use.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Uploaded &lt;b&gt;&lt;a href=&quot;https://youtu.be/512ZjLOVOEA&quot;&gt;my first youtube video on a sequence heap&lt;/a&gt;&lt;/b&gt;! I sped it up so the speed is 1.2x because I felt I talked too slowly. It might say it was published today, but I had it unlisted for a while.&lt;/li&gt;
&lt;li&gt;Published 2 articles on this blog this month (this is the second one!).&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Meaningful%20losses%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Meaningful%20losses%3A&quot;&gt;Meaningful losses:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Meaningful%20losses%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;A lot of hair ☹️.&lt;/li&gt;
&lt;li&gt;A relationship I don&#39;t want to repair; a living situation where I am &lt;b&gt;increasingly uncomfortable&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lost budding relationships&lt;/b&gt; with people because I cannot reach them. A car-centric way of life is Southern California. I cannot build familiarity with other people with my lack of mobility. I am absolutely sure I can benefit others, but that means little if I do not show up.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Looking%20ahead%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Looking%20ahead%3A&quot;&gt;Looking ahead:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Looking%20ahead%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Open myself to &lt;b&gt;couch surfing&lt;/b&gt; around other people&#39;s places. A friend thinks I can use this situation to network. I am not so optimistic.&lt;/li&gt;
&lt;li&gt;Or &lt;b&gt;leave America&lt;/b&gt;. And live somewhere cheaper for a while. Still unemployed. There is no one who will help me until I can bring enough value to them.&lt;/li&gt;
&lt;li&gt;Do an &lt;b&gt;in-person seminar&lt;/b&gt; at a community college in July. Two people are interested. I do want to connect better with students, and help them where they are at.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Continue lectures&lt;/b&gt; every Saturday in July even if no one shows up. I can at least practice my communication skills, video/audio editing skills, speaking, and problem solving skills. When I will one day need these skills for something else, I can show up for those situations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Supercommunicators, Book Club</title>
    <link href="https://17070415.xyz/blog/supercommunicators-bookclub.html"/>
    <updated>4024-06-05T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/supercommunicators-bookclub.html</id>
    <content type="html">&lt;p&gt;
I&#39;ve found others interested in the art of human connection and pitched the idea of doing a book club on &lt;i&gt;Supercommunicators&lt;/i&gt; with me. Success!
&lt;/p&gt;

&lt;p&gt;
I&#39;ve been a fan of Charles Duhigg&#39;s work since I read &lt;i&gt;The Power of Habit&lt;/i&gt; over ten years ago, back when I first started reading about how to get more done.
&lt;/p&gt;

&lt;p&gt;
I already read the book, and now I can learn from others and provide value at the same time.
&lt;/p&gt;

&lt;p&gt;
Here&#39;s a 4 week agenda I made. Feel free to use it, share it, or suggest improvements!
&lt;/p&gt;
&lt;div id=&quot;outline-container-Week%201%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Week%201%3A&quot;&gt;Week 1:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Week%201%3A&quot;&gt;
&lt;p&gt;
83 pages
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Prologue (pp i-xviii)&lt;/li&gt;
&lt;li&gt;The Three Kinds of Conversation (pp. 1-33)&lt;/li&gt;
&lt;li&gt;The &lt;i&gt;What&#39;s This Really About?&lt;/i&gt; Conversation (pp. 35-75)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Questions%20for%20Reading%20Comprehension%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Questions%20for%20Reading%20Comprehension%3A&quot;&gt;Questions for Reading Comprehension:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Questions%20for%20Reading%20Comprehension%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;What do you hope to gain from this section?&lt;/li&gt;
&lt;li&gt;What are you hoping to get out of the book and this book club?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What is the goal of a conversation?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Finish this sentence: C_ _ _ _ _ _ _ _ _ _ _ _ is connection.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Explain in your own words the Matching Principle and how it&#39;s different than mimicking.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What is neural entrainment? Describe a moment in your life where you felt neurally entrained.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Most recently, when did you not follow Rule One and not pay attention to the conversation? What happened?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What did you learn from this week&#39;s reading?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Discussion%20topics%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Discussion%20topics%3A&quot;&gt;Discussion topics:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Discussion%20topics%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;What kind of conversation are we having now?&lt;/li&gt;
&lt;li&gt;What did you learn from this week&#39;s reading?&lt;/li&gt;
&lt;li&gt;I&#39;m here because I want to be more consistent as a communicator. What about you?&lt;/li&gt;
&lt;li&gt;Has anyone prepared for conversations? How did it work out?&lt;/li&gt;
&lt;li&gt;Has anyone tried meetings where the cultural norm, or rule was to declared what their goal for the conversation was? How did it go?&lt;/li&gt;
&lt;li&gt;Boly&#39;s creative perspective shifting impressed me. His ability to see Karl&#39;s values clearly allowed him to create a completely different argument to shift Karl&#39;s own perspective. When have you done something like this? Or do you have examples of someone else doing this?&lt;/li&gt;
&lt;li&gt;Is there an upcoming conversation you want to prepare for? How will you prepare for it?&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Week%202%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Week%202%3A&quot;&gt;Week 2:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Week%202%3A&quot;&gt;
&lt;p&gt;
84 pages
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;The &lt;i&gt;How Do We Feel?&lt;/i&gt; Conversation (pp. 77-161)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Week%202%3A--Questions%20for%20Reading%20Comprehension%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Week%202%3A--Questions%20for%20Reading%20Comprehension%3A&quot;&gt;Questions for Reading Comprehension:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Week%202%3A--Questions%20for%20Reading%20Comprehension%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;What do you hope to gain from this section?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Why did Epley stop drinking?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What 3 questions Epley ask the hedge fund managers to share?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;How would you apply learnings from the Fast Friends Procedure to a non-laboratory social setting?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What role does vulnerability play in connecting with others?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;How quickly can strangers connect?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Convert the following questions into deep questions, or describe how you would lead into a deep question:
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Do you like movies?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What did you do this weekend?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Where do you work?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;How did McGuire select astronauts? What Supercommunicator principles did he follow?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;How did writers of The Big Bang Theory end up having actors communicate emotions to an audience?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Name a conflict in your life. Why were you fighting? State its surface issue as well as the emotional conflict.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Reflect upon a time someone really connected with you. Did you loop for understanding?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What does controlling a conflict&#39;s boundaries mean to you?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What did you learn?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Week%202%3A--Discussion%20topics%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Week%202%3A--Discussion%20topics%3A&quot;&gt;Discussion topics:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Week%202%3A--Discussion%20topics%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;What did you learn?&lt;/li&gt;
&lt;li&gt;What (new) ways do you want to bring the power of questions into your life?&lt;/li&gt;
&lt;li&gt;I don&#39;t feel like Epley&#39;s experiment with hedge fund managers would make me feel more connected to other hedge fund managers. What about other people?&lt;/li&gt;
&lt;li&gt;Tell me about how you handled a conflict recently. What did you do?&lt;/li&gt;
&lt;li&gt;Does anyone have a conflict with people they care about and disagree with?&lt;/li&gt;
&lt;li&gt;Has anyone calmed a storm by looping for understanding in an online forum? Or something close? How did you do it?&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Week%203%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Week%203%3A&quot;&gt;Week 3:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Week%203%3A&quot;&gt;
&lt;p&gt;
65 pages
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;The &lt;i&gt;Who Are We?&lt;/i&gt; Conversation (pp. 169-234)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Week%203%3A--Questions%20for%20Reading%20Comprehension%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Week%203%3A--Questions%20for%20Reading%20Comprehension%3A&quot;&gt;Questions for Reading Comprehension:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Week%203%3A--Questions%20for%20Reading%20Comprehension%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;What do you hope to gain from this section?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;In your own words, what is stereotype threat? Do you face this? What&#39;s a strategy you might use to mitigate stereotype threat?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What is the contact hypothesis?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;How can you draw out multiple identities?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;How does this chapter tie into what you know already about communicating during amidst conflict?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What does a &lt;i&gt;Who Are We?&lt;/i&gt; Conversation look like? How do you know it succeeded?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Define motivational interviewing. Where else did the book mention this concept?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What is identity threat? How did this impact the culture at Netflix?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Think about a hard conversation you&#39;ve had. What obstacles did you face? What can you do to overcome those obstacles in a similar conversation in the future?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;How can you use the guidelines to help people you care about have an important conversations?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;What did you learn?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Week%203%3A--Discussion%20topics%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Week%203%3A--Discussion%20topics%3A&quot;&gt;Discussion topics:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Week%203%3A--Discussion%20topics%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;What did you learn?&lt;/li&gt;
&lt;li&gt;I&#39;m really impressed with Chamie&#39;s ability to sway one of her patients. I&#39;m also very surprised at Salma Mousa&#39;s experiment. What did you feel when reading those passages?&lt;/li&gt;
&lt;li&gt;Are you trying to persuade someone currently? How can you use a &lt;i&gt;Who Are We?&lt;/i&gt; conversation to help?&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Week%204%3A&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Week%204%3A&quot;&gt;Week 4:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Week%204%3A&quot;&gt;
&lt;p&gt;
Free discussion; No pages, meet to talk about implementation and results or seek advice.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Solidifying%20understanding%20with%20review%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Solidifying%20understanding%20with%20review%3A&quot;&gt;Solidifying understanding with review:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Solidifying%20understanding%20with%20review%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npr.org/2024/02/20/1196978652/life-kit-supercommunicators-charles-dughigg&quot;&gt;https://www.npr.org/2024/02/20/1196978652/life-kit-supercommunicators-charles-dughigg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Who do you consider a supercommunicator? What traits do they have?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;How can someone else be sure you&#39;re not only waiting your turn to speak?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;How is matching not the same as mimicking? Note a time in your life where you matched but did not mimic.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Week%204%3A--Discussion%20topics%3A&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Week%204%3A--Discussion%20topics%3A&quot;&gt;Discussion topics:&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Week%204%3A--Discussion%20topics%3A&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;How is implementation going?&lt;/li&gt;
&lt;li&gt;What other tactics do you use to connect with others that weren&#39;t mentioned?&lt;/li&gt;
&lt;li&gt;What is your favorite way to connect with someone?&lt;/li&gt;
&lt;li&gt;What did you disagree with in the book? Why?&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Programming Helm: Quick File Access</title>
    <link href="https://17070415.xyz/blog/helm-quick-open-org-files.html"/>
    <updated>4024-03-26T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/helm-quick-open-org-files.html</id>
    <content type="html">
&lt;div id=&quot;outline-container-org5982912&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org5982912&quot;&gt;Code&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org5982912&quot;&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/org-dir &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;expand-file-name &lt;span style=&quot;color: #677691;&quot;&gt;&quot;~/org/&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Named these functions for debugging.&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Wanted to modify the lists in place by adding the display name as first element&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/helm-action&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;candidate&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;find-file &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;cl-first candidate&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/helm-transformer&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;candidates&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;mapcar
   &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;file-with-attributes&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
     &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;cons &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;file-name-nondirectory &lt;span style=&quot;color: #b0b0b3;&quot;&gt;(&lt;/span&gt;cl-first file-with-attributes&lt;span style=&quot;color: #b0b0b3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;
           file-with-attributes&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
   &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;sort candidates &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;lambda&lt;/span&gt; &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;c1 c2&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #aebed8;&quot;&gt;(&lt;/span&gt;time-less-p &lt;span style=&quot;color: #b0b0b3;&quot;&gt;(&lt;/span&gt;nth 7 c2&lt;span style=&quot;color: #b0b0b3;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b0b0b3;&quot;&gt;(&lt;/span&gt;nth 7 c1&lt;span style=&quot;color: #b0b0b3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #aebed8;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/org-dir-helm-source
      &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;helm-build-sync-source&lt;/span&gt;
          &lt;span style=&quot;color: #677691;&quot;&gt;&quot;Quick Open Org File&quot;&lt;/span&gt;
        &lt;span style=&quot;color: #81A1C1;&quot;&gt;:action&lt;/span&gt; #&#39;jwow/helm-action
        &lt;span style=&quot;color: #81A1C1;&quot;&gt;:candidates&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;directory-files-and-attributes jwow/org-dir
                                                    t
                                                    &lt;span style=&quot;color: #677691;&quot;&gt;&quot;.org$&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;.org.gpg$&quot;&lt;/span&gt;
                                                    t&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;sorted by last modified time, descending&lt;/span&gt;
        &lt;span style=&quot;color: #81A1C1;&quot;&gt;:candidate-transformer&lt;/span&gt; #&#39;jwow/helm-transformer
        &lt;span style=&quot;color: #81A1C1;&quot;&gt;:diacritics&lt;/span&gt; t&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/org-dir-quick-jump&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;helm &lt;span style=&quot;color: #81A1C1;&quot;&gt;:sources&lt;/span&gt; &#39;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;jwow/org-dir-helm-source&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;define-key xah-fly-command-map &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;kbd &lt;span style=&quot;color: #677691;&quot;&gt;&quot;C-SPC o&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt; #&#39;jwow/org-dir-quick-jump&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Interprocess Communication (IPC) In Emacs for Typing Sounds</title>
    <link href="https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html"/>
    <updated>4024-01-30T00:00:00Z</updated>
    <id>https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html</id>
    <content type="html">&lt;p&gt;
&lt;b&gt;&lt;i&gt;CLACK CLACK CLACK.&lt;/i&gt;&lt;/b&gt; Do you hear that? It&#39;s the sound of an IBM Selectric typewriter. &lt;b&gt;&lt;i&gt;PING&lt;/i&gt;&lt;/b&gt;.
&lt;/p&gt;

&lt;p&gt;
Making typewriter from emacs won&#39;t boost your productivity, but why the hell should it. Part of using emacs is making it your own.
&lt;/p&gt;

&lt;p&gt;
But I ran into lag&amp;#x2013;my keystrokes struggled to get on the page&amp;#x2013;arresting my evil schemes to a full stop. Every future propaganda leader needs the ability to propagate their ideas. It was &lt;span class=&quot;underline&quot;&gt;unacceptable&lt;/span&gt;!
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;In this article, I investigate&lt;/b&gt; quick ways to make the &lt;a href=&quot;https://github.com/rbanffy/selectric-mode/&quot;&gt;selectric-mode&lt;/a&gt; package &lt;span class=&quot;underline&quot;&gt;faster&lt;/span&gt;, from trying emacs threads to an mpv daemon.
&lt;/p&gt;

&lt;p&gt;
If you just want to look at results, skip to the &lt;a href=&quot;https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html#Full%20code&quot;&gt;Full Code&lt;/a&gt; or &lt;a href=&quot;https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html#Performance%20comparison&quot;&gt;Performance comparison&lt;/a&gt;.
&lt;/p&gt;

&lt;hr /&gt;

&lt;div class=&quot;note&quot; id=&quot;org1d53654&quot;&gt;
&lt;p&gt;
Since I originally wrote this article (unpublished) on January of the same solar year, I&#39;ve come up with yet another solution.
&lt;/p&gt;

&lt;p&gt;
I&#39;ll also try to upload a video of this at some point.
&lt;/p&gt;

&lt;p&gt;
This blog post also has a sequel that I&#39;ll upload soon! &lt;i&gt;&amp;#x2013; 2024-12-24&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;https://17070415.xyz/blog/selective-org-inline-image-toggle.html&quot;&gt;Here it is&lt;/a&gt; &lt;i&gt;&amp;#x2013; 2024-01-09&lt;/i&gt;
&lt;/p&gt;

&lt;/div&gt;

&lt;hr /&gt;
&lt;div id=&quot;outline-container-Prerequisites&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Prerequisites&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mpv-player/mpv&quot;&gt;mpv&lt;/a&gt; installed
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;mpv will essentially act as a daemon that we can write text to and return control quickly to emacs&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;*nix operating system 
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;(this might work on windows, untested; windows works a bit differently with pipes)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;An audio file&lt;/li&gt;
&lt;li&gt;(optional) emacs &lt;a href=&quot;https://github.com/rbanffy/selectric-mode/&quot;&gt;selectric-mode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Why%20use%20IPC%20for%20this%3F&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Why%20use%20IPC%20for%20this%3F&quot;&gt;Why use IPC for this?&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Why%20use%20IPC%20for%20this%3F&quot;&gt;
&lt;p&gt;
Emacs is mainly single threaded&lt;sup&gt;&lt;a id=&quot;fnr.1&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html#fn.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. So even though emacs has &lt;code&gt;(play-sound)&lt;/code&gt;, this will block, locking up emacs for the duration of the sound.
&lt;/p&gt;

&lt;p&gt;
Much of parallelism in emacs boils down to forking a process and sending commands to it.
&lt;/p&gt;

&lt;p&gt;
That&#39;s what &lt;code&gt;selectric-mode&lt;/code&gt; does. &lt;a href=&quot;https://github.com/rbanffy/selectric-mode/blob/1840de71f7414b7cd6ce425747c8e26a413233aa/selectric-mode.el#L50-L51&quot;&gt;It calls&lt;/a&gt; 
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;start-process &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*Messages*&quot;&lt;/span&gt; nil &lt;span style=&quot;color: #677691;&quot;&gt;&quot;aplay&quot;&lt;/span&gt; sound-file-name&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And hey, it works. Play a sound a file from a different process and the user is back in control in emacs.
&lt;/p&gt;

&lt;p&gt;
But forking processes is expensive. It costs both time, and memory. What&#39;s more&amp;#x2013;we&#39;re just playing the same sound. Do we really need to start a process again and again?
&lt;/p&gt;

&lt;p&gt;
My computer couldn&#39;t handle selectric very well when I first used it years ago. I felt this when I was using a selectric-mode on a pentium core processor&amp;#x2026;.It&#39;s runs okay now, but my computer still gets very hot. No one has worked on the performance of it and the author has not responded to issues.
&lt;/p&gt;

&lt;p&gt;
Looking up playing audio online with emacs shows people mostly using &lt;code&gt;aplay&lt;/code&gt; or &lt;code&gt;play&lt;/code&gt; however.
&lt;/p&gt;

&lt;p&gt;
Couldn&#39;t we just decouple the caller (emacs) from the receiver (thing that plays audio), and keep the receiver alive?
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Thread%20Detour&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Thread%20Detour&quot;&gt;Thread Detour&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Thread%20Detour&quot;&gt;
&lt;p&gt;
Before diving into the daemon approach, I wanted to try threads.
&lt;/p&gt;

&lt;p&gt;
So instead of &lt;code&gt;(start-process ...)&lt;/code&gt; on the main thread, we can instead move that off to another thread. This frees up the command loop&lt;sup&gt;&lt;a id=&quot;fnr.2&quot; class=&quot;footref&quot; href=&quot;https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html#fn.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; from starting the process.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; selectric-mode
  &lt;span style=&quot;color: #81A1C1;&quot;&gt;:config&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defvar&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/typewriter-enabled&lt;/span&gt; nil&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/threaded-sound&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;()&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;make-thread #&#39;selectric-move&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/toggle-typewriter&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;()&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interactive&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/typewriter-enabled &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;not jwow/typewriter-enabled&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;add-hook &#39;post-command-hook #&#39;jwow/threaded-sound&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;remove-hook &#39;post-command-hook #&#39;jwow/threaded-sound&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;

  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Now bind the key to a keymap, since I use xfk I bound it like so
&lt;/span&gt;  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;(define-key xah-fly-leader-key-map  (kbd &quot;; b&quot;) #&#39;jwow/toggle-typewriter)
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;code&gt;M-x jwow/toggle-typewriter&lt;/code&gt; to toggle.
&lt;/p&gt;

&lt;p&gt;
This solves the blocking issue. I was able to type continuously, holding down a key for 30 seconds without lag.
&lt;/p&gt;

&lt;p&gt;
But the CPU was still high. See &lt;a href=&quot;https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html#Performance%20comparison&quot;&gt;Performance comparison&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
That&#39;s because starting a process each time was expensive. What would help was a long running process with the audio already loaded in memory. Something we could control, like mpv.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-MPV%20Approach&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;MPV%20Approach&quot;&gt;MPV Approach&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-MPV%20Approach&quot;&gt;
&lt;p&gt;
The idea is taken from wasamasa&#39;s &lt;a href=&quot;https://depp.brause.cc/chip8.el/&quot;&gt;chip8.el&lt;/a&gt;: use mpv as a daemon and feed it messages from emacs. Emacs regains control and does other logic while the audio plays.
&lt;/p&gt;

&lt;p&gt;
I first heard about this approach from &lt;a href=&quot;https://emacsconf.org/2020/talks/27/&quot;&gt;his emacsconf talk&lt;/a&gt;. I tried the code, but it doesn&#39;t work anymore because mpv dropped the &lt;code&gt;--input-file&lt;/code&gt; command option.
&lt;/p&gt;

&lt;p&gt;
Eventually I stumbled onto other flags, like &lt;code&gt;--input-ipc-server&lt;/code&gt;. And the mpv package, &lt;code&gt;empv.el&lt;/code&gt;, takes a similar approach in creating the socket now. In my case it&#39;s a unix socket file. 
&lt;/p&gt;

&lt;p&gt;
All that&#39;s left is for emacs to send messages through the socket. Of course, emacs has a native API for that: &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/elisp/Network-Processes.html&quot;&gt;Network Processes&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Once we have this process that acts as a wrapper for the socket, we simply talk to the process with &lt;code&gt;(process-send-string process-reference string)&lt;/code&gt;. Would it work?
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Code%2C%20step%20by%20step&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Code%2C%20step%20by%20step&quot;&gt;Code, step by step&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Code%2C%20step%20by%20step&quot;&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-First%2C%20get%20selectric-mode&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;First%2C%20get%20selectric-mode&quot;&gt;First, get selectric-mode&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-First%2C%20get%20selectric-mode&quot;&gt;
&lt;p&gt;
Most readers by now will be familiar with use-package. If you have melpa as a repository you can simply run:
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org83db2d3&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; selectric-mode&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;selectric-mode 1&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Run%20mpv%20with%20a%20socket&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Run%20mpv%20with%20a%20socket&quot;&gt;Run mpv with a socket&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Run%20mpv%20with%20a%20socket&quot;&gt;
&lt;p&gt;
Now let&#39;s get a socket so we can remote control &lt;code&gt;mpv&lt;/code&gt;
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org52a46ec&quot;&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/mpv-audio-file &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;selectric-audio-file
                                 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;expand-file-name
                                  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;%s/../selectric-move.wav&quot;&lt;/span&gt;
                                          &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;find-library-name &lt;span style=&quot;color: #677691;&quot;&gt;&quot;selectric-mode&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                            &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;message selectric-audio-file&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/unix-socket-file &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;expand-file-name &lt;span style=&quot;color: #677691;&quot;&gt;&quot;~/ipc-socket&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This is the process
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defvar&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;mpv-process&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/start-mpv-with-socket&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;socket-file audio-file&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; mpv-process
        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Note that if you have a config, that might have different settings than how the process is started The
&lt;/span&gt;        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;options are more verbose here because I have defaults that I&#39;m overriding
&lt;/span&gt;        &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;start-process &lt;span style=&quot;color: #677691;&quot;&gt;&quot;mpv&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*mpv*&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;mpv&quot;&lt;/span&gt;
                       &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--no-video&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--loop-playlist=no&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--pause&quot;&lt;/span&gt;
                       &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Otherwise the *mpv* buffer gets really full 
&lt;/span&gt;                       &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--no-terminal&quot;&lt;/span&gt;
                       &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--keep-open&quot;&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--input-ipc-server=%s&quot;&lt;/span&gt; socket-file&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                       audio-file&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;jwow/start-mpv-with-socket jwow/unix-socket-file jwow/mpv-audio-file&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Finally%2C%20connect%20to%20the%20socket&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Finally%2C%20connect%20to%20the%20socket&quot;&gt;Finally, connect to the socket&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Finally%2C%20connect%20to%20the%20socket&quot;&gt;
&lt;p&gt;
Note the use of &lt;code&gt;make-network-process&lt;/code&gt;. This is how we wrap the socket. By the time I was done with this code and looked at &lt;code&gt;empv.el&lt;/code&gt;
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot; id=&quot;org9dbcbd1&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This must be run after the mpv process has started
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This is because we connect to that process
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/socket-process 
      &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;make-network-process
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:name&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;socket-client&quot;&lt;/span&gt;
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:buffer&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*socket-output*&quot;&lt;/span&gt;
       &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Ensure that we are talking through a unix socket using &#39;local
&lt;/span&gt;       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:family&lt;/span&gt; &#39;local
       &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Usually this is a protocol name but 
&lt;/span&gt;       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:service&lt;/span&gt; jwow/unix-socket-file&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;selectric-type-sound&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;The &#92;n is important, otherwise mpv will not recognize the command. Commands apparently must be terminated with a new line.
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;process-send-string jwow/socket-process &lt;span style=&quot;color: #677691;&quot;&gt;&quot;seek -10; cycle pause&#92;n&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Performance%20comparison&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Performance%20comparison&quot;&gt;Performance comparison&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Performance%20comparison&quot;&gt;
&lt;p&gt;
For this section, I just looked at the graph from gnome system monitor. I also didn&#39;t type for the same duration in each of the three approaches as there was enough data.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;Without any sound&lt;/b&gt;
&lt;/p&gt;

&lt;figure id=&quot;org30d4689&quot;&gt;
&lt;img src=&quot;file:///home/furaro/src/my-site/src/content/data/28/5fd737-fdf0-4371-a1c7-bb75ce4cc55d/2025-01-01_11-14.png&quot; alt=&quot;2025-01-01_11-14.png&quot; width=&quot;100%&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 1: &lt;/span&gt;15% CPU normally&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
&lt;b&gt;Using plain selectric mode:&lt;/b&gt;
&lt;/p&gt;

&lt;figure id=&quot;org31a9911&quot;&gt;
&lt;img src=&quot;file:///home/furaro/src/my-site/src/content/data/28/5fd737-fdf0-4371-a1c7-bb75ce4cc55d/Screenshot%20From%202024-12-26%2006-58-29.png&quot; alt=&quot;Screenshot From 2024-12-26 06-58-29.png&quot; width=&quot;100%&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 2: &lt;/span&gt;55-60% CPU without changes&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
&lt;b&gt;Using threads:&lt;/b&gt;
&lt;/p&gt;

&lt;figure id=&quot;org4b26b0a&quot;&gt;
&lt;img src=&quot;file:///home/furaro/src/my-site/src/content/data/28/5fd737-fdf0-4371-a1c7-bb75ce4cc55d/clipboard-20241231T014409.png&quot; alt=&quot;clipboard-20241231T014409.png&quot; width=&quot;100%&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 3: &lt;/span&gt;40% CPU using threads&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
&lt;b&gt;Using mpv:&lt;/b&gt;
&lt;/p&gt;

&lt;figure id=&quot;org9568392&quot;&gt;
&lt;img src=&quot;file:///home/furaro/src/my-site/src/content/data/28/5fd737-fdf0-4371-a1c7-bb75ce4cc55d/Screenshot%20From%202024-12-26%2007-07-46.png&quot; alt=&quot;Screenshot From 2024-12-26 07-07-46.png&quot; width=&quot;100%&quot; /&gt;

&lt;figcaption&gt;&lt;span class=&quot;figure-number&quot;&gt;Figure 4: &lt;/span&gt;20% CPU using mpv&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
Although the screenshots are from different days, and therefore slightly different state on my computer, these results
tend to hold regardless. I was happy enough with my approach, but I won&#39;t pretend it&#39;s perfect.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Issues%20in%20the%20mpv%20approach&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Issues%20in%20the%20mpv%20approach&quot;&gt;Issues in the mpv approach&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Issues%20in%20the%20mpv%20approach&quot;&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-What%20if%20you%20wanted%20to%20play%20multiple%20files%20at%20once%3F&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;What%20if%20you%20wanted%20to%20play%20multiple%20files%20at%20once%3F&quot;&gt;What if you wanted to play multiple files at once?&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-What%20if%20you%20wanted%20to%20play%20multiple%20files%20at%20once%3F&quot;&gt;
&lt;p&gt;
An mpv instance &lt;b&gt;can only play one audio file at a time&lt;/b&gt; (as far as I know). This either means you spin up multiple processes of mpv, or you find some kind of process that can do audio mixing. Like a synth, or a DAW which uses synths. (Sorry if I mess up the technical terms, audio experts)
&lt;/p&gt;

&lt;p&gt;
I don&#39;t know too much about audio so maybe there&#39;s a lightweight way to do this. For what it&#39;s worth, something mixes down everything in realtime into ALSA, so there&#39;s probably a way.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Audio%20starts%20and%20stops&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Audio%20starts%20and%20stops&quot;&gt;Audio starts and stops&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Audio%20starts%20and%20stops&quot;&gt;
&lt;p&gt;
The two commands sent to selectric are &lt;code&gt;seek -10; cycle pause&#92;n&lt;/code&gt;. In the middle of playing, mpv will seek back 10 seconds, meaning it stops playing the current file.
&lt;/p&gt;

&lt;p&gt;
This stems from the lack of mixing functionality.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Type%20sound%20is%20too%20loud&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Type%20sound%20is%20too%20loud&quot;&gt;Type sound is too loud&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Type%20sound%20is%20too%20loud&quot;&gt;
&lt;p&gt;
Sounds like a gun. The sound files themselves may need to be modified.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Can%20we%20get%20the%20CPU%20lower%3F&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;Can%20we%20get%20the%20CPU%20lower%3F&quot;&gt;Can we get the CPU lower?&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-Can%20we%20get%20the%20CPU%20lower%3F&quot;&gt;
&lt;p&gt;
Making a sound doesn&#39;t seem like it should cost so much.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Exploring%20more&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Exploring%20more&quot;&gt;Exploring more&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Exploring%20more&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;In 2024-12-24, I got excited by another general solution. &lt;a href=&quot;https://17070415.xyz/blog/snd-selectric-mode-v0.0.1-released.html&quot;&gt;Join me there&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mpv-player/mpv/blob/master/etc/input.conf&quot;&gt;mpv has many options&lt;/a&gt; and you can drive it completely by ipc (I think!). Try grabbing data from the mpv process too!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/isamert/empv.el/blob/60956a07c40e0a9ac0df5a6e57694b62f7fce041/empv.el#L79&quot;&gt;empv.el drives mpv using ipc as well&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If the process you want to communicate with registers itself with D-Bus, you can try emacs&#39;s D-Bus API. To debug and find message signatures, I&#39;ve had good luck with the D-Spy tool. Things are a bit cryptic since many programs have lacking documentation on how they are controlled via dbus.&lt;/li&gt;
&lt;li&gt;In the example here, I only changed the execution flow when when a user was typing. I didn&#39;t change how the move sound worked in the typewriter. You can actually try other commands to drive mpv remotely here: &lt;a href=&quot;https://github.com/mpv-player/mpv/blob/master/DOCS/man/input.rst&quot;&gt;https://github.com/mpv-player/mpv/blob/master/DOCS/man/input.rst&lt;/a&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;It&#39;d be interesting to try &lt;code&gt;loadfile &amp;lt;url&amp;gt; [&amp;lt;flags&amp;gt; [&amp;lt;index&amp;gt; [&amp;lt;options&amp;gt;]]]&lt;/code&gt; to load other files into mpv and cycle through them. Would it be performant?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;I tried out &lt;a href=&quot;https://github.com/bojanserafimov/midio&quot;&gt;midio&lt;/a&gt; which may do what you&#39;re looking for. From my understanding, you send midi commands to fluidsynth, which is kind of similar to what we&#39;re doing here.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-Full%20code&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;Full%20code&quot;&gt;Full code&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-Full%20code&quot;&gt;
&lt;p&gt;
Copy and paste into a scratch buffer and &lt;code&gt;M-x eval-buffer&lt;/code&gt;!
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-elisp&quot;&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;I&#39;m using selectric mode, but you can try out the code without it. 
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Just make sure you have an audio file you can use
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;And call (process-send-string jwow/socket-process &quot;seek -10; cycle pause&#92;n&quot;)
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;use-package&lt;/span&gt; selectric-mode&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;selectric-mode 1&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/mpv-audio-file &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;selectric-audio-file
                                 &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;expand-file-name
                                  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;%s/../selectric-move.wav&quot;&lt;/span&gt;
                                          &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;find-library-name &lt;span style=&quot;color: #677691;&quot;&gt;&quot;selectric-mode&quot;&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;
                            &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;message selectric-audio-file&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/unix-socket-file &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;expand-file-name &lt;span style=&quot;color: #677691;&quot;&gt;&quot;~/ipc-socket&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This is the process
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defvar&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;mpv-process&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;jwow/start-mpv-with-socket&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;socket-file audio-file&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;
  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; mpv-process
        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Note that if you have a config, that might have different settings than how the process is started The
&lt;/span&gt;        &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;options are more verbose here because I have defaults that I&#39;m overriding
&lt;/span&gt;        &lt;span style=&quot;color: #b0b1a3;&quot;&gt;(&lt;/span&gt;start-process &lt;span style=&quot;color: #677691;&quot;&gt;&quot;mpv&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*mpv*&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;mpv&quot;&lt;/span&gt;
                       &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--no-video&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--loop-playlist=no&quot;&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--pause&quot;&lt;/span&gt;
                       &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Otherwise the *mpv* buffer gets really full 
&lt;/span&gt;                       &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--no-terminal&quot;&lt;/span&gt;
                       &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--keep-open&quot;&lt;/span&gt; &lt;span style=&quot;color: #97b098;&quot;&gt;(&lt;/span&gt;format &lt;span style=&quot;color: #677691;&quot;&gt;&quot;--input-ipc-server=%s&quot;&lt;/span&gt; socket-file&lt;span style=&quot;color: #97b098;&quot;&gt;)&lt;/span&gt;
                       audio-file&lt;span style=&quot;color: #b0b1a3;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;jwow/start-mpv-with-socket jwow/unix-socket-file jwow/mpv-audio-file&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This must be run after the mpv process has started
&lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;This is because we connect to that process
&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;setq&lt;/span&gt; jwow/socket-process 
      &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;make-network-process
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:name&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;socket-client&quot;&lt;/span&gt;
       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:buffer&lt;/span&gt; &lt;span style=&quot;color: #677691;&quot;&gt;&quot;*socket-output*&quot;&lt;/span&gt;
       &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Ensure that we are talking through a unix socket using &#39;local
&lt;/span&gt;       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:family&lt;/span&gt; &#39;local
       &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;Usually this is a protocol name but 
&lt;/span&gt;       &lt;span style=&quot;color: #81A1C1;&quot;&gt;:service&lt;/span&gt; jwow/unix-socket-file&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #8c8c8c;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #FFFFFF; font-weight: bold;&quot;&gt;selectric-type-sound&lt;/span&gt; &lt;span style=&quot;color: #93a8c6;&quot;&gt;()&lt;/span&gt;
  &lt;span style=&quot;color: #677691;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #677691;&quot;&gt;The &#92;n is important, otherwise mpv will not recognize the command. Commands apparently must be terminated with a new line.
&lt;/span&gt;  &lt;span style=&quot;color: #93a8c6;&quot;&gt;(&lt;/span&gt;process-send-string jwow/socket-process &lt;span style=&quot;color: #677691;&quot;&gt;&quot;seek -10; cycle pause&#92;n&quot;&lt;/span&gt;&lt;span style=&quot;color: #93a8c6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8c8c8c;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.1&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html#fnr.1&quot; role=&quot;doc-backlink&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
Threading capabilities have been added actually &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#Threads&quot;&gt;elisp#Threads&lt;/a&gt;. 
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a id=&quot;fn.2&quot; class=&quot;footnum&quot; href=&quot;https://17070415.xyz/blog/interprocess-communication-(ipc)-in-emacs-for-typing-sounds.html#fnr.2&quot; role=&quot;doc-backlink&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot; role=&quot;doc-footnote&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
The &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#Command-Loop&quot;&gt;command loop&lt;/a&gt; is what gives you the feeling of control&amp;#x2013;it listens to your input. If this main thread was busy doing X for a while, you wouldn&#39;t be able to get your next keystroke on the buffer until emacs finished doing X.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
</feed>
