<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>https://www.alcarney.me/</id>
  <title>Alex Carney | Blog</title>
  <updated>2026-03-24T21:32:27.633048+00:00</updated>
  <link href="https://www.alcarney.me/" />
  <link href="https://www.alcarney.me/blog/atom.xml" rel="self" />
  <author>
    <name>Alex Carney</name>
  </author>
  <generator uri="https://www.sphinx-doc.org/en/master/" version="8">Sphinx</generator>
  
  <entry>
    <id>https://www.alcarney.me/blog/2026/indexing-info-manuals/</id>
    <link href="https://www.alcarney.me/blog/2026/indexing-info-manuals" rel="alternate" />
    <published>2026-03-09T00:00:00+00:00</published>
    <updated>2026-03-09T00:00:00+00:00</updated>
    <title>Indexing Info Manuals</title>
    <content type="html">
      &lt;section id=&#34;indexing-info-manuals&#34;&gt;
&lt;h1&gt;Indexing Info Manuals&lt;a class=&#34;headerlink&#34; href=&#34;#indexing-info-manuals&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;I’ve been working around this issue for a while now.&lt;/p&gt;
&lt;p&gt;By default, the &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;h&lt;/kbd&gt; &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;i&lt;/kbd&gt; binding in Emacs opens the list of available
&lt;a class=&#34;reference external&#34; href=&#34;https://en.wikipedia.org/wiki/Info_(Unix)&#34;&gt;info manuals&lt;/a&gt; for you to browse through.
Unfortunately, I would only be shown manuals that had been included with third-party Emacs packages like
&lt;a class=&#34;reference external&#34; href=&#34;https://protesilaos.com/emacs/denote&#34;&gt;denote&lt;/a&gt;.
System provided manuals, such as the one for Emacs itself, were nowhere to be seen:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;File: dir,        Node: Top       This is the top of the INFO tree

  This (the Directory node) gives a menu of major topics.
  Typing &amp;quot;q&amp;quot; exits, &amp;quot;H&amp;quot; lists all Info commands, &amp;quot;d&amp;quot; returns here,
  &amp;quot;h&amp;quot; gives a primer for first-timers,
  &amp;quot;mEmacs&amp;lt;Return&amp;gt;&amp;quot; visits the Emacs manual, etc.

  In Emacs, you can click mouse button 2 on a menu item or cross reference
  to select it.

* Menu:

Emacs
* Denote Sequence: (denote-sequence).
                                Sequence notes or Folgezettel with Denote.
* Denote: (denote).             Simple notes with an efficient file-naming
                                  scheme.
* Eat: (eat).                   Emulate A Terminal.
* Embark: (embark).             Emacs Mini-Buffer Actions Rooted in Keymaps.
* Forge: (forge).               Access Git Forges from Magit.
* Ghub: (ghub).                 Client library for the Github API.
* Magit: (magit).               Using Git from Emacs with Magit.
* Magit-Section: (magit-section).
                                Use Magit sections in your own packages.
* Orderless: (orderless).       Completion style for matching regexps in any
                                  order.
* Tempel: (tempel).             Simple templates for Emacs.
* Transient: (transient).       Transient Commands.
* With-Editor: (with-editor).   Using the Emacsclient as $EDITOR.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, I could clearly see files like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/usr/share/info/emacs.info.gz&lt;/span&gt;&lt;/code&gt; on my system and I could access specific info nodes by evaluating expressions like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;(info&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;&amp;quot;(emacs)Displaying&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;Buffers&amp;quot;)&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I’ve now reached the point where it’s bugging me enough to actually dig in and try to figure out what is going on.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;dir-files&#34;&gt;
&lt;h2&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; files&lt;a class=&#34;headerlink&#34; href=&#34;#dir-files&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It turns out that the buffer you see when invoking &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;h&lt;/kbd&gt; &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;i&lt;/kbd&gt; is assembled from all the places Emacs is configured to search for info manuals (via the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Info-directory-list&lt;/span&gt;&lt;/code&gt; variable).
Each directory is expected to contain a file called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; that would provide a list of all info manuals in the directory.
For example in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote&lt;/span&gt;&lt;/code&gt; package:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;~/.emacs.d/elpa/denote-4.1.3/ $ cat ./dir

This is the file .../info/dir, which contains the
topmost node of the Info hierarchy, called (dir)Top.
The first time you invoke Info you start off looking at this node.

File: dir,    Node: Top       This is the top of the INFO tree

  This (the Directory node) gives a menu of major topics.
  Typing &amp;quot;q&amp;quot; exits, &amp;quot;H&amp;quot; lists all Info commands, &amp;quot;d&amp;quot; returns here,
  &amp;quot;h&amp;quot; gives a primer for first-timers,
  &amp;quot;mEmacs&amp;lt;Return&amp;gt;&amp;quot; visits the Emacs manual, etc.

  In Emacs, you can click mouse button 2 on a menu item or cross reference
  to select it.

* Menu:

Emacs misc features
* Denote: (denote).             Simple notes with an efficient file-naming
                                  scheme.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;where &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;(denote).&lt;/span&gt;&lt;/code&gt; instructs Emacs to look for a file called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.info&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Armed with this knowledge, you would expect to find a similar file in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/usr/share/info&lt;/span&gt;&lt;/code&gt;, but unsurprsingly, it’s missing in my case.
The obvious solution then, would be to ensure that a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; file is present in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/usr/share/info&lt;/span&gt;&lt;/code&gt; directory however, my Linux flavour of choice (&lt;a class=&#34;reference external&#34; href=&#34;https://getaurora.dev/en/&#34;&gt;Aurora&lt;/a&gt;) makes this a bit more interesting:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ touch /usr/share/info/dir
touch: cannot touch &amp;#39;/usr/share/info/dir&amp;#39;: Read-only file system
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Interestingly however, this didn’t turn out to be a big deal as manually editing the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; file provided by denote I proved to myself that you didn’t actually need the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;.info&lt;/span&gt;&lt;/code&gt; file to be in the same folder as the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; file, as long as it was &lt;em&gt;somewhere&lt;/em&gt; listed in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Info-directory-list&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-diff notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt; * Menu:

&lt;span class=&#34;w&#34;&gt; &lt;/span&gt; Emacs misc features
&lt;span class=&#34;gi&#34;&gt;+ * Emacs: (emacs).               The Emacs manual.&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt; * Denote: (denote).             Simple notes with an efficient file-naming
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;                                 scheme.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now all that’s left is to build a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; file indexing all the missing manuals.&lt;/p&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;The “correct” way to do this is is to use the
&lt;a class=&#34;reference external&#34; href=&#34;https://www.gnu.org/software/texinfo/manual/texinfo/html_node/Invoking-install_002dinfo.html&#34;&gt;install-info&lt;/a&gt;
command from the
&lt;a class=&#34;reference external&#34; href=&#34;https://www.gnu.org/software/texinfo/&#34;&gt;texinfo&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;But since I don’t have the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;texinfo&lt;/span&gt;&lt;/code&gt; package installed I thought it would be fun to write a small Python script to do the same.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;build-info-dir-py&#34;&gt;
&lt;h2&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;build-info-dir.py&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#build-info-dir-py&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;build-info-dir.py&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;build-info-dir.py &amp;lt;directory&amp;gt; &amp;lt;output&amp;gt;&lt;/span&gt;

&lt;span class=&#34;sd&#34;&gt;Index all info manuals in a given directory and produce a ``dir`` index file.&lt;/span&gt;
&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;argparse&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;gzip&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;pathlib&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;sys&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As we can see from the examples above, the format of a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; file is quite straightforward, the hardest part is figuring out the title and description of each manual along with which sections to group them under.&lt;/p&gt;
&lt;p&gt;The &lt;a class=&#34;reference external&#34; href=&#34;https://www.gnu.org/software/texinfo/manual/texinfo/html_node/Installing-Dir-Entries.html&#34;&gt;texinfo documentation&lt;/a&gt; states that manuals export specific info nodes to the top-level &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; using the following syntax (example taken from the info file for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote&lt;/span&gt;&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;INFO-DIR-SECTION Emacs misc features
START-INFO-DIR-ENTRY
* Denote: (denote).     Simple notes with an efficient file-naming scheme.
END-INFO-DIR-ENTRY
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which can be extracted as follows:&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;build-info-dir.py&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DIR_SECTION&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;INFO-DIR-SECTION &amp;quot;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;extract_dir_nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;dict&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;dict&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;open_info_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readlines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;decode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;ignore&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rstrip&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;startswith&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DIR_SECTION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;section&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DIR_SECTION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;

            &lt;span class=&#34;k&#34;&gt;elif&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;START-INFO-DIR-ENTRY&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
                &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;

            &lt;span class=&#34;k&#34;&gt;elif&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;END-INFO-DIR-ENTRY&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setdefault&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[])&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extend&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;

            &lt;span class=&#34;k&#34;&gt;elif&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;isinstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
                &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;open_info_file&lt;/span&gt;&lt;/code&gt; is a separate helper function as info manuals can be gzipped.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;build-info-dir.py&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;open_info_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;.gz&amp;quot;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;suffix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gzip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;All that’s left is the infrastructure to find and aggregate the result of each info file.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;build-info-dir.py&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;index_info_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;dict&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info_dir&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;glob&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;*.info*&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
        &lt;span class=&#34;c1&#34;&gt;# Some manuals are split into mutliple files, we only need to index the top-level file&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;info-&amp;quot;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;

        &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Indexing &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;...&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extract_dir_nodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;items&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setdefault&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[])&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extend&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;lines&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x1f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;File: dir&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Node: Top&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;This is the top of the INFO tree&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;* Menu:&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;items&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;lines&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;lines&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extend&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After &lt;strong&gt;much&lt;/strong&gt; trial and error, I eventually figured out that the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dir&lt;/span&gt;&lt;/code&gt; file &lt;strong&gt;must&lt;/strong&gt; contain&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;the special character &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;quot;\x1f&amp;quot;&lt;/span&gt;&lt;/code&gt; (rendered as &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;^_&lt;/span&gt;&lt;/code&gt; by Emacs),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;File:&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;dir...&lt;/span&gt;&lt;/code&gt; header and&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;Menu:&lt;/span&gt;&lt;/code&gt; string&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;in order to be parsed correctly.&lt;/p&gt;
&lt;p&gt;Other than that, it appears like you can add any other text you’d like and it would be rendered in the final &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;*info*&lt;/span&gt;&lt;/code&gt; buffer.
I was tempted to add a count of all the manuals found, but since the file we’re generating here isn’t the only source, any counts are unlikely to be accurate.&lt;/p&gt;
&lt;p&gt;Finally, to make the script useful let’s wrap it in a simple CLI interface.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;build-info-dir.py&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argparse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ArgumentParser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_argument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;infodir&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pathlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_argument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;-o&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;--output&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argparse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FileType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;w&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse_args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;index_info_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;infodir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;output&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;building-and-using-the-index&#34;&gt;
&lt;h2&gt;Building and Using the Index&lt;a class=&#34;headerlink&#34; href=&#34;#building-and-using-the-index&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To get Emacs to use the the index, we of course have to generate it:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ mkdir -p ~/.local/share/info
$ python build-info-dir.py /usr/share/info -o ~/.local/share/info/dir
...
Indexing url.info.gz...
Indexing use-package.info.gz...
Indexing vhdl-mode.info.gz...
Indexing vip.info.gz...
Indexing viper.info.gz...
Indexing vtable.info.gz...
Indexing widget.info.gz...
Indexing wisent.info.gz...
Indexing woman.info.gz...
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And make sure Emacs is configured to search the folder&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;init.el&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-elisp notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;add-to-list&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;&amp;#39;Info-directory-list&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;             &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;concat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;getenv&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;HOME&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;/.local/share/info/&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;style&gt;
  #info-dir { max-height: 350px; overflow: scroll; }
&lt;/style&gt;&lt;div class=&#34;highlight-none notranslate&#34; id=&#34;info-dir&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;File: dir    Node: Top       This is the top of the INFO tree

* Menu:

Software development
* As: (as).                     The GNU assembler.
* Gas: (as).                    The GNU assembler.
* Bfd: (bfd).                   The Binary File Descriptor library.
* Binutils: (binutils).         The GNU binary utilities.
* bison: (bison).       GNU parser generator (Yacc replacement).
* Cpp: (cpp).                  The GNU C preprocessor.
* Cpplib: (cppinternals).      Cpplib internals.
* CTF: (ctf-spec).         The CTF file format.
* gcc: (gcc).                  The GNU Compiler Collection.
* g++: (gcc).                  The GNU C++ compiler.
* gcov: (gcc) Gcov.            ‘gcov’--a test coverage program.
* gcov-tool: (gcc) Gcov-tool.  ‘gcov-tool’--an offline gcda profile processing program.
* gcov-dump: (gcc) Gcov-dump.  ‘gcov-dump’--an offline gcda and gcno profile dump tool.
* lto-dump: (gcc) lto-dump.    ‘lto-dump’--Tool for
* flex: (flex).      Fast lexical analyzer generator (lex replacement).
dumping LTO object files.
* Gccgo: (gccgo).           A GCC-based compiler for the Go language
* gccinstall: (gccinstall).    Installing the GNU Compiler Collection.
* gccint: (gccint).            Internals of the GNU Compiler Collection.
* GNUstep Make: (gnustep-make).         The GNUstep build system.
* gprof: (gprof).                Profiling your program&amp;#39;s execution
* Ld: (ld).                       The GNU linker.
* Ld-Internals: (ldint).     The GNU linker internals.
* Make: (make).            Remake files automatically.
* SFrame: (sframe-spec).         The Simple Frame format.
Basics
* Bash: (bash).                     The GNU Bourne-Again SHell.
* Coreutils: (coreutils).       Core GNU (file, text, shell) utilities.
* Common options: (coreutils)Common options.
* File permissions: (coreutils)File permissions.  Access modes.
* Date input formats: (coreutils)Date input formats.
* Ed: (ed).                     The GNU line editor
* Finding files: (find).        Operating on files matching certain criteria.
* Time: (time).                  GNU time utility.
Math
* bc: (bc).                    An arbitrary precision calculator language.
Individual utilities
* addr2line: (binutils)addr2line. Convert addresses to file and line.
* ar: (binutils)ar.               Create, modify, and extract from archives.
* c++filt: (binutils)c++filt.          Filter to demangle encoded C++ symbols.
* cxxfilt: (binutils)c++filt.     MS-DOS name for c++filt.
* dlltool: (binutils)dlltool.          Create files needed to build and use DLLs.
* nm: (binutils)nm.               List symbols from object files.
* objcopy: (binutils)objcopy.          Copy and translate object files.
* objdump: (binutils)objdump.     Display information from object files.
* ranlib: (binutils)ranlib.       Generate index to archive contents.
* readelf: (binutils)readelf.          Display the contents of ELF format files.
* size: (binutils)size.           List section sizes and total size.
* strings: (binutils)strings.     List printable strings from files.
* strip: (binutils)strip.         Discard symbols.
* elfedit: (binutils)elfedit.     Update ELF header and property of ELF files.
* windmc: (binutils)windmc.    Generator for Windows message resources.
* windres: (binutils)windres.          Manipulate Windows resources.
* arch: (coreutils)arch invocation.             Print machine hardware name.
* b2sum: (coreutils)b2sum invocation.           Print or check BLAKE2 digests.
* base32: (coreutils)base32 invocation.         Base32 encode/decode data.
* base64: (coreutils)base64 invocation.         Base64 encode/decode data.
* basename: (coreutils)basename invocation.     Strip directory and suffix.
* basenc: (coreutils)basenc invocation.         Encoding/decoding of data.
* cat: (coreutils)cat invocation.               Concatenate and write files.
* chcon: (coreutils)chcon invocation.           Change SELinux CTX of files.
* chgrp: (coreutils)chgrp invocation.           Change file groups.
* chmod: (coreutils)chmod invocation.           Change access permissions.
* chown: (coreutils)chown invocation.           Change file owners and groups.
* chroot: (coreutils)chroot invocation.         Specify the root directory.
* cksum: (coreutils)cksum invocation.           Print POSIX CRC checksum.
* comm: (coreutils)comm invocation.             Compare sorted files by line.
* cp: (coreutils)cp invocation.                 Copy files.
* csplit: (coreutils)csplit invocation.         Split by context.
* cut: (coreutils)cut invocation.               Print selected parts of lines.
* date: (coreutils)date invocation.             Print/set system date and time.
* dd: (coreutils)dd invocation.                 Copy and convert a file.
* df: (coreutils)df invocation.                 Report file system usage.
* dir: (coreutils)dir invocation.               List directories briefly.
* dircolors: (coreutils)dircolors invocation.   Color setup for ls.
* dirname: (coreutils)dirname invocation.       Strip last file name component.
* du: (coreutils)du invocation.                 Report file usage.
* echo: (coreutils)echo invocation.             Print a line of text.
* env: (coreutils)env invocation.               Modify the environment.
* expand: (coreutils)expand invocation.         Convert tabs to spaces.
* expr: (coreutils)expr invocation.             Evaluate expressions.
* factor: (coreutils)factor invocation.         Print prime factors
* false: (coreutils)false invocation.           Do nothing, unsuccessfully.
* fmt: (coreutils)fmt invocation.               Reformat paragraph text.
* fold: (coreutils)fold invocation.             Wrap long input lines.
* groups: (coreutils)groups invocation.         Print group names a user is in.
* head: (coreutils)head invocation.             Output the first part of files.
* hostid: (coreutils)hostid invocation.         Print numeric host identifier.
* hostname: (coreutils)hostname invocation.     Print or set system name.
* id: (coreutils)id invocation.                 Print user identity.
* install: (coreutils)install invocation.       Copy files and set attributes.
* join: (coreutils)join invocation.             Join lines on a common field.
* kill: (coreutils)kill invocation.             Send a signal to processes.
* link: (coreutils)link invocation.             Make hard links between files.
* ln: (coreutils)ln invocation.                 Make links between files.
* logname: (coreutils)logname invocation.       Print current login name.
* ls: (coreutils)ls invocation.                 List directory contents.
* md5sum: (coreutils)md5sum invocation.         Print or check MD5 digests.
* mkdir: (coreutils)mkdir invocation.           Create directories.
* mkfifo: (coreutils)mkfifo invocation.         Create FIFOs (named pipes).
* mknod: (coreutils)mknod invocation.           Create special files.
* mktemp: (coreutils)mktemp invocation.         Create temporary files.
* mv: (coreutils)mv invocation.                 Rename files.
* nice: (coreutils)nice invocation.             Modify niceness.
* nl: (coreutils)nl invocation.                 Number lines and write files.
* nohup: (coreutils)nohup invocation.           Immunize to hangups.
* nproc: (coreutils)nproc invocation.           Print the number of processors.
* numfmt: (coreutils)numfmt invocation.         Reformat numbers.
* od: (coreutils)od invocation.                 Dump files in octal, etc.
* paste: (coreutils)paste invocation.           Merge lines of files.
* pathchk: (coreutils)pathchk invocation.       Check file name portability.
* pinky: (coreutils)pinky invocation.           Print information about users.
* pr: (coreutils)pr invocation.                 Paginate or columnate files.
* printenv: (coreutils)printenv invocation.     Print environment variables.
* printf: (coreutils)printf invocation.         Format and print data.
* ptx: (coreutils)ptx invocation.               Produce permuted indexes.
* pwd: (coreutils)pwd invocation.               Print working directory.
* readlink: (coreutils)readlink invocation.     Print referent of a symlink.
* realpath: (coreutils)realpath invocation.     Print resolved file names.
* rm: (coreutils)rm invocation.                 Remove files.
* rmdir: (coreutils)rmdir invocation.           Remove empty directories.
* runcon: (coreutils)runcon invocation.         Run in specified SELinux CTX.
* seq: (coreutils)seq invocation.               Print numeric sequences
* sha1sum: (coreutils)sha1sum invocation.       Print or check SHA-1 digests.
* sha2: (coreutils)sha2 utilities.              Print or check SHA-2 digests.
* shred: (coreutils)shred invocation.           Remove files more securely.
* shuf: (coreutils)shuf invocation.             Shuffling text files.
* sleep: (coreutils)sleep invocation.           Delay for a specified time.
* sort: (coreutils)sort invocation.             Sort text files.
* split: (coreutils)split invocation.           Split into pieces.
* stat: (coreutils)stat invocation.             Report file(system) status.
* stdbuf: (coreutils)stdbuf invocation.         Modify stdio buffering.
* stty: (coreutils)stty invocation.             Print/change terminal settings.
* sum: (coreutils)sum invocation.               Print traditional checksum.
* sync: (coreutils)sync invocation.             Sync files to stable storage.
* tac: (coreutils)tac invocation.               Reverse files.
* tail: (coreutils)tail invocation.             Output the last part of files.
* tee: (coreutils)tee invocation.               Redirect to multiple files.
* test: (coreutils)test invocation.             File/string tests.
* timeout: (coreutils)timeout invocation.       Run with time limit.
* touch: (coreutils)touch invocation.           Change file timestamps.
* tr: (coreutils)tr invocation.                 Translate characters.
* true: (coreutils)true invocation.             Do nothing, successfully.
* truncate: (coreutils)truncate invocation.     Shrink/extend size of a file.
* tsort: (coreutils)tsort invocation.           Topological sort.
* tty: (coreutils)tty invocation.               Print terminal name.
* uname: (coreutils)uname invocation.           Print system information.
* unexpand: (coreutils)unexpand invocation.     Convert spaces to tabs.
* uniq: (coreutils)uniq invocation.             Uniquify files.
* unlink: (coreutils)unlink invocation.         Removal via unlink(2).
* uptime: (coreutils)uptime invocation.         Print uptime and load.
* users: (coreutils)users invocation.           Print current user names.
* vdir: (coreutils)vdir invocation.             List directories verbosely.
* wc: (coreutils)wc invocation.                 Line, word, and byte counts.
* who: (coreutils)who invocation.               Print who is logged in.
* whoami: (coreutils)whoami invocation.         Print effective user ID.
* yes: (coreutils)yes invocation.               Print a string indefinitely.
* cmp: (diffutils)Invoking cmp.                 Compare 2 files byte by byte.
* diff: (diffutils)Invoking diff.               Compare 2 files line by line.
* diff3: (diffutils)Invoking diff3.             Compare 3 files line by line.
* patch: (diffutils)Invoking patch.             Apply a patch to a file.
* sdiff: (diffutils)Invoking sdiff.             Merge 2 files side-by-side.
* find: (find)Finding Files.                    Finding and acting on files.
* locate: (find)Invoking locate.                Finding files in a database.
* updatedb: (find)Invoking updatedb.            Building the locate database.
* xargs: (find)Invoking xargs.                  Operating on many files.
* awk: (gawk)Invoking Gawk.                     Text scanning and processing.
* Gawk Work Flow: (gawkworkflow)Overview.         Participating in ‘gawk’ development.
* gunzip: (gzip)Overview.                       Decompression.
* gzexe: (gzip)Overview.                        Compress executables.
* zcat: (gzip)Overview.                         Decompression to stdout.
* zdiff: (gzip)Overview.                        Compare compressed files.
* zforce: (gzip)Overview.                       Force .gz extension on files.
* zgrep: (gzip)Overview.                        Search compressed files.
* zmore: (gzip)Overview.                        Decompression output by pages.
* tar: (tar)tar invocation.                     Invoking GNU ‘tar’.
Archiving
* Cpio: (cpio).                 Copy-in-copy-out archiver to tape or disk.
* Tar: (tar).                   Making tape (or disk) archives.
* Xorrecord: (xorrecord).           Emulates CD/DVD/BD program cdrecord
* Xorriso-dd-target: (xorriso-dd-target). Device evaluator and disk image copier for GNU/Linux
* Xorriso: (xorriso).           Burns ISO 9660 on CD, DVD, BD.
* Xorrisofs: (xorrisofs).           Emulates ISO 9660 program mkisofs

* dc: (dc).                   Arbitrary precision RPN &amp;quot;Desktop Calculator&amp;quot;.
Text creation and manipulation
* Diffutils: (diffutils).       Comparing and merging files.
* Gawk: (gawk).                 A text scanning and processing language.
* Gawk Work Flow: (gawkworkflow).                 Participating in ‘gawk’ development.
* grep: (grep).                 Print lines that match patterns.
* M4: (m4).                     A powerful macro processor.
* pm-gawk: (pm-gawk).    Persistent memory version of gawk.
* sed: (sed).                   Stream EDitor.

GNU organization
* Maintaining Findutils: (find-maint).        Maintaining GNU findutils
Network applications
* awkinet: (gawkinet).          TCP/IP Internetworking With &amp;#39;gawk&amp;#39;.
GNU Gettext Utilities
* gettext: (gettext).                          GNU gettext utilities.
* autopoint: (gettext)autopoint Invocation.    Copy gettext infrastructure.
* envsubst: (gettext)envsubst Invocation.      Expand environment variables.
* gettextize: (gettext)gettextize Invocation.  Prepare a package for gettext.
* msgattrib: (gettext)msgattrib Invocation.    Select part of a PO file.
* msgcat: (gettext)msgcat Invocation.          Combine several PO files.
* msgcmp: (gettext)msgcmp Invocation.          Compare a PO file and template.
* msgcomm: (gettext)msgcomm Invocation.        Match two PO files.
* msgconv: (gettext)msgconv Invocation.        Convert PO file to encoding.
* msgen: (gettext)msgen Invocation.            Create an English PO file.
* msgexec: (gettext)msgexec Invocation.        Process a PO file.
* msgfilter: (gettext)msgfilter Invocation.    Pipe a PO file through a filter.
* msgfmt: (gettext)msgfmt Invocation.          Make MO files out of PO files.
* msggrep: (gettext)msggrep Invocation.        Select part of a PO file.
* msginit: (gettext)msginit Invocation.        Create a fresh PO file.
* msgmerge: (gettext)msgmerge Invocation.      Update a PO file from template.
* msgunfmt: (gettext)msgunfmt Invocation.      Uncompile MO file into PO file.
* msguniq: (gettext)msguniq Invocation.        Unify duplicates for PO file.
* ngettext: (gettext)ngettext Invocation.      Translate a message with plural.
* xgettext: (gettext)xgettext Invocation.      Extract strings into a PO file.
* ISO639: (gettext)Language Codes.             ISO 639 language codes.
* ISO3166: (gettext)Country Codes.             ISO 3166 country codes.
GNU Utilities
* gpg2: (gnupg).           OpenPGP encryption and signing tool.
* gpgsm: (gnupg).          S/MIME encryption and signing tool.
* gpg-agent: (gnupg).      The secret key daemon.
* dirmngr: (gnupg).        X.509 CRL and OCSP server.
* dirmngr-client: (gnupg). X.509 CRL and OCSP client.
* pinentry: (pinentry).    Securely ask for a passphrase or PIN.
Kernel
* grub2-dev: (grub2-dev).                 The GRand Unified Bootloader Dev
* GRUB2: (grub2).                 The GRand Unified Bootloader
* grub2-install: (grub2)Invoking grub2-install.    Install GRUB on your drive
* grub2-mkconfig: (grub2)Invoking grub2-mkconfig.  Generate GRUB configuration
* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub2-mkpasswd-pbkdf2.
* grub2-mkrelpath: (grub2)Invoking grub2-mkrelpath.
* grub2-mkrescue: (grub2)Invoking grub2-mkrescue.  Make a GRUB rescue image
* grub2-mount: (grub2)Invoking grub2-mount.        Mount a file system using GRUB
* grub2-probe: (grub2)Invoking grub2-probe.        Probe device information
* grub2-script-check: (grub2)Invoking grub2-script-check.
Compression
* Gzip: (gzip).                 General (de)compression of files (lzw).
Libraries
* History: (history).       The GNU history library API.
* RLuserman: (rluserman).       The GNU readline library User&amp;#39;s Manual.
* libcdio: (libcdio).           GNU Compact Disc Input, Output, and Control Library.
* libgomp: (libgomp).          GNU Offloading and Multi Processing Runtime Library.
* Source-highlight-lib: (source-highlight-lib).  Highlights contents
* Auth-source: (auth).          The Emacs auth-source library.
* CL-Lib: (cl).                 Partial Common Lisp support for Emacs Lisp.
* D-Bus: (dbus).                Using D-Bus in Emacs.
* Emacs MIME: (emacs-mime).     Emacs MIME de/composition library.
* SMTP: (smtpmail).             Emacs library for sending mail via SMTP.
* URL: (url).                   URL loading package.
* Widget: (widget).             The &amp;quot;widget&amp;quot; package used by the Emacs
                                  Customization facility.
Localization
* libchewing: (libchewing).           The libchewing reference manual.
Misc
* Liblouis: (liblouis). A braille translator and back-translator
DOS
* Mtools: (mtools).        Mtools: utilities to access DOS disks in Unix.
Editors
* nano: (nano).                 Small and friendly text editor.
Encryption
* Nettle: (nettle).             A low-level cryptographic library.
System administration
* parted: (parted).                         GNU partitioning software
* Which: (which).                               Show full path of commands.
Texinfo documentation system
* Pinfo: (pinfo).           curses based lynx-style info browser.
Utilities
* Source-highlight: (source-highlight).  Highlights contents
* ZSH: (zsh).                     The Z Shell Manual.
Emacs
* Autotype: (autotype).         Convenient features for text that you enter
                                  frequently in Emacs.
* Bovine: (bovine).             Semantic bovine parser development.
* Calc: (calc).                 Advanced desk calculator and mathematical tool.
* Dired-X: (dired-x).           Dired Extra Features.
* Ebrowse: (ebrowse).           A C++ class browser for Emacs.
* EDE: (ede).                   The Emacs Development Environment.
* Ediff: (ediff).               A visual interface for comparing and
                                  merging programs.
* EDT: (edt).                   An Emacs emulation of the EDT editor.
* Eglot: (eglot).             Language Server Protocol client for Emacs.
* EIEIO: (eieio).               An objects system for Emacs Lisp.
* EasyPG Assistant: (epa).      An Emacs user interface to GNU Privacy Guard.
* ERT: (ert).                   Emacs Lisp regression testing tool.
* Eshell: (eshell).             A command shell implemented in Emacs Lisp.
* EWW: (eww).      Emacs Web Wowser
* Flymake: (flymake).           A universal on-the-fly syntax checker.
* Forms: (forms).               Emacs package for editing data bases
                                  by filling in forms.
* Htmlfontify: (htmlfontify).   Convert source code to html.
* Ido: (ido).                   Interactively do things with buffers and files.
* Modus Themes: (modus-themes). Elegant, highly legible and customizable themes.
* PCL-CVS: (pcl-cvs).           Emacs front-end to CVS.
* RefTeX: (reftex).             Emacs support for LaTeX cross-references
                                  and citations.
* Remember: (remember).         Simple information manager for Emacs.
* Semantic: (semantic).         Source code parser library and utilities.
* SES: (ses).                   Simple Emacs Spreadsheet.
* Speedbar: (speedbar).         File/Tag summarizing utility.
* SRecode: (srecode).           Semantic template code generator.
* Todo Mode: (todo-mode).       Make and maintain todo lists.
* Transient: (transient).       Transient Commands.
* use-package: (use-package). Declarative package configuration for Emacs.
* VIP: (vip).                   An obsolete VI-emulation for Emacs.
* VIPER: (viper).               A VI-emulation mode for Emacs.
* vtable: (vtable).     Variable Pitch Tables.
* Wisent: (wisent).             Semantic Wisent parser development.
* WoMan: (woman).               Browse UN*X Manual Pages &amp;quot;W.O. (without) Man&amp;quot;.
* CC Mode: (ccmode).            Emacs mode for editing C, C++, Objective-C,
                                  Java, Pike, AWK, and CORBA IDL code.
* IDLWAVE: (idlwave).           Major mode and shell for IDL files.
* nXML Mode: (nxml-mode).       XML editing mode with RELAX NG support.
* Octave mode: (octave-mode).   Emacs mode for editing GNU Octave files.
* Org Mode: (org).      Outline-based notes management and organizer.
* VHDL Mode: (vhdl-mode).       Emacs mode for editing VHDL code.
* Emacs FAQ: (efaq).            Frequently Asked Questions about Emacs.
* Emacs: (emacs).               The extensible self-documenting text editor.
* Emacs Lisp Intro: (eintr).    A simple introduction to Emacs Lisp programming.
* Elisp: (elisp).               The Emacs Lisp Reference Manual.
* Emacs GnuTLS: (emacs-gnutls). The Emacs GnuTLS integration.
* ERC: (erc).                   Powerful and extensible IRC client for Emacs.
* EUDC: (eudc).                 Emacs client for directory servers (LDAP, BBDB).
* Gnus: (gnus).                 The newsreader Gnus.
* Mairix: (mairix-el).          Emacs interface to the Mairix mail indexer.
* Message: (message).           Mail and news composition mode that
                                  goes with Gnus.
* MH-E: (mh-e).                 Emacs interface to the MH mail system.
* Newsticker: (newsticker).     A feed reader for Emacs.
* PGG: (pgg).                   An obsolete Emacs interface to various
                                  PGP implementations.
* Rcirc: (rcirc).               Internet Relay Chat (IRC) client.
* SASL: (sasl).                 The Emacs SASL library.
* SC: (sc).                     Supercite lets you cite parts of messages
                                  you&amp;#39;re replying to, in flexible ways.
* Sieve: (sieve).               Managing Sieve scripts in Emacs.
* Tramp: (tramp).               Transparent Remote Access, Multiple Protocol
                                  Emacs remote file access via ssh and scp.
* Denote Sequence: (denote-sequence).
                                Sequence notes or Folgezettel with Denote.
* Denote: (denote).             Simple notes with an efficient file-naming
                                  scheme.
* Eat: (eat).                   Emulate A Terminal.
* Embark: (embark).             Emacs Mini-Buffer Actions Rooted in Keymaps.
* Forge: (forge).               Access Git Forges from Magit.
* Ghub: (ghub).                 Client library for the Github API.
* Magit: (magit).               Using Git from Emacs with Magit.
* Magit-Section: (magit-section).
                                Use Magit sections in your own packages.
* Orderless: (orderless).       Completion style for matching regexps in any
                                  order.
* Tempel: (tempel).             Simple templates for Emacs.
* With-Editor: (with-editor).   Using the Emacsclient as $EDITOR.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2025/rich-screenshots-with-wezterm/</id>
    <link href="https://www.alcarney.me/blog/2025/rich-screenshots-with-wezterm" rel="alternate" />
    <published>2025-08-22T00:00:00+00:00</published>
    <updated>2025-08-22T00:00:00+00:00</updated>
    <title>Taking Rich Screenshots with Wezterm</title>
    <content type="html">
      &lt;section id=&#34;taking-rich-screenshots-with-wezterm&#34;&gt;
&lt;h1&gt;Taking Rich Screenshots with Wezterm&lt;a class=&#34;headerlink&#34; href=&#34;#taking-rich-screenshots-with-wezterm&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;When working on this site, I’ve often wanted to include a screenshot or two.
But since git doesn’t work well with binary files and I don’t want to have to deal with media hosting I’ve tended to shy away from it.&lt;/p&gt;
&lt;p&gt;However, a lot of what I want to take a screenshot of can be rendered in a terminal.&lt;/p&gt;
&lt;p&gt;Which is suddenly quite interesting as a terminal’s contents can be entirely described in plain(-ish) text.
Surely it must be possible to capture the contents of a terminal window and then render it as some kind of image? Perhaps an SVG?&lt;/p&gt;
&lt;svg class=&#34;rich-terminal&#34; viewBox=&#34;0 0 1726 1026.0&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
    &lt;!-- Generated with Rich https://www.textualize.io --&gt;
    &lt;style&gt;

    @font-face {
        font-family: &#34;Fira Code&#34;;
        src: local(&#34;FiraCode-Regular&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2&#34;) format(&#34;woff2&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff&#34;) format(&#34;woff&#34;);
        font-style: normal;
        font-weight: 400;
    }
    @font-face {
        font-family: &#34;Fira Code&#34;;
        src: local(&#34;FiraCode-Bold&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2&#34;) format(&#34;woff2&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff&#34;) format(&#34;woff&#34;);
        font-style: bold;
        font-weight: 700;
    }

    .terminal-3055561968-matrix {
        font-family: Fira Code, monospace;
        font-size: 20px;
        line-height: 24.4px;
        font-variant-east-asian: full-width;
    }

    .terminal-3055561968-title {
        font-size: 18px;
        font-weight: bold;
        font-family: arial;
    }

    .terminal-3055561968-r1 { fill: #bcbeaf }
.terminal-3055561968-r2 { fill: #d0e2c8;font-weight: bold }
.terminal-3055561968-r3 { fill: #c8b399 }
.terminal-3055561968-r4 { fill: #ffffff }
.terminal-3055561968-r5 { fill: #d0e2c8 }
.terminal-3055561968-r6 { fill: #c8b399;font-weight: bold }
.terminal-3055561968-r7 { fill: #c8b399;text-decoration: underline; }
.terminal-3055561968-r8 { fill: #c8b399;font-weight: bold;text-decoration: underline; }
.terminal-3055561968-r9 { fill: #d0e2c8;font-style: italic; }
.terminal-3055561968-r10 { fill: #bcbeaf;font-weight: bold;font-style: italic; }
.terminal-3055561968-r11 { fill: #bcbeaf;text-decoration: underline; }
.terminal-3055561968-r12 { fill: #bcbeaf;font-weight: bold;text-decoration: underline; }
    &lt;/style&gt;

    &lt;defs&gt;
    &lt;clipPath id=&#34;terminal-3055561968-clip-terminal&#34;&gt;
      &lt;rect x=&#34;0&#34; y=&#34;0&#34; width=&#34;1707.0&#34; height=&#34;975.0&#34; /&gt;
    &lt;/clipPath&gt;
    &lt;clipPath id=&#34;terminal-3055561968-line-0&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;1.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-1&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;25.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-2&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;50.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-3&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;74.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-4&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;99.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-5&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;123.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-6&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;147.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-7&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;172.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-8&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;196.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-9&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;221.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-10&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;245.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-11&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;269.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-12&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;294.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-13&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;318.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-14&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;343.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-15&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;367.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-16&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;391.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-17&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;416.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-18&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;440.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-19&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;465.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-20&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;489.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-21&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;513.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-22&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;538.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-23&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;562.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-24&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;587.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-25&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;611.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-26&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;635.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-27&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;660.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-28&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;684.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-29&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;709.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-30&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;733.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-31&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;757.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-32&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;782.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-33&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;806.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-34&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;831.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-35&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;855.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-36&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;879.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-37&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;904.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3055561968-line-38&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;928.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34;/&gt;
            &lt;/clipPath&gt;
    &lt;/defs&gt;

    &lt;rect fill=&#34;#000000&#34; stroke=&#34;rgba(255,255,255,0.35)&#34; stroke-width=&#34;1&#34; x=&#34;1&#34; y=&#34;1&#34; width=&#34;1724&#34; height=&#34;1024&#34; rx=&#34;8&#34;/&gt;&lt;text class=&#34;terminal-3055561968-title&#34; fill=&#34;#ffffff&#34; text-anchor=&#34;middle&#34; x=&#34;862&#34; y=&#34;27&#34;&gt;M-x&amp;#160;pdb&lt;/text&gt;
            &lt;g transform=&#34;translate(26,22)&#34;&gt;
            &lt;circle cx=&#34;0&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#ff5f57&#34;/&gt;
            &lt;circle cx=&#34;22&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#febc2e&#34;/&gt;
            &lt;circle cx=&#34;44&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#28c840&#34;/&gt;
            &lt;/g&gt;
        
    &lt;g transform=&#34;translate(9, 41)&#34; clip-path=&#34;url(#terminal-3055561968-clip-terminal)&#34;&gt;
    &lt;rect fill=&#34;#40503d&#34; x=&#34;0&#34; y=&#34;1.5&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;1.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#40503d&#34; x=&#34;48.8&#34; y=&#34;1.5&#34; width=&#34;1464&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#40503d&#34; x=&#34;1512.8&#34; y=&#34;1.5&#34; width=&#34;170.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#40503d&#34; x=&#34;1683.6&#34; y=&#34;1.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;25.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;50.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;74.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;99.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;73.2&#34; y=&#34;99.1&#34; width=&#34;1634.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;123.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;147.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;172.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;196.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;221.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;245.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;269.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;294.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;318.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;343.1&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;367.5&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;391.9&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;416.3&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;440.7&#34; width=&#34;1708&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#70523a&#34; x=&#34;0&#34; y=&#34;465.1&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#70523a&#34; x=&#34;36.6&#34; y=&#34;465.1&#34; width=&#34;109.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#70523a&#34; x=&#34;146.4&#34; y=&#34;465.1&#34; width=&#34;1561.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;489.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;36.6&#34; y=&#34;489.5&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;489.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;158.6&#34; y=&#34;489.5&#34; width=&#34;1549.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;513.9&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;513.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;513.9&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;538.3&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;538.3&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;538.3&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;562.7&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;562.7&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;562.7&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;122&#34; y=&#34;562.7&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;134.2&#34; y=&#34;562.7&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;183&#34; y=&#34;562.7&#34; width=&#34;1525&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;587.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;587.1&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;134.2&#34; y=&#34;587.1&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;170.8&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;183&#34; y=&#34;587.1&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;231.8&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;244&#34; y=&#34;587.1&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;268.4&#34; y=&#34;587.1&#34; width=&#34;170.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;439.2&#34; y=&#34;587.1&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;475.8&#34; y=&#34;587.1&#34; width=&#34;85.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;561.2&#34; y=&#34;587.1&#34; width=&#34;85.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;646.6&#34; y=&#34;587.1&#34; width=&#34;1061.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;611.5&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;611.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;611.5&#34; width=&#34;97.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;183&#34; y=&#34;611.5&#34; width=&#34;61&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;244&#34; y=&#34;611.5&#34; width=&#34;1464&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;635.9&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;635.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;635.9&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;660.3&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;660.3&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;660.3&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;684.7&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;684.7&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;684.7&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;109.8&#34; y=&#34;684.7&#34; width=&#34;158.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;268.4&#34; y=&#34;684.7&#34; width=&#34;122&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;390.4&#34; y=&#34;684.7&#34; width=&#34;1317.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;709.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;709.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;709.1&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;733.5&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;733.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;733.5&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;757.9&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;757.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;757.9&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;782.3&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;782.3&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;782.3&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;806.7&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;806.7&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;806.7&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;831.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;831.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;831.1&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;855.5&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;855.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;855.5&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;879.9&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;879.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;879.9&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;904.3&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;12.2&#34; y=&#34;904.3&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;85.4&#34; y=&#34;904.3&#34; width=&#34;1622.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#40503d&#34; x=&#34;0&#34; y=&#34;928.7&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#40503d&#34; x=&#34;12.2&#34; y=&#34;928.7&#34; width=&#34;195.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#40503d&#34; x=&#34;207.4&#34; y=&#34;928.7&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#40503d&#34; x=&#34;231.8&#34; y=&#34;928.7&#34; width=&#34;122&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#40503d&#34; x=&#34;353.8&#34; y=&#34;928.7&#34; width=&#34;1354.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;&lt;rect fill=&#34;#303f2d&#34; x=&#34;0&#34; y=&#34;953.1&#34; width=&#34;1695.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;/&gt;
    &lt;g class=&#34;terminal-3055561968-matrix&#34;&gt;
    &lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;0&#34; y=&#34;20&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-0)&#34;&gt;|&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r2&#34; x=&#34;12.2&#34; y=&#34;20&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3055561968-line-0)&#34;&gt;-1-&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;48.8&#34; y=&#34;20&#34; textLength=&#34;1464&#34; clip-path=&#34;url(#terminal-3055561968-line-0)&#34;&gt;|&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;[85%]&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r3&#34; x=&#34;1512.8&#34; y=&#34;20&#34; textLength=&#34;170.8&#34; clip-path=&#34;url(#terminal-3055561968-line-0)&#34;&gt;18:58&amp;#160;18/03/26&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;1683.6&#34; y=&#34;20&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3055561968-line-0)&#34;&gt;&amp;#160;☰&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;20&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-0)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;0&#34; y=&#34;44.4&#34; textLength=&#34;1708&#34; clip-path=&#34;url(#terminal-3055561968-line-1)&#34;&gt;Current&amp;#160;directory&amp;#160;is&amp;#160;~/Projects/alcarney/blog/content/&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;44.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-1)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;0&#34; y=&#34;68.8&#34; textLength=&#34;1708&#34; clip-path=&#34;url(#terminal-3055561968-line-2)&#34;&gt;&amp;gt;&amp;#160;/var/home/alex/Projects/alcarney/blog/content/example.py(1)&amp;lt;module&amp;gt;()&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;68.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-2)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;0&#34; y=&#34;93.2&#34; textLength=&#34;1708&#34; clip-path=&#34;url(#terminal-3055561968-line-3)&#34;&gt;-&amp;gt;&amp;#160;import&amp;#160;pathlib&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;93.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-3)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r6&#34; x=&#34;0&#34; y=&#34;117.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-4)&#34;&gt;(Pdb)&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;117.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-4)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;142&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-5)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;166.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-6)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;190.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-7)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;215.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-8)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;239.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-9)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;264&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-10)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;288.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-11)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;312.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-12)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;337.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-13)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;361.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-14)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;386&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-15)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;410.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-16)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;434.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-17)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;459.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-18)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r7&#34; x=&#34;0&#34; y=&#34;483.6&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3055561968-line-19)&#34;&gt;-&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r8&#34; x=&#34;36.6&#34; y=&#34;483.6&#34; textLength=&#34;109.8&#34; clip-path=&#34;url(#terminal-3055561968-line-19)&#34;&gt;*gud-pdb*&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r7&#34; x=&#34;146.4&#34; y=&#34;483.6&#34; textLength=&#34;1561.6&#34; clip-path=&#34;url(#terminal-3055561968-line-19)&#34;&gt;&amp;#160;4:6&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;(Debugger:run&amp;#160;Apheleia)&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;483.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-19)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;0&#34; y=&#34;508&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3055561968-line-20)&#34;&gt;&amp;#160;=&amp;gt;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r2&#34; x=&#34;36.6&#34; y=&#34;508&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3055561968-line-20)&#34;&gt;&amp;#160;&amp;#160;1&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r6&#34; x=&#34;85.4&#34; y=&#34;508&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-20)&#34;&gt;import&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;158.6&#34; y=&#34;508&#34; textLength=&#34;1549.4&#34; clip-path=&#34;url(#terminal-3055561968-line-20)&#34;&gt;&amp;#160;pathlib&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;508&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-20)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;532.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-21)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;2&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;532.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-21)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;556.8&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-22)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;3&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;556.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-22)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;581.2&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-23)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;4&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r6&#34; x=&#34;85.4&#34; y=&#34;581.2&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3055561968-line-23)&#34;&gt;def&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r3&#34; x=&#34;134.2&#34; y=&#34;581.2&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3055561968-line-23)&#34;&gt;main&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;183&#34; y=&#34;581.2&#34; textLength=&#34;1525&#34; clip-path=&#34;url(#terminal-3055561968-line-23)&#34;&gt;():&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;581.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-23)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;605.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;5&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r6&#34; x=&#34;134.2&#34; y=&#34;605.6&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;for&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r9&#34; x=&#34;183&#34; y=&#34;605.6&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;file&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r6&#34; x=&#34;244&#34; y=&#34;605.6&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;in&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;268.4&#34; y=&#34;605.6&#34; textLength=&#34;170.8&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;&amp;#160;pathlib.Path(&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;439.2&#34; y=&#34;605.6&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;&amp;quot;.&amp;quot;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;475.8&#34; y=&#34;605.6&#34; textLength=&#34;85.4&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;).glob(&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;561.2&#34; y=&#34;605.6&#34; textLength=&#34;85.4&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;&amp;quot;*.rst&amp;quot;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;646.6&#34; y=&#34;605.6&#34; textLength=&#34;1061.4&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;):&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-24)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;630&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-25)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;6&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r10&#34; x=&#34;183&#34; y=&#34;630&#34; textLength=&#34;61&#34; clip-path=&#34;url(#terminal-3055561968-line-25)&#34;&gt;print&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;244&#34; y=&#34;630&#34; textLength=&#34;1464&#34; clip-path=&#34;url(#terminal-3055561968-line-25)&#34;&gt;(file.name)&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;630&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-25)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;654.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-26)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;7&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;654.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-26)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;678.8&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-27)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;8&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;678.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-27)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;703.2&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-28)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;9&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r6&#34; x=&#34;85.4&#34; y=&#34;703.2&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3055561968-line-28)&#34;&gt;if&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;109.8&#34; y=&#34;703.2&#34; textLength=&#34;158.6&#34; clip-path=&#34;url(#terminal-3055561968-line-28)&#34;&gt;&amp;#160;__name__&amp;#160;==&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;268.4&#34; y=&#34;703.2&#34; textLength=&#34;122&#34; clip-path=&#34;url(#terminal-3055561968-line-28)&#34;&gt;&amp;quot;__main__&amp;quot;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;390.4&#34; y=&#34;703.2&#34; textLength=&#34;1317.6&#34; clip-path=&#34;url(#terminal-3055561968-line-28)&#34;&gt;:&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;703.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-28)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r1&#34; x=&#34;12.2&#34; y=&#34;727.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3055561968-line-29)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;10&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r5&#34; x=&#34;85.4&#34; y=&#34;727.6&#34; textLength=&#34;1622.6&#34; clip-path=&#34;url(#terminal-3055561968-line-29)&#34;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;main()&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;727.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-29)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;752&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-30)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;776.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-31)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;800.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-32)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;825.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-33)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;849.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-34)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;874&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-35)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;898.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-36)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;922.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-37)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r11&#34; x=&#34;0&#34; y=&#34;947.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-38)&#34;&gt;-&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r12&#34; x=&#34;12.2&#34; y=&#34;947.2&#34; textLength=&#34;195.2&#34; clip-path=&#34;url(#terminal-3055561968-line-38)&#34;&gt;🖿&amp;#160;alcarney/blog&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r8&#34; x=&#34;231.8&#34; y=&#34;947.2&#34; textLength=&#34;122&#34; clip-path=&#34;url(#terminal-3055561968-line-38)&#34;&gt;example.py&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r11&#34; x=&#34;353.8&#34; y=&#34;947.2&#34; textLength=&#34;1354.2&#34; clip-path=&#34;url(#terminal-3055561968-line-38)&#34;&gt;&amp;#160;1:0&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;(Python&amp;#160;ws&amp;#160;Apheleia©&amp;#160;ElDoc)&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;947.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-38)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3055561968-r4&#34; x=&#34;1708&#34; y=&#34;971.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3055561968-line-39)&#34;&gt;
&lt;/text&gt;
    &lt;/g&gt;
    &lt;/g&gt;
&lt;/svg&gt;
&lt;p&gt;Yes it is!&lt;/p&gt;
&lt;p&gt;In this blog post I describe how I arrived at the workflow I used to include the above screenshot on this website.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;taking-the-screenshot&#34;&gt;
&lt;h2&gt;Taking the screenshot&lt;a class=&#34;headerlink&#34; href=&#34;#taking-the-screenshot&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ll admit it, this whole idea started out as a solution in search of a problem!&lt;/p&gt;
&lt;p&gt;I’ve been using &lt;a class=&#34;reference external&#34; href=&#34;https://wezterm.org&#34;&gt;WezTerm&lt;/a&gt; as my terminal emulator for a while now, but I wasn’t taking advantage of the fact that it is configured using Lua and so I was looking for an excuse to try something non-trivial.&lt;/p&gt;
&lt;p&gt;Before long I found it - &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pane:get_lines_as_escapes()&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The above function returns the current contents of the terminal pane as a string, including all the escape codes that control the formatting!
By
&lt;a class=&#34;reference external&#34; href=&#34;https://wezterm.org/config/lua/window-events/augment-command-palette.html#adding-a-rename-tab-entry-to-the-palette&#34;&gt;mashing&lt;/a&gt;
together a couple of
&lt;a class=&#34;reference external&#34; href=&#34;https://wezterm.org/config/lua/pane/get_lines_as_escapes.html&#34;&gt;examples&lt;/a&gt;
from the documentation I soon had a custom command I could invoke through the command palette which would dump the contents of the active pane to a text file.&lt;/p&gt;
&lt;div class=&#34;highlight-lua notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;augment-command-palette&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;brief&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Take screenshot&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;icon&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;cod_device_camera&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;action&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;act&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;PromptInputLine&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Screenshot name&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;action&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;action_callback&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;then&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_lines_as_escapes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;io.open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.txt&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;w+&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition-flatpak-permissions admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Flatpak permissions…&lt;/p&gt;
&lt;p&gt;I have the &lt;a class=&#34;reference external&#34; href=&#34;https://flathub.org/apps/org.wezfurlong.wezterm&#34;&gt;Flatpak&lt;/a&gt; version of  WezTerm installed.&lt;/p&gt;
&lt;p&gt;This led to a bizarre issue where the call to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;io.open()&lt;/span&gt;&lt;/code&gt; kept failing silently by returning &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nil&lt;/span&gt;&lt;/code&gt;.
&lt;a class=&#34;reference external&#34; href=&#34;https://stackoverflow.com/a/75390601&#34;&gt;Apparently&lt;/a&gt;, in order to get an actual error message you need to wrap the call in an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;assert()&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Eventually, I was able to spot that WezTerm was complaining that the filesystem was read-only.
Thankfully, the KDE System Settings app allowed me to grant WezTerm write access to my filesystem without too much hassle.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;After running the command and giving it a filename I was left with a plain-ish text file that looked something like the following&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;\x1b[38:2::255:255:255m\x1b[48:2::49:49:49m|\x1b(B\x1b[0;1m\x1b[38:2::255:255:255m\x1b[40m*gud-test*        x\x1b(B\x1b[0m\x1b[&amp;#39;z...
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;rendering-the-screenshot&#34;&gt;
&lt;h2&gt;Rendering the Screenshot&lt;a class=&#34;headerlink&#34; href=&#34;#rendering-the-screenshot&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we have the raw data, there are lots of ways we could approach rendering it, for example you could dump it into &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/xtermjs/xterm.js&#34;&gt;xterm.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, while I have nothing against JavaScript it’s always nice not to rely on it unnecessarily.
Since this is a static screenshot anyway it makes sense to render it offline and embed the result in the page.&lt;/p&gt;
&lt;p&gt;Using the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/textualize/rich&#34;&gt;rich&lt;/a&gt; Python library, it only takes a few lines of code to convert the screenshot from plain-ish text to an SVG.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;io&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;pathlib&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;rich.console&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Console&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;rich.text&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Text&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;lt;filepath&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read_text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Text&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from_ansi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;console&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;StringIO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;force_terminal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;svg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_svg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Example screenshot&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There is one small issue… passing &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;None&lt;/span&gt;&lt;/code&gt; for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;width&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;height&lt;/span&gt;&lt;/code&gt; of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Console&lt;/span&gt;&lt;/code&gt; object means that it will use the dimensions of the current terminal executing the code rather than the dimensions of the terminal the screenshot was captured from!&lt;/p&gt;
&lt;section id=&#34;width-and-height&#34;&gt;
&lt;h3&gt;Width and Height&lt;a class=&#34;headerlink&#34; href=&#34;#width-and-height&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In order for the captured data to be rendered correctly, rich’s &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Console&lt;/span&gt;&lt;/code&gt; object needs to use the same &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;width&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;height&lt;/span&gt;&lt;/code&gt; as the original terminal.&lt;/p&gt;
&lt;p&gt;This means that when we take the screenshot, we also need to capture the dimensions of the terminal pane.
Easy enough with WezTerm’s Lua API, but where to store the values?&lt;/p&gt;
&lt;p&gt;Rather than try and invent a file format, why not reuse the &lt;a class=&#34;reference external&#34; href=&#34;https://docs.asciinema.org/manual/asciicast/v3/&#34;&gt;asciicast&lt;/a&gt; format from &lt;a class=&#34;reference external&#34; href=&#34;https://asciinema.org/&#34;&gt;asciinema&lt;/a&gt;?
After all a screenshot is just a single frame screencast!&lt;/p&gt;
&lt;p&gt;We don’t need to worry too much about the details of the format, the following snippet should be enough for this use case.&lt;/p&gt;
&lt;div class=&#34;highlight-json notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;cols&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;lt;width&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;rows&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;lt;height&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;o&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;lt;captured_output&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which we can modify our custom WezTerm command to produce.&lt;/p&gt;
&lt;div class=&#34;highlight-lua notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;augment-command-palette&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;brief&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Take screenshot&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;icon&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;cod_device_camera&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;action&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;act&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;PromptInputLine&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Screenshot name&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;action&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;action_callback&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;then&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;o&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_lines_as_escapes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cols&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;cols&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;rows&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;viewport_rows&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;io.open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.cast&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;w+&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;json_encode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;json_encode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And update our Python code accordingly&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fpath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;lt;filepath&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fpath&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;header&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loads&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;body&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loads&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Text&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from_ansi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;console&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;StringIO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;force_terminal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cols&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;rows&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;svg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_svg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;options&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;At this point you’d think it would be job done, but there is one more detail to consider…&lt;/p&gt;
&lt;svg version=&#34;1.0&#34;  class=&#34;rich-terminal&#34; viewBox=&#34;0 0 933 684.4&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
    &lt;!-- Generated with Rich https://www.textualize.io --&gt;
    &lt;style&gt;

    @font-face {
        font-family: &#34;Fira Code&#34;;
        src: local(&#34;FiraCode-Regular&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2&#34;) format(&#34;woff2&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff&#34;) format(&#34;woff&#34;);
        font-style: normal;
        font-weight: 400;
    }
    @font-face {
        font-family: &#34;Fira Code&#34;;
        src: local(&#34;FiraCode-Bold&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2&#34;) format(&#34;woff2&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff&#34;) format(&#34;woff&#34;);
        font-style: bold;
        font-weight: 700;
    }

    .terminal-3457234609-matrix {
        font-family: Fira Code, monospace;
        font-size: 20px;
        line-height: 24.4px;
        font-variant-east-asian: full-width;
    }

    .terminal-3457234609-title {
        font-size: 18px;
        font-weight: bold;
        font-family: arial;
    }

    .terminal-3457234609-r1 { fill: #c5c8c6 }
.terminal-3457234609-r2 { fill: #c5c8c6;font-weight: bold }
.terminal-3457234609-r3 { fill: #c5c8c6;font-weight: bold;font-style: italic; }
.terminal-3457234609-r4 { fill: #c5c8c6;font-style: italic; }
    &lt;/style&gt;

    &lt;defs&gt;
    &lt;clipPath id=&#34;terminal-3457234609-clip-terminal&#34;&gt;
      &lt;rect x=&#34;0&#34; y=&#34;0&#34; width=&#34;914.0&#34; height=&#34;633.4&#34;&gt;&lt;/rect&gt;
    &lt;/clipPath&gt;
    &lt;clipPath id=&#34;terminal-3457234609-line-0&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;1.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-1&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;25.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-2&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;50.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-3&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;74.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-4&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;99.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-5&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;123.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-6&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;147.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-7&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;172.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-8&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;196.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-9&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;221.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-10&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;245.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-11&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;269.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-12&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;294.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-13&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;318.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-14&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;343.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-15&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;367.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-16&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;391.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-17&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;416.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-18&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;440.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-19&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;465.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-20&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;489.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-21&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;513.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-22&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;538.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-23&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;562.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3457234609-line-24&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;587.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
    &lt;/defs&gt;

    &lt;rect fill=&#34;#292929&#34; stroke=&#34;rgba(255,255,255,0.35)&#34; stroke-width=&#34;1&#34; x=&#34;1&#34; y=&#34;1&#34; width=&#34;931&#34; height=&#34;682.4&#34; rx=&#34;8&#34;&gt;&lt;/rect&gt;
            &lt;g transform=&#34;translate(26,22)&#34;&gt;
            &lt;circle cx=&#34;0&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#ff5f57&#34;&gt;&lt;/circle&gt;
            &lt;circle cx=&#34;22&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#febc2e&#34;&gt;&lt;/circle&gt;
            &lt;circle cx=&#34;44&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#28c840&#34;&gt;&lt;/circle&gt;
            &lt;/g&gt;

    &lt;g transform=&#34;translate(9, 41)&#34; clip-path=&#34;url(#terminal-3457234609-clip-terminal)&#34;&gt;
    &lt;rect fill=&#34;#4b4e55&#34; x=&#34;12.2&#34; y=&#34;1.5&#34; width=&#34;231.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;25.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;73.2&#34; y=&#34;25.9&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;85.4&#34; y=&#34;25.9&#34; width=&#34;829.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;50.3&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;74.7&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;99.1&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;123.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;73.2&#34; y=&#34;123.5&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;85.4&#34; y=&#34;123.5&#34; width=&#34;829.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;147.9&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;172.3&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;196.7&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;221.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;73.2&#34; y=&#34;221.1&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;109.8&#34; y=&#34;221.1&#34; width=&#34;805.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;245.5&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;269.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;73.2&#34; y=&#34;269.9&#34; width=&#34;841.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;294.3&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;318.7&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;318.7&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;318.7&#34; width=&#34;97.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;195.2&#34; y=&#34;318.7&#34; width=&#34;707.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;902.8&#34; y=&#34;318.7&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;343.1&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;343.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;343.1&#34; width=&#34;170.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;268.4&#34; y=&#34;343.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;280.6&#34; y=&#34;343.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;353.8&#34; y=&#34;343.1&#34; width=&#34;561.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;367.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;367.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;367.5&#34; width=&#34;97.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;195.2&#34; y=&#34;367.5&#34; width=&#34;183&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;378.2&#34; y=&#34;367.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;414.8&#34; y=&#34;367.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;451.4&#34; y=&#34;367.5&#34; width=&#34;463.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;391.9&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;391.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;391.9&#34; width=&#34;97.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;195.2&#34; y=&#34;391.9&#34; width=&#34;61&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;256.2&#34; y=&#34;391.9&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;268.4&#34; y=&#34;391.9&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;305&#34; y=&#34;391.9&#34; width=&#34;610&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;416.3&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;416.3&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;416.3&#34; width=&#34;146.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;244&#34; y=&#34;416.3&#34; width=&#34;183&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;427&#34; y=&#34;416.3&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;463.6&#34; y=&#34;416.3&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;500.2&#34; y=&#34;416.3&#34; width=&#34;414.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;440.7&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;440.7&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;440.7&#34; width=&#34;146.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;244&#34; y=&#34;440.7&#34; width=&#34;122&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;366&#34; y=&#34;440.7&#34; width=&#34;549&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;465.1&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;465.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;465.1&#34; width=&#34;146.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;244&#34; y=&#34;465.1&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;268.4&#34; y=&#34;465.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;280.6&#34; y=&#34;465.1&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;317.2&#34; y=&#34;465.1&#34; width=&#34;597.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;489.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;489.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;489.5&#34; width=&#34;195.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;292.8&#34; y=&#34;489.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;317.2&#34; y=&#34;489.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;341.6&#34; y=&#34;489.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;378.2&#34; y=&#34;489.5&#34; width=&#34;268.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;646.6&#34; y=&#34;489.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;683.2&#34; y=&#34;489.5&#34; width=&#34;231.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;513.9&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;513.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;513.9&#34; width=&#34;244&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;341.6&#34; y=&#34;513.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;414.8&#34; y=&#34;513.9&#34; width=&#34;500.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;538.3&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;24.4&#34; y=&#34;538.3&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;538.3&#34; width=&#34;817.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;562.7&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;562.7&#34; width=&#34;195.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;292.8&#34; y=&#34;562.7&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;341.6&#34; y=&#34;562.7&#34; width=&#34;573.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;611.5&#34; width=&#34;902.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;
    &lt;g class=&#34;terminal-3457234609-matrix&#34;&gt;
    &lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;20&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-0)&#34;&gt;|&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;12.2&#34; y=&#34;20&#34; textLength=&#34;231.8&#34; clip-path=&#34;url(#terminal-3457234609-line-0)&#34;&gt;*gud-test*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;244&#34; y=&#34;20&#34; textLength=&#34;671&#34; clip-path=&#34;url(#terminal-3457234609-line-0)&#34;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[89%]&amp;nbsp;21:17&amp;nbsp;18/06/25&amp;nbsp;☰&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;20&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-0)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r3&#34; x=&#34;0&#34; y=&#34;44.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-1)&#34;&gt;(Pdb)&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;73.2&#34; y=&#34;44.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-1)&#34;&gt;n&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;44.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-1)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;68.8&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3457234609-line-2)&#34;&gt;&amp;gt;&amp;nbsp;/var/home/alex/Projects/swyddfa/lsp-devtools/develop/lib/lsp-devtools/ls\&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;68.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-2)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;93.2&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3457234609-line-3)&#34;&gt;p_devtools/agent/server.py(166)feed()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;93.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-3)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;117.6&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3457234609-line-4)&#34;&gt;-&amp;gt;&amp;nbsp;if&amp;nbsp;(idx&amp;nbsp;:=&amp;nbsp;state.buffer.find(SEP))&amp;nbsp;==&amp;nbsp;-1:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;117.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-4)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r3&#34; x=&#34;0&#34; y=&#34;142&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-5)&#34;&gt;(Pdb)&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;73.2&#34; y=&#34;142&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-5)&#34;&gt;n&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;142&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-5)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;166.4&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3457234609-line-6)&#34;&gt;&amp;gt;&amp;nbsp;/var/home/alex/Projects/swyddfa/lsp-devtools/develop/lib/lsp-devtools/ls\&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;166.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-6)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;190.8&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3457234609-line-7)&#34;&gt;p_devtools/agent/server.py(169)feed()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;190.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-7)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;215.2&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3457234609-line-8)&#34;&gt;-&amp;gt;&amp;nbsp;line,&amp;nbsp;state.buffer&amp;nbsp;=&amp;nbsp;state.buffer[:idx],&amp;nbsp;state.buffer[idx&amp;nbsp;+&amp;nbsp;len(SEP)&amp;nbsp;:]&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;215.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-8)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r3&#34; x=&#34;0&#34; y=&#34;239.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-9)&#34;&gt;(Pdb)&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;73.2&#34; y=&#34;239.6&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-9)&#34;&gt;idx&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;239.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-9)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;264&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3457234609-line-10)&#34;&gt;30&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;264&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-10)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r3&#34; x=&#34;0&#34; y=&#34;288.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-11)&#34;&gt;(Pdb)&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;288.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-11)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;312.8&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-12)&#34;&gt;-&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;36.6&#34; y=&#34;312.8&#34; textLength=&#34;122&#34; clip-path=&#34;url(#terminal-3457234609-line-12)&#34;&gt;*gud-test*&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;158.6&#34; y=&#34;312.8&#34; textLength=&#34;756.4&#34; clip-path=&#34;url(#terminal-3457234609-line-12)&#34;&gt;&amp;nbsp;60:6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Debugger:run&amp;nbsp;Apheleia)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;312.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-12)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;337.2&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-13)&#34;&gt;&amp;nbsp;&amp;nbsp;160&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r4&#34; x=&#34;195.2&#34; y=&#34;337.2&#34; textLength=&#34;707.6&#34; clip-path=&#34;url(#terminal-3457234609-line-13)&#34;&gt;#&amp;nbsp;So&amp;nbsp;we&amp;nbsp;will&amp;nbsp;keep&amp;nbsp;running&amp;nbsp;that&amp;nbsp;parser&amp;nbsp;as&amp;nbsp;long&amp;nbsp;as&amp;nbsp;the&amp;nbsp;buffe&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;902.8&#34; y=&#34;337.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-13)&#34;&gt;\&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;337.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-13)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r4&#34; x=&#34;97.6&#34; y=&#34;361.6&#34; textLength=&#34;170.8&#34; clip-path=&#34;url(#terminal-3457234609-line-14)&#34;&gt;r&amp;nbsp;continues&amp;nbsp;to&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r4&#34; x=&#34;280.6&#34; y=&#34;361.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-14)&#34;&gt;shrink&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;361.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-14)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;386&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-15)&#34;&gt;&amp;nbsp;&amp;nbsp;161&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;195.2&#34; y=&#34;386&#34; textLength=&#34;183&#34; clip-path=&#34;url(#terminal-3457234609-line-15)&#34;&gt;previous_length&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;378.2&#34; y=&#34;386&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-15)&#34;&gt;&amp;nbsp;=&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;414.8&#34; y=&#34;386&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-15)&#34;&gt;len&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;451.4&#34; y=&#34;386&#34; textLength=&#34;463.6&#34; clip-path=&#34;url(#terminal-3457234609-line-15)&#34;&gt;(state.buffer)&amp;nbsp;+&amp;nbsp;1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;386&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-15)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;410.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-16)&#34;&gt;&amp;nbsp;&amp;nbsp;162&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;195.2&#34; y=&#34;410.4&#34; textLength=&#34;61&#34; clip-path=&#34;url(#terminal-3457234609-line-16)&#34;&gt;while&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;268.4&#34; y=&#34;410.4&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-16)&#34;&gt;len&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;305&#34; y=&#34;410.4&#34; textLength=&#34;610&#34; clip-path=&#34;url(#terminal-3457234609-line-16)&#34;&gt;(state.buffer)&amp;nbsp;&amp;lt;&amp;nbsp;previous_length:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;410.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-16)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;434.8&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-17)&#34;&gt;&amp;nbsp;&amp;nbsp;163&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;244&#34; y=&#34;434.8&#34; textLength=&#34;183&#34; clip-path=&#34;url(#terminal-3457234609-line-17)&#34;&gt;previous_length&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;427&#34; y=&#34;434.8&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-17)&#34;&gt;&amp;nbsp;=&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;463.6&#34; y=&#34;434.8&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-17)&#34;&gt;len&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;500.2&#34; y=&#34;434.8&#34; textLength=&#34;414.8&#34; clip-path=&#34;url(#terminal-3457234609-line-17)&#34;&gt;(state.buffer)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;434.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-17)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;459.2&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-18)&#34;&gt;&amp;nbsp;&amp;nbsp;164&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;244&#34; y=&#34;459.2&#34; textLength=&#34;122&#34; clip-path=&#34;url(#terminal-3457234609-line-18)&#34;&gt;breakpoint&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;366&#34; y=&#34;459.2&#34; textLength=&#34;549&#34; clip-path=&#34;url(#terminal-3457234609-line-18)&#34;&gt;()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;459.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-18)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;483.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-19)&#34;&gt;&amp;nbsp;&amp;nbsp;165&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;244&#34; y=&#34;483.6&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3457234609-line-19)&#34;&gt;if&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;280.6&#34; y=&#34;483.6&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-19)&#34;&gt;not&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;317.2&#34; y=&#34;483.6&#34; textLength=&#34;597.8&#34; clip-path=&#34;url(#terminal-3457234609-line-19)&#34;&gt;&amp;nbsp;state.headers_complete:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;483.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-19)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;508&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-20)&#34;&gt;&amp;nbsp;&amp;nbsp;166&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;292.8&#34; y=&#34;508&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3457234609-line-20)&#34;&gt;if&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;317.2&#34; y=&#34;508&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3457234609-line-20)&#34;&gt;&amp;nbsp;(&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;341.6&#34; y=&#34;508&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-20)&#34;&gt;idx&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;378.2&#34; y=&#34;508&#34; textLength=&#34;268.4&#34; clip-path=&#34;url(#terminal-3457234609-line-20)&#34;&gt;&amp;nbsp;:=&amp;nbsp;state.buffer.find(&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;646.6&#34; y=&#34;508&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3457234609-line-20)&#34;&gt;SEP&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;683.2&#34; y=&#34;508&#34; textLength=&#34;231.8&#34; clip-path=&#34;url(#terminal-3457234609-line-20)&#34;&gt;))&amp;nbsp;==&amp;nbsp;-1:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;508&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-20)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;532.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-21)&#34;&gt;&amp;nbsp;&amp;nbsp;167&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;341.6&#34; y=&#34;532.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-21)&#34;&gt;return&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;532.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-21)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;24.4&#34; y=&#34;556.8&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3457234609-line-22)&#34;&gt;&amp;nbsp;&amp;nbsp;168&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;556.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-22)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;581.2&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3457234609-line-23)&#34;&gt;&amp;nbsp;&amp;nbsp;=&amp;gt;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;48.8&#34; y=&#34;581.2&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3457234609-line-23)&#34;&gt;169&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;292.8&#34; y=&#34;581.2&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3457234609-line-23)&#34;&gt;line&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;341.6&#34; y=&#34;581.2&#34; textLength=&#34;573.4&#34; clip-path=&#34;url(#terminal-3457234609-line-23)&#34;&gt;,&amp;nbsp;state.buffer&amp;nbsp;=&amp;nbsp;state.buffer[:idx],&amp;nbsp;state.buf\&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;581.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-23)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;0&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;-&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;12.2&#34; y=&#34;605.6&#34; textLength=&#34;183&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;🖿&amp;nbsp;lsp-devtools&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;219.6&#34; y=&#34;605.6&#34; textLength=&#34;109.8&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;server.py&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;329.4&#34; y=&#34;605.6&#34; textLength=&#34;341.6&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;&amp;nbsp;169:0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Python&amp;nbsp;Flymake[&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;671&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;0&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;695.4&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;0&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r2&#34; x=&#34;719.8&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;1&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;732&#34; y=&#34;605.6&#34; textLength=&#34;183&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;]&amp;nbsp;ws&amp;nbsp;Apheleia©&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3457234609-r1&#34; x=&#34;915&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3457234609-line-24)&#34;&gt;
&lt;/text&gt;
    &lt;/g&gt;
    &lt;/g&gt;
&lt;/svg&gt;
&lt;p&gt;My terminal colours are not being preserved!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;sgr-codes&#34;&gt;
&lt;h3&gt;SGR Codes&lt;a class=&#34;headerlink&#34; href=&#34;#sgr-codes&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’m not the right person to try and explain how terminal rendering works.
I only know enough to say that the story is long and built up using many layers of escape codes…&lt;/p&gt;
&lt;p&gt;The codes that matter for this tale are something called &lt;a class=&#34;reference external&#34; href=&#34;https://strasis.com/documentation/limelight-xe/reference/ecma-48-sgr-codes&#34;&gt;SGR codes&lt;/a&gt; and they control various formatting properties including colour.
Most documentation I’ve found will say that to set the text colour to… red for example, you need to use the following escape sequence:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;\x1b[38;2;255;0;0m
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, there are some places that specify an alternative representation:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;\x1b[38:2::255:0:0m
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It turns out that WezTerm uses this second style, which &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;rich&lt;/span&gt;&lt;/code&gt; does not recognise, resulting in the colourless image you saw above.
To fix this, &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/Textualize/rich/pull/3789&#34;&gt;I tweaked&lt;/a&gt; the way rich parsed escape codes to allow for both styles, resulting in the image you see below.&lt;/p&gt;
&lt;svg class=&#34;rich-terminal&#34; viewBox=&#34;0 0 933 684.4&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
    &lt;!-- Generated with Rich https://www.textualize.io --&gt;
    &lt;style&gt;

    @font-face {
        font-family: &#34;Fira Code&#34;;
        src: local(&#34;FiraCode-Regular&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2&#34;) format(&#34;woff2&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff&#34;) format(&#34;woff&#34;);
        font-style: normal;
        font-weight: 400;
    }
    @font-face {
        font-family: &#34;Fira Code&#34;;
        src: local(&#34;FiraCode-Bold&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2&#34;) format(&#34;woff2&#34;),
                url(&#34;https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff&#34;) format(&#34;woff&#34;);
        font-style: bold;
        font-weight: 700;
    }

    .terminal-3357607941-matrix {
        font-family: Fira Code, monospace;
        font-size: 20px;
        line-height: 24.4px;
        font-variant-east-asian: full-width;
    }

    .terminal-3357607941-title {
        font-size: 18px;
        font-weight: bold;
        font-family: arial;
    }

    .terminal-3357607941-r1 { fill: #ffffff }
.terminal-3357607941-r2 { fill: #ffffff;font-weight: bold }
.terminal-3357607941-r3 { fill: #c5c8c6 }
.terminal-3357607941-r4 { fill: #6ae4b9;font-weight: bold;font-style: italic; }
.terminal-3357607941-r5 { fill: #989898 }
.terminal-3357607941-r6 { fill: #989898;font-style: italic; }
.terminal-3357607941-r7 { fill: #fec43f;font-style: italic; }
.terminal-3357607941-r8 { fill: #00d3d0 }
.terminal-3357607941-r9 { fill: #f78fe7;font-weight: bold }
.terminal-3357607941-r10 { fill: #b6a0ff;font-weight: bold }
.terminal-3357607941-r11 { fill: #ff3030 }
.terminal-3357607941-r12 { fill: #969696 }
.terminal-3357607941-r13 { fill: #2fafff;font-weight: bold }
.terminal-3357607941-r14 { fill: #969696;font-weight: bold }
.terminal-3357607941-r15 { fill: #ff5f59;font-weight: bold }
.terminal-3357607941-r16 { fill: #fec43f;font-weight: bold }
.terminal-3357607941-r17 { fill: #6ae4b9;font-weight: bold }
    &lt;/style&gt;

    &lt;defs&gt;
    &lt;clipPath id=&#34;terminal-3357607941-clip-terminal&#34;&gt;
      &lt;rect x=&#34;0&#34; y=&#34;0&#34; width=&#34;914.0&#34; height=&#34;633.4&#34;&gt;&lt;/rect&gt;
    &lt;/clipPath&gt;
    &lt;clipPath id=&#34;terminal-3357607941-line-0&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;1.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-1&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;25.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-2&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;50.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-3&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;74.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-4&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;99.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-5&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;123.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-6&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;147.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-7&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;172.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-8&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;196.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-9&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;221.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-10&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;245.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-11&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;269.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-12&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;294.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-13&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;318.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-14&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;343.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-15&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;367.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-16&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;391.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-17&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;416.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-18&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;440.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-19&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;465.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-20&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;489.5&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-21&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;513.9&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-22&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;538.3&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-23&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;562.7&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
&lt;clipPath id=&#34;terminal-3357607941-line-24&#34;&gt;
    &lt;rect x=&#34;0&#34; y=&#34;587.1&#34; width=&#34;915&#34; height=&#34;24.65&#34;&gt;&lt;/rect&gt;
            &lt;/clipPath&gt;
    &lt;/defs&gt;

    &lt;rect fill=&#34;#292929&#34; stroke=&#34;rgba(255,255,255,0.35)&#34; stroke-width=&#34;1&#34; x=&#34;1&#34; y=&#34;1&#34; width=&#34;931&#34; height=&#34;682.4&#34; rx=&#34;8&#34;&gt;&lt;/rect&gt;
            &lt;g transform=&#34;translate(26,22)&#34;&gt;
            &lt;circle cx=&#34;0&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#ff5f57&#34;&gt;&lt;/circle&gt;
            &lt;circle cx=&#34;22&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#febc2e&#34;&gt;&lt;/circle&gt;
            &lt;circle cx=&#34;44&#34; cy=&#34;0&#34; r=&#34;7&#34; fill=&#34;#28c840&#34;&gt;&lt;/circle&gt;
            &lt;/g&gt;

    &lt;g transform=&#34;translate(9, 41)&#34; clip-path=&#34;url(#terminal-3357607941-clip-terminal)&#34;&gt;
    &lt;rect fill=&#34;#313131&#34; x=&#34;0&#34; y=&#34;1.5&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;12.2&#34; y=&#34;1.5&#34; width=&#34;231.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#313131&#34; x=&#34;244&#34; y=&#34;1.5&#34; width=&#34;671&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;25.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;73.2&#34; y=&#34;25.9&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;85.4&#34; y=&#34;25.9&#34; width=&#34;829.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;50.3&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;74.7&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;99.1&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;123.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;73.2&#34; y=&#34;123.5&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;85.4&#34; y=&#34;123.5&#34; width=&#34;829.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;147.9&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;172.3&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;196.7&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;221.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;73.2&#34; y=&#34;221.1&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;109.8&#34; y=&#34;221.1&#34; width=&#34;805.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;245.5&#34; width=&#34;915&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;269.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;73.2&#34; y=&#34;269.9&#34; width=&#34;841.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#535353&#34; x=&#34;0&#34; y=&#34;294.3&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#535353&#34; x=&#34;36.6&#34; y=&#34;294.3&#34; width=&#34;122&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#535353&#34; x=&#34;158.6&#34; y=&#34;294.3&#34; width=&#34;756.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;318.7&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;318.7&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;318.7&#34; width=&#34;97.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;195.2&#34; y=&#34;318.7&#34; width=&#34;707.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;902.8&#34; y=&#34;318.7&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;343.1&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;343.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;343.1&#34; width=&#34;170.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;268.4&#34; y=&#34;343.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;280.6&#34; y=&#34;343.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;353.8&#34; y=&#34;343.1&#34; width=&#34;561.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;367.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;367.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;367.5&#34; width=&#34;97.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;195.2&#34; y=&#34;367.5&#34; width=&#34;183&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;378.2&#34; y=&#34;367.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;414.8&#34; y=&#34;367.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;451.4&#34; y=&#34;367.5&#34; width=&#34;463.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;391.9&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;391.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;391.9&#34; width=&#34;97.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;195.2&#34; y=&#34;391.9&#34; width=&#34;61&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;256.2&#34; y=&#34;391.9&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;268.4&#34; y=&#34;391.9&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;305&#34; y=&#34;391.9&#34; width=&#34;610&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;416.3&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;416.3&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;416.3&#34; width=&#34;146.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;244&#34; y=&#34;416.3&#34; width=&#34;183&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;427&#34; y=&#34;416.3&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;463.6&#34; y=&#34;416.3&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;500.2&#34; y=&#34;416.3&#34; width=&#34;414.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;440.7&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;440.7&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;440.7&#34; width=&#34;146.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#8b1a1a&#34; x=&#34;244&#34; y=&#34;440.7&#34; width=&#34;122&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;366&#34; y=&#34;440.7&#34; width=&#34;549&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;465.1&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;465.1&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;465.1&#34; width=&#34;146.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;244&#34; y=&#34;465.1&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;268.4&#34; y=&#34;465.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;280.6&#34; y=&#34;465.1&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;317.2&#34; y=&#34;465.1&#34; width=&#34;597.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;489.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;489.5&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;489.5&#34; width=&#34;195.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;292.8&#34; y=&#34;489.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;317.2&#34; y=&#34;489.5&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;341.6&#34; y=&#34;489.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;378.2&#34; y=&#34;489.5&#34; width=&#34;268.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;646.6&#34; y=&#34;489.5&#34; width=&#34;36.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;683.2&#34; y=&#34;489.5&#34; width=&#34;231.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;513.9&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;513.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;513.9&#34; width=&#34;244&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;341.6&#34; y=&#34;513.9&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;414.8&#34; y=&#34;513.9&#34; width=&#34;500.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;538.3&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#1e1e1e&#34; x=&#34;24.4&#34; y=&#34;538.3&#34; width=&#34;73.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;538.3&#34; width=&#34;817.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;562.7&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#535353&#34; x=&#34;48.8&#34; y=&#34;562.7&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;97.6&#34; y=&#34;562.7&#34; width=&#34;195.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;292.8&#34; y=&#34;562.7&#34; width=&#34;48.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;341.6&#34; y=&#34;562.7&#34; width=&#34;573.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;0&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;12.2&#34; y=&#34;587.1&#34; width=&#34;183&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;195.2&#34; y=&#34;587.1&#34; width=&#34;24.4&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;219.6&#34; y=&#34;587.1&#34; width=&#34;109.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;329.4&#34; y=&#34;587.1&#34; width=&#34;341.6&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;671&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;683.2&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;695.4&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;707.6&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;719.8&#34; y=&#34;587.1&#34; width=&#34;12.2&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#303030&#34; x=&#34;732&#34; y=&#34;587.1&#34; width=&#34;183&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;&lt;rect fill=&#34;#4b4e55&#34; x=&#34;0&#34; y=&#34;611.5&#34; width=&#34;902.8&#34; height=&#34;24.65&#34; shape-rendering=&#34;crispEdges&#34;&gt;&lt;/rect&gt;
    &lt;g class=&#34;terminal-3357607941-matrix&#34;&gt;
    &lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;20&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-0)&#34;&gt;|&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r2&#34; x=&#34;12.2&#34; y=&#34;20&#34; textLength=&#34;231.8&#34; clip-path=&#34;url(#terminal-3357607941-line-0)&#34;&gt;*gud-test*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;244&#34; y=&#34;20&#34; textLength=&#34;671&#34; clip-path=&#34;url(#terminal-3357607941-line-0)&#34;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[89%]&amp;nbsp;21:17&amp;nbsp;18/06/25&amp;nbsp;☰&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;20&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-0)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r4&#34; x=&#34;0&#34; y=&#34;44.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-1)&#34;&gt;(Pdb)&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r2&#34; x=&#34;73.2&#34; y=&#34;44.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-1)&#34;&gt;n&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;44.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-1)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;68.8&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3357607941-line-2)&#34;&gt;&amp;gt;&amp;nbsp;/var/home/alex/Projects/swyddfa/lsp-devtools/develop/lib/lsp-devtools/ls\&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;68.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-2)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;93.2&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3357607941-line-3)&#34;&gt;p_devtools/agent/server.py(166)feed()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;93.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-3)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;117.6&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3357607941-line-4)&#34;&gt;-&amp;gt;&amp;nbsp;if&amp;nbsp;(idx&amp;nbsp;:=&amp;nbsp;state.buffer.find(SEP))&amp;nbsp;==&amp;nbsp;-1:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;117.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-4)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r4&#34; x=&#34;0&#34; y=&#34;142&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-5)&#34;&gt;(Pdb)&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r2&#34; x=&#34;73.2&#34; y=&#34;142&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-5)&#34;&gt;n&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;142&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-5)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;166.4&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3357607941-line-6)&#34;&gt;&amp;gt;&amp;nbsp;/var/home/alex/Projects/swyddfa/lsp-devtools/develop/lib/lsp-devtools/ls\&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;166.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-6)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;190.8&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3357607941-line-7)&#34;&gt;p_devtools/agent/server.py(169)feed()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;190.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-7)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;215.2&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3357607941-line-8)&#34;&gt;-&amp;gt;&amp;nbsp;line,&amp;nbsp;state.buffer&amp;nbsp;=&amp;nbsp;state.buffer[:idx],&amp;nbsp;state.buffer[idx&amp;nbsp;+&amp;nbsp;len(SEP)&amp;nbsp;:]&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;215.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-8)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r4&#34; x=&#34;0&#34; y=&#34;239.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-9)&#34;&gt;(Pdb)&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r2&#34; x=&#34;73.2&#34; y=&#34;239.6&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-9)&#34;&gt;idx&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;239.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-9)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;264&#34; textLength=&#34;915&#34; clip-path=&#34;url(#terminal-3357607941-line-10)&#34;&gt;30&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;264&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-10)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r4&#34; x=&#34;0&#34; y=&#34;288.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-11)&#34;&gt;(Pdb)&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;288.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-11)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;312.8&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-12)&#34;&gt;-&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r2&#34; x=&#34;36.6&#34; y=&#34;312.8&#34; textLength=&#34;122&#34; clip-path=&#34;url(#terminal-3357607941-line-12)&#34;&gt;*gud-test*&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;158.6&#34; y=&#34;312.8&#34; textLength=&#34;756.4&#34; clip-path=&#34;url(#terminal-3357607941-line-12)&#34;&gt;&amp;nbsp;60:6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Debugger:run&amp;nbsp;Apheleia)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;312.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-12)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;337.2&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-13)&#34;&gt;&amp;nbsp;&amp;nbsp;160&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r6&#34; x=&#34;195.2&#34; y=&#34;337.2&#34; textLength=&#34;707.6&#34; clip-path=&#34;url(#terminal-3357607941-line-13)&#34;&gt;#&amp;nbsp;So&amp;nbsp;we&amp;nbsp;will&amp;nbsp;keep&amp;nbsp;running&amp;nbsp;that&amp;nbsp;parser&amp;nbsp;as&amp;nbsp;long&amp;nbsp;as&amp;nbsp;the&amp;nbsp;buffe&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;902.8&#34; y=&#34;337.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-13)&#34;&gt;\&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;337.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-13)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r6&#34; x=&#34;97.6&#34; y=&#34;361.6&#34; textLength=&#34;170.8&#34; clip-path=&#34;url(#terminal-3357607941-line-14)&#34;&gt;r&amp;nbsp;continues&amp;nbsp;to&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r6&#34; x=&#34;280.6&#34; y=&#34;361.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-14)&#34;&gt;shrink&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;361.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-14)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;386&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-15)&#34;&gt;&amp;nbsp;&amp;nbsp;161&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r8&#34; x=&#34;195.2&#34; y=&#34;386&#34; textLength=&#34;183&#34; clip-path=&#34;url(#terminal-3357607941-line-15)&#34;&gt;previous_length&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;378.2&#34; y=&#34;386&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-15)&#34;&gt;&amp;nbsp;=&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r9&#34; x=&#34;414.8&#34; y=&#34;386&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-15)&#34;&gt;len&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;451.4&#34; y=&#34;386&#34; textLength=&#34;463.6&#34; clip-path=&#34;url(#terminal-3357607941-line-15)&#34;&gt;(state.buffer)&amp;nbsp;+&amp;nbsp;1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;386&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-15)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;410.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-16)&#34;&gt;&amp;nbsp;&amp;nbsp;162&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r10&#34; x=&#34;195.2&#34; y=&#34;410.4&#34; textLength=&#34;61&#34; clip-path=&#34;url(#terminal-3357607941-line-16)&#34;&gt;while&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r9&#34; x=&#34;268.4&#34; y=&#34;410.4&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-16)&#34;&gt;len&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;305&#34; y=&#34;410.4&#34; textLength=&#34;610&#34; clip-path=&#34;url(#terminal-3357607941-line-16)&#34;&gt;(state.buffer)&amp;nbsp;&amp;lt;&amp;nbsp;previous_length:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;410.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-16)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;434.8&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-17)&#34;&gt;&amp;nbsp;&amp;nbsp;163&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r8&#34; x=&#34;244&#34; y=&#34;434.8&#34; textLength=&#34;183&#34; clip-path=&#34;url(#terminal-3357607941-line-17)&#34;&gt;previous_length&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;427&#34; y=&#34;434.8&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-17)&#34;&gt;&amp;nbsp;=&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r9&#34; x=&#34;463.6&#34; y=&#34;434.8&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-17)&#34;&gt;len&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;500.2&#34; y=&#34;434.8&#34; textLength=&#34;414.8&#34; clip-path=&#34;url(#terminal-3357607941-line-17)&#34;&gt;(state.buffer)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;434.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-17)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;459.2&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-18)&#34;&gt;&amp;nbsp;&amp;nbsp;164&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r11&#34; x=&#34;244&#34; y=&#34;459.2&#34; textLength=&#34;122&#34; clip-path=&#34;url(#terminal-3357607941-line-18)&#34;&gt;breakpoint&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;366&#34; y=&#34;459.2&#34; textLength=&#34;549&#34; clip-path=&#34;url(#terminal-3357607941-line-18)&#34;&gt;()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;459.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-18)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;483.6&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-19)&#34;&gt;&amp;nbsp;&amp;nbsp;165&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r10&#34; x=&#34;244&#34; y=&#34;483.6&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3357607941-line-19)&#34;&gt;if&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r10&#34; x=&#34;280.6&#34; y=&#34;483.6&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-19)&#34;&gt;not&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;317.2&#34; y=&#34;483.6&#34; textLength=&#34;597.8&#34; clip-path=&#34;url(#terminal-3357607941-line-19)&#34;&gt;&amp;nbsp;state.headers_complete:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;483.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-19)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;508&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-20)&#34;&gt;&amp;nbsp;&amp;nbsp;166&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r10&#34; x=&#34;292.8&#34; y=&#34;508&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3357607941-line-20)&#34;&gt;if&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;317.2&#34; y=&#34;508&#34; textLength=&#34;24.4&#34; clip-path=&#34;url(#terminal-3357607941-line-20)&#34;&gt;&amp;nbsp;(&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r8&#34; x=&#34;341.6&#34; y=&#34;508&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-20)&#34;&gt;idx&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;378.2&#34; y=&#34;508&#34; textLength=&#34;268.4&#34; clip-path=&#34;url(#terminal-3357607941-line-20)&#34;&gt;&amp;nbsp;:=&amp;nbsp;state.buffer.find(&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r2&#34; x=&#34;646.6&#34; y=&#34;508&#34; textLength=&#34;36.6&#34; clip-path=&#34;url(#terminal-3357607941-line-20)&#34;&gt;SEP&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;683.2&#34; y=&#34;508&#34; textLength=&#34;231.8&#34; clip-path=&#34;url(#terminal-3357607941-line-20)&#34;&gt;))&amp;nbsp;==&amp;nbsp;-1:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;508&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-20)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;532.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-21)&#34;&gt;&amp;nbsp;&amp;nbsp;167&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r10&#34; x=&#34;341.6&#34; y=&#34;532.4&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-21)&#34;&gt;return&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;532.4&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-21)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r5&#34; x=&#34;24.4&#34; y=&#34;556.8&#34; textLength=&#34;73.2&#34; clip-path=&#34;url(#terminal-3357607941-line-22)&#34;&gt;&amp;nbsp;&amp;nbsp;168&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;556.8&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-22)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;0&#34; y=&#34;581.2&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3357607941-line-23)&#34;&gt;&amp;nbsp;&amp;nbsp;=&amp;gt;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r2&#34; x=&#34;48.8&#34; y=&#34;581.2&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3357607941-line-23)&#34;&gt;169&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r8&#34; x=&#34;292.8&#34; y=&#34;581.2&#34; textLength=&#34;48.8&#34; clip-path=&#34;url(#terminal-3357607941-line-23)&#34;&gt;line&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r1&#34; x=&#34;341.6&#34; y=&#34;581.2&#34; textLength=&#34;573.4&#34; clip-path=&#34;url(#terminal-3357607941-line-23)&#34;&gt;,&amp;nbsp;state.buffer&amp;nbsp;=&amp;nbsp;state.buffer[:idx],&amp;nbsp;state.buf\&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;581.2&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-23)&#34;&gt;
&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r12&#34; x=&#34;0&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;-&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r13&#34; x=&#34;12.2&#34; y=&#34;605.6&#34; textLength=&#34;183&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;🖿&amp;nbsp;lsp-devtools&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r14&#34; x=&#34;219.6&#34; y=&#34;605.6&#34; textLength=&#34;109.8&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;server.py&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r12&#34; x=&#34;329.4&#34; y=&#34;605.6&#34; textLength=&#34;341.6&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;&amp;nbsp;169:0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Python&amp;nbsp;Flymake[&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r15&#34; x=&#34;671&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;0&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r16&#34; x=&#34;695.4&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;0&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r17&#34; x=&#34;719.8&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;1&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r12&#34; x=&#34;732&#34; y=&#34;605.6&#34; textLength=&#34;183&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;]&amp;nbsp;ws&amp;nbsp;Apheleia©&amp;nbsp;&lt;/text&gt;&lt;text class=&#34;terminal-3357607941-r3&#34; x=&#34;915&#34; y=&#34;605.6&#34; textLength=&#34;12.2&#34; clip-path=&#34;url(#terminal-3357607941-line-24)&#34;&gt;
&lt;/text&gt;
    &lt;/g&gt;
    &lt;/g&gt;
&lt;/svg&gt;&lt;p&gt;Which is better, but it still isn’t an accurate representation of what I see in my terminal.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;colour-palette&#34;&gt;
&lt;h3&gt;Colour Palette&lt;a class=&#34;headerlink&#34; href=&#34;#colour-palette&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Aside from providing specific RGB values, SGR codes also allow for applications to choose from a palette of 16 colours - 8 “normal” and 8 “bright” colours.&lt;/p&gt;
&lt;p&gt;The specific colours in this palette are of course dependent on whatever theme you have configured in your terminal emulator, so the final step is to ensure that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;rich&lt;/span&gt;&lt;/code&gt; uses the same colour palette as my terminal.&lt;/p&gt;
&lt;p&gt;Thankfully the asciicast format supports recording this information alongside the width and height, all we need to do is extend the screenshot command in WezTerm to populate it.&lt;/p&gt;
&lt;div class=&#34;highlight-lua notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_builtin_color_schemes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;effective_config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;color_scheme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;o&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_lines_as_escapes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cols&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;cols&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;rows&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;viewport_rows&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;fg&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;foreground&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;bg&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;palette&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;table.concat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;append_tables&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;ansi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;brights&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;details&gt;&lt;summary&gt;Expand to see the complete command implementation&lt;/summary&gt;&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wezterm/commands/screenshot.lua&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-lua notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;wezterm&amp;#39;&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;io&amp;#39;&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;os&amp;#39;&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;act&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;action&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;M&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;append_tables&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(...)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;tbl&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;ipairs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({...})&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;do&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;tbl&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;do&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;tbl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;

&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;M&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;augment-command-palette&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;brief&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Take screenshot&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;icon&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;cod_device_camera&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;action&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;act&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;PromptInputLine&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Screenshot name&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;-- initial_value = os.date(&amp;#39;%Y%m%dT%H%M%S--terminal-screenshot&amp;#39;), -- apparently this requires a nightly build&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;action&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;action_callback&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;then&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_builtin_color_schemes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;effective_config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;color_scheme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;o&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_lines_as_escapes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cols&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;cols&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;rows&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dimensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;viewport_rows&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;fg&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;foreground&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;bg&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;palette&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;table.concat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;append_tables&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;ansi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;brights&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;io.open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.cast&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;w+&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;json_encode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wezterm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;json_encode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;kr&#34;&gt;end&lt;/span&gt;

&lt;span class=&#34;kr&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;M&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;&lt;p&gt;Which of course requires a similar update to the rendering code&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;term&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;ansi_colors&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;theme&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;palette&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;theme&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TerminalTheme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;theme&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;bg&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;triplet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;foreground&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;theme&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;fg&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;triplet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;normal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;col&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;triplet&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;col&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ansi_colors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]],&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;bright&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;col&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;triplet&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;col&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ansi_colors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:]],&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;svg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_svg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;options&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which, finally, results in the SVG you saw at the start of this blog post!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;sphinx-integration&#34;&gt;
&lt;h2&gt;Sphinx Integration&lt;a class=&#34;headerlink&#34; href=&#34;#sphinx-integration&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When working on a post for this site, I want to be able to just include the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;*.cast&lt;/span&gt;&lt;/code&gt; file produced by WezTerm as I would with any other image&lt;/p&gt;
&lt;div class=&#34;highlight-rst notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;termshot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt; /images/example.cast
   &lt;span class=&#34;nc&#34;&gt;:title:&lt;/span&gt; Example
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and have Sphinx perform the conversion to SVG automatically during the build.
This can be done by creating a custom &lt;a class=&#34;reference external&#34; href=&#34;https://docutils.sourceforge.io/docs/howto/rst-directives.html&#34;&gt;directive&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The following class defintion defines the interface for the directive, we want it accept a single argument (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/images/example.cast&lt;/span&gt;&lt;/code&gt;)
and have the option to specify a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;:title:&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Termshot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SphinxDirective&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;required_arguments&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;optional_arguments&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;final_argument_whitespace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;option_spec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directives&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unchanged&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Each directive has a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;run()&lt;/span&gt;&lt;/code&gt; method, which should return a list of nodes which are inserted into the document at the location where the directive was used.&lt;/p&gt;
&lt;p&gt;Other Sphinx directives like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;figure::&lt;/span&gt;&lt;/code&gt; or &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;include::&lt;/span&gt;&lt;/code&gt; interpret absolute paths as paths relative to the project root.
I want the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;termshot::&lt;/span&gt;&lt;/code&gt; directive to behave in the same way, so I pass the given filepath through the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;self.env.relfn2path&lt;/span&gt;&lt;/code&gt; function which handles that for me&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fpath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;relfn2path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arguments&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once the svg has been generated, it needs to be included in the final HTML somehow, there are many way to approach this but for simplicity I’ve opted to inline the SVG code using a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;raw&lt;/span&gt;&lt;/code&gt; docutils node.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;svg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_svg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;options&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;svg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;html&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;details&gt;&lt;summary&gt;Expand to see the complete implementation&lt;/summary&gt;&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;__future__&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;annotations&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;io&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;json&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;pathlib&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;typing&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;os.path&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;abspath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;relpath&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;docutils&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;docutils.parsers.rst&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directives&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;rich.color&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;rich.console&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Console&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;rich.terminal_theme&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TerminalTheme&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;rich.text&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Text&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;sphinx.util.docutils&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SphinxDirective&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;typing&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TYPE_CHECKING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;sphinx.application&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Sphinx&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Termshot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SphinxDirective&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;required_arguments&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;optional_arguments&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;final_argument_whitespace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;option_spec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directives&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unchanged&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fpath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;relfn2path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arguments&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fpath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;header&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loads&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;body&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loads&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;

        &lt;span class=&#34;n&#34;&gt;term&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;term&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;ansi_colors&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;theme&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;palette&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;n&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Text&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from_ansi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;theme&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TerminalTheme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;theme&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;bg&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;triplet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;foreground&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;theme&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;fg&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;triplet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;normal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;col&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;triplet&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;col&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ansi_colors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]],&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;bright&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;col&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;triplet&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;col&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ansi_colors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:]],&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;n&#34;&gt;console&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;StringIO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;force_terminal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cols&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;term&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;rows&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;svg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_svg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;options&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;svg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;html&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Sphinx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_directive&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;termshot&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Termshot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;parallel_read_safe&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2025/blogging-with-sphinx-and-denoteel/</id>
    <link href="https://www.alcarney.me/blog/2025/blogging-with-sphinx-and-denoteel" rel="alternate" />
    <published>2025-05-17T00:00:00+00:00</published>
    <updated>2025-05-17T00:00:00+00:00</updated>
    <title>Blogging with Sphinx and denote.el</title>
    <content type="html">
      &lt;section id=&#34;blogging-with-sphinx-and-denote-el&#34;&gt;
&lt;h1&gt;Blogging with Sphinx and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#blogging-with-sphinx-and-denote-el&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;If you have spent any time following the Emacs community, you will have likely come across the &lt;a class=&#34;reference external&#34; href=&#34;https://protesilaos.com/emacs/denote&#34;&gt;denote.el&lt;/a&gt; project.
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt; defines a clever file-naming scheme and provides an associated Emacs package containing utilities for managing files which follow this naming scheme.&lt;/p&gt;
&lt;p&gt;In this blog post I outline how I have adopted &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt; to manage the content on this site and how I’ve extended &lt;a class=&#34;reference external&#34; href=&#34;https://www.sphinx-doc.org/en/master/index.html&#34;&gt;Sphinx&lt;/a&gt; to take advantage this.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;denote-el-basics&#34;&gt;
&lt;h2&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt; basics&lt;a class=&#34;headerlink&#34; href=&#34;#denote-el-basics&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For an in-depth introduction to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt; be sure to check out &lt;a class=&#34;reference external&#34; href=&#34;https://www.youtube.com/watch?v=mLzFJcLpDFI&amp;amp;list=PL8Bwba5vnQK0F6gR0AGOQH48xbLRe_qWC&amp;amp;index=2&#34;&gt;this video&lt;/a&gt; however, as mentioned in the introduction, the core of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt; is the file-naming sheme:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&amp;lt;timestamp&amp;gt;--&amp;lt;title&amp;gt;__&amp;lt;tags&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;where&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;timestamp&amp;gt;&lt;/span&gt;&lt;/code&gt; captures the date and time the file was created and acts as the file’s unique identifier&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;/code&gt; a lowercase &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;-&lt;/span&gt;&lt;/code&gt; separated string which captures your traditional file name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;tags&amp;gt;&lt;/span&gt;&lt;/code&gt; (called keywords by denote) is a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;_&lt;/span&gt;&lt;/code&gt; separated string of tag names&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As an example the filename for this blog post is:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;20250217T182726--blogging-with-sphinx-and-denoteel__blog_blogging_denote_emacs_sphinx.rst
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The main benefit in naming your files in this way is that you can perform some fairly sophisticated queries across your files with simple text based searches.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;restructuredtext-and-denote-el&#34;&gt;
&lt;span id=&#34;denote-rst&#34;&gt;&lt;/span&gt;&lt;h2&gt;reStructuredText and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#restructuredtext-and-denote-el&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While I don’t use Emacs all the time, it’s safe to say that it has become my default editor when working on personal projects.
So it’s nice to be able to make use of the utilities provided by the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/protesilaos/denote&#34;&gt;denote.el&lt;/a&gt; package when working on this site.&lt;/p&gt;
&lt;p&gt;One of the main features provided by the package is to insert &lt;a class=&#34;reference external&#34; href=&#34;https://protesilaos.com/emacs/denote#h:13218826-56a5-482a-9b91-5b6de4f14261&#34;&gt;front matter&lt;/a&gt; into your notes corresponding to the information encoded in the filename &lt;strong&gt;and&lt;/strong&gt; to keep the two in sync when either one changes.&lt;/p&gt;
&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt; has built in support for several markup formats however, the &lt;a class=&#34;reference external&#34; href=&#34;https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#rst-primer&#34; title=&#34;(in Sphinx v9.1.0)&#34;&gt;&lt;span class=&#34;xref std std-ref&#34;&gt;reStructuredText&lt;/span&gt;&lt;/a&gt; syntax used by Sphinx is not one of them.
Of course, being an Emacs package this isn’t something that a few lines of lisp cannot solve!&lt;/p&gt;
&lt;div class=&#34;admonition-what-about-markdown admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;What about Markdown?&lt;/p&gt;
&lt;p&gt;Yes, both &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt; and &lt;a class=&#34;reference external&#34; href=&#34;https://www.sphinx-doc.org/en/master/usage/markdown.html#markdown&#34; title=&#34;(in Sphinx v9.1.0)&#34;&gt;&lt;span class=&#34;xref std std-ref&#34;&gt;Sphinx support&lt;/span&gt;&lt;/a&gt; Markdown however, I simply prefer reStructuredText 😅&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;highlight-elisp notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;use-package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:ensure&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:hook&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dired-mode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote-dired-mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:config&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;;; Add reStructuredText support to denote&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;add-to-list&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;&amp;#39;denote-file-types&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;rst&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:extension&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;.rst&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:date-key-regexp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;^:date:&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:date-value-function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote-date-iso-8601&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:date-value-reverse-function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote-extract-date-from-front-matter&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:front-matter&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;:title: %s\n:date: %s\n:tags: %s\n:identifier: %s\n\n&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:title-key-regexp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;^:title:&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:title-value-function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;identity&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:title-value-reverse-function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote-trim-whitespace&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:keywords-key-regexp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;^:tags:&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:keywords-value-function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;lambda&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;string-join&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ks&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:keywords-value-reverse-function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote-extract-keywords-from-front-matter&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:identifier-key-regexp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;^:identifier:&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:identifier-value-function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;identity&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:identifier-value-reverse-function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote-trim-whitespace&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:link&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;:denote:link:`%2$s &amp;lt;%1$s&amp;gt;`&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:link-in-context-regexp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;concat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;:denote:link:`.*?&amp;lt;\\(?1:&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote-id-regexp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;\\)&amp;gt;`&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which gives denote the information it needs to read and write its metadata using reStructuredText’s &lt;a class=&#34;reference external&#34; href=&#34;https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#rst-field-lists&#34; title=&#34;(in Sphinx v9.1.0)&#34;&gt;&lt;span class=&#34;xref std std-ref&#34;&gt;field list&lt;/span&gt;&lt;/a&gt; syntax.&lt;/p&gt;
&lt;div class=&#34;highlight-rst notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;:title:&lt;/span&gt; Blogging with Sphinx and denote.el
&lt;span class=&#34;nc&#34;&gt;:date:&lt;/span&gt; 2025-05-17
&lt;span class=&#34;nc&#34;&gt;:tags:&lt;/span&gt; blog, blogging, denote, emacs, sphinx
&lt;span class=&#34;nc&#34;&gt;:identifier:&lt;/span&gt; 20250217T182726
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It also instructs &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote&lt;/span&gt;&lt;/code&gt; to use a role called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote:link&lt;/span&gt;&lt;/code&gt; when inserting a link to another note, but we’ll come back to that a bit later on.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;sphinx-and-denote-el&#34;&gt;
&lt;h2&gt;Sphinx and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote.el&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#sphinx-and-denote-el&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Again, denote is primarily a file-naming scheme, so you don’t &lt;em&gt;have&lt;/em&gt; to do anything special to get it to work with Sphinx - it will just work&lt;sup&gt;TM&lt;/sup&gt;.
However, by extending Sphinx I get to smooth off some rough edges and take advantage of the metadata in the filename to build some nice features.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2025/blogging-with-sphinx-and-denoteel/#denote-sphinx-discover-content&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Discovering Content&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2025/blogging-with-sphinx-and-denoteel/#denote-sphinx-mark-posts&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Using Tags to Mark Blog Posts&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2025/blogging-with-sphinx-and-denoteel/#denote-sphinx-pretty-urls&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Pretty URLs&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2025/blogging-with-sphinx-and-denoteel/#denote-sphinx-cross-references&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Cross References&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;I’m only going to elaborate on some aspects of the code underpinning this, so if you want the full details be sure to take a look at the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/blog/blob/6fecce876ffbb808390a6b59a62ae081abaaf395/extensions/denote&#34;&gt;complete implementation&lt;/a&gt; of the denote extension.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;The &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/blog/blob/6fecce876ffbb808390a6b59a62ae081abaaf395/extensions/denote/record.py#L15&#34;&gt;Record&lt;/a&gt;
dataclass captures all of the information encoded in and derived from a denote style filename.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/blog/blob/6fecce876ffbb808390a6b59a62ae081abaaf395/extensions/denote/domain.py#L83&#34;&gt;Denote&lt;/a&gt; Sphinx &lt;a class=&#34;reference external&#34; href=&#34;https://www.sphinx-doc.org/en/master/extdev/domainapi.html#domain-api&#34; title=&#34;(in Sphinx v9.1.0)&#34;&gt;&lt;span class=&#34;xref std std-ref&#34;&gt;Domain&lt;/span&gt;&lt;/a&gt; is the main store of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Record&lt;/span&gt;&lt;/code&gt; instances and can be thought of as the “backend” of the extension.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The rest of the extension uses the APIs provided by the two above classes to integrate with Sphinx at various points in the build lifecycle.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;section id=&#34;discovering-content&#34;&gt;
&lt;span id=&#34;denote-sphinx-discover-content&#34;&gt;&lt;/span&gt;&lt;h3&gt;Discovering Content&lt;a class=&#34;headerlink&#34; href=&#34;#discovering-content&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Thanks to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;source-read&lt;/span&gt;&lt;/code&gt; event it’s trivial to build an index of all the files in the Sphinx project that have a denote style filename&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;discover_records&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Sphinx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]):&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;Discover and index records based on their filename&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;docpath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;record&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docpath&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Denote&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;domains&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;denote&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_record&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once Sphinx has parsed the file the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;doctree-read&lt;/span&gt;&lt;/code&gt; event is emitted, which we can use to extract additional information from the file’s front matter and content.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;parse_records&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Sphinx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;doctree&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;Extract additional information from a document&amp;#39;s content&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Denote&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;domains&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;denote&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;metadata&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{})&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;record&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;records&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;doctree&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next_node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;condition&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;descend&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;astext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;date&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timestamp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fromisoformat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

        &lt;span class=&#34;c1&#34;&gt;# Assume UTC if no timezone available&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timestamp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tzinfo&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timestamp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timestamp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tzinfo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;UTC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I primarily use this to change the post date or title without having to change the identifier or title portions of the filename - which would lead to broken links.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;using-tags-to-mark-blog-posts&#34;&gt;
&lt;span id=&#34;denote-sphinx-mark-posts&#34;&gt;&lt;/span&gt;&lt;h3&gt;Using Tags to Mark Blog Posts&lt;a class=&#34;headerlink&#34; href=&#34;#using-tags-to-mark-blog-posts&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are currently two main sections to this site - blog posts and notes (the code section is broken and we can talk about dotfiles another time! 😅).&lt;/p&gt;
&lt;p&gt;The obvious solution to this would be to create a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;blog/&lt;/span&gt;&lt;/code&gt; folder and a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;notes/&lt;/span&gt;&lt;/code&gt; folder and call it a day.
However, denote lends itself well to having just a folder full of files and I quite liked the idea of dumping all my files into a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;content/&lt;/span&gt;&lt;/code&gt; folder and using tags to… &lt;em&gt;ahem&lt;/em&gt; denote different types of content.&lt;/p&gt;
&lt;p&gt;This allows for a nice workflow where something can start as a note but can easily be promoted to a blog post if needed.&lt;/p&gt;
&lt;p&gt;Implementing this quite straightforward, choose a name for the tag (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;blog&lt;/span&gt;&lt;/code&gt;) and when it is found set the corresponding flag on the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Record&lt;/span&gt;&lt;/code&gt; instance. Note that I also remove the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;blog&lt;/span&gt;&lt;/code&gt; tag from the list of tags so that it does not appear in the list of tags in the sidebar.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;match&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FILENAME_PATTERN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;match&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;match&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;group&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;tags&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;remove&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;blog&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;is_blogpost&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;except&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;ValueError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;is_blogpost&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;False&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Record&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;is_blogpost&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_blogpost&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then make use of the flag when ever it’s relevant, for example when building the index of all blog posts&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;add_record&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Record&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;Add a record to the domain&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;
    &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;records&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_blogpost&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;posts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;pretty-urls&#34;&gt;
&lt;span id=&#34;denote-sphinx-pretty-urls&#34;&gt;&lt;/span&gt;&lt;h3&gt;Pretty URLs&lt;a class=&#34;headerlink&#34; href=&#34;#pretty-urls&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You may have noticed that the url to this page is not&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;https://www.alcarney.me/content/20250217T182726--blogging-with-sphinx-and-denoteel__blog_blogging_emacs_sphinx/
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is because I have created a custom Sphinx &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/blog/blob/6fecce876ffbb808390a6b59a62ae081abaaf395/extensions/denote/builder.py#L16&#34;&gt;builder&lt;/a&gt;, derived from the standard &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;DirectoryHTMLBuilder&lt;/span&gt;&lt;/code&gt; and which implements the following url scheme&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Blog posts are written to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/blog/&amp;lt;year&amp;gt;/&amp;lt;title&amp;gt;&lt;/span&gt;&lt;/code&gt; e.g. &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/blog/2025/blogging-with-sphinx-and-denoteel&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Notes are written to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/notes/&amp;lt;identifier&amp;gt;&lt;/span&gt;&lt;/code&gt; e.g. &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/notes/20250217T182726&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;admonition warning&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Warning&lt;/p&gt;
&lt;p&gt;This involves overwriting the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;get_target_uri&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;get_output_path&lt;/span&gt;&lt;/code&gt; methods on the base builder class, which I am 90% sure are &lt;strong&gt;not&lt;/strong&gt; part of Sphinx’s public API. This can and &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/blog/commit/61c21eb612d247ab34891ad76e74a27702ffef27#diff-a634783132b52e5d734032dc004c9ae0bb4db3ba32b3108a5b19714be4d7635d&#34;&gt;will&lt;/a&gt; break on you between Sphinx versions!&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;cross-references&#34;&gt;
&lt;span id=&#34;denote-sphinx-cross-references&#34;&gt;&lt;/span&gt;&lt;h3&gt;Cross References&lt;a class=&#34;headerlink&#34; href=&#34;#cross-references&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Remember back in the &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2025/blogging-with-sphinx-and-denoteel/#denote-rst&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;reStructuredText and denote.el&lt;/span&gt;&lt;/a&gt; section I instructed denote to use the following syntax when inserting links?&lt;/p&gt;
&lt;div class=&#34;highlight-elisp notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:link&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;:denote:link:`%2$s &amp;lt;%1$s&amp;gt;`&amp;quot;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;:link-in-context-regexp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;concat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;:denote:link:`.*?&amp;lt;\\(?1:&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;denote-id-regexp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;\\)&amp;gt;`&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This was so I could define a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;:denote:link:&lt;/span&gt;&lt;/code&gt; role as part of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Denote&lt;/span&gt;&lt;/code&gt; domain&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Denote&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Domain&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;A domain for denote style note taking.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;denote&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;roles&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;link&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;XRefRole&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and implement the &lt;a class=&#34;reference external&#34; href=&#34;https://www.sphinx-doc.org/en/master/extdev/domainapi.html#sphinx.domains.Domain.resolve_xref&#34; title=&#34;(in Sphinx v9.1.0)&#34;&gt;&lt;code class=&#34;xref py py-meth docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;resolve_xref()&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; method so that links generated by &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote-link&lt;/span&gt;&lt;/code&gt; and related commands link to the correct page when generating the html for this site&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;resolve_xref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BuildEnvironment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;fromdocname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;typ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pending_xref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;contnode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Element&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Element&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;Resolve cross references&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;record&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;records&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;identifier&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linktext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;contnode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;astext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;contnode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;contnode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linktext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;make_refnode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fromdocname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;docname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;contnode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition-example admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Example&lt;/p&gt;
&lt;p&gt;Here are links to &lt;a class=&#34;reference internal&#34; href=&#34;../notes/20250216T190756/&#34; title=&#34;My Emacs Configuration&#34;&gt;My Emacs Configuration&lt;/a&gt; and my &lt;a class=&#34;reference internal&#34; href=&#34;../notes/20250216T190621/&#34; title=&#34;Neovim&#34;&gt;neovim config&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See below for how this looks in the source for this page&lt;/p&gt;
&lt;div class=&#34;highlight-rst notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;admonition&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt; Example

   Here are links to &lt;span class=&#34;na&#34;&gt;:denote:link:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;`20250216T190756`&lt;/span&gt; and my &lt;span class=&#34;na&#34;&gt;:denote:link:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;`neovim config &amp;lt;20250216T190621&amp;gt;`&lt;/span&gt;.

   See below for how this looks in the source for this page

&lt;span class=&#34;p&#34;&gt;   ..&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;literalinclude&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt; ./20250217T182726==1--blogging-with-sphinx-and-denoteel__blog_blogging_denote_emacs_sphinx.rst
      &lt;span class=&#34;nc&#34;&gt;:language:&lt;/span&gt; rst
      &lt;span class=&#34;nc&#34;&gt;:start-at:&lt;/span&gt; .. admonition:: Example
      &lt;span class=&#34;nc&#34;&gt;:end-at:&lt;/span&gt; Generating
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;generating-feeds-and-archives&#34;&gt;
&lt;span id=&#34;blog-generating-feeds-archives&#34;&gt;&lt;/span&gt;&lt;h3&gt;Generating Feeds and Archives&lt;a class=&#34;headerlink&#34; href=&#34;#generating-feeds-and-archives&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is mainly &lt;span class=&#34;line-through&#34;&gt;stolen from&lt;/span&gt; inspired by the &lt;a class=&#34;reference external&#34; href=&#34;https://ablog.readthedocs.io/en/stable/&#34;&gt;ablog&lt;/a&gt; extension (which is a great extension if you want a Sphinx-powered blog by the way)&lt;/p&gt;
&lt;p&gt;Using the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;html-collect-pages&lt;/span&gt;&lt;/code&gt; event it’s possible to generate entirely new pages during the build process and since all of denote’s metadata is right there in the filename it’s easy to select just the subsets of files you are interested in&lt;/p&gt;
&lt;p&gt;Currently I generate&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An index of all blog posts&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;generate_collections&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Sphinx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;Generate collections of records according to some criteria&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Denote&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;domains&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;denote&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

    &lt;span class=&#34;c1&#34;&gt;# Emit an all blog posts page&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;collection&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;posts&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;Blog&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;blog&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;blog/collection.html&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An RSS feed of all blog posts&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;baseurl&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blog_baseurl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blog_title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;now&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tz&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;UTC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;relurl&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;blog/atom.xml&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
        &lt;span class=&#34;s2&#34;&gt;&amp;quot;sphinx_version&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;8&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;blog/atom&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;blog/atom.xml&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An index of all blog posts in a given year&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;by_year&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;posts&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;by_year&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;year&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;collection&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;by_year&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;collection&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;collection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Posts in &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;year&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;blog/&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;year&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;blog/collection.html&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An index of all blog posts &lt;em&gt;and notes&lt;/em&gt; with a given tag&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;by_tag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;records&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;by_tag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;tags&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;by_tag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;blog/tags.html&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;links&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;all_records&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;collection&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;by_tag&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;nodes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;kind&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;tag&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;collection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;links&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;source&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;identifier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;target&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;all_records&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;identifier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;collection&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;collection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Tagged with: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;tag/&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;blog/collection.html&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I still need to make it so that I can pull out a record’s content in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;blog/collection.html&lt;/span&gt;&lt;/code&gt; template - you may notice that the RSS feed only contains post titles at the moment!&lt;/p&gt;
&lt;p&gt;But for the HTML at least I was able to cheat and use &lt;a class=&#34;reference external&#34; href=&#34;https://htmx.org/&#34;&gt;HTMX&lt;/a&gt; to pull the content through when the post scrolls into view.&lt;/p&gt;
&lt;div class=&#34;highlight-html notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;hx-trigger&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;intersect once&amp;quot;&lt;/span&gt;
     &lt;span class=&#34;na&#34;&gt;hx-get&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;{{ pathto(post.docname) }}&amp;quot;&lt;/span&gt;
     &lt;span class=&#34;na&#34;&gt;hx-select&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;.post-teaser&amp;quot;&lt;/span&gt;
     &lt;span class=&#34;na&#34;&gt;hx-swap&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;innerHTML ignoreTitle:true&amp;quot;&lt;/span&gt;
     &lt;span class=&#34;na&#34;&gt;style&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;min-width: 0&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which of course isn’t ideal, especially when you realise any links in the inserted content will be broken! 😅&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;next-steps&#34;&gt;
&lt;h2&gt;Next Steps&lt;a class=&#34;headerlink&#34; href=&#34;#next-steps&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As you might guess this is still quite immature and there’s plenty that I’d still like to explore or needs fixing!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;xref denote denote-link docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Fixing&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;Search&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The search bar you see in the sidebar is pretty much useless in its current form.
Yes, you can type something in and it will take you to a search results page, but all the links on that page will be broken!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fixing notes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While I could send you a direct link to one of the notes on this site and you could see it, there’s no actual way to browse them at this time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;denote-sequence&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;There are many pages on this site which form a series of some kind.
However, the only way to handle this currently is for me to remember to add relevant links forwards and backwards in the chain!&lt;/p&gt;
&lt;p&gt;Building on a part of the denote file-naming scheme I’ve ignored so far - the signature - the &lt;a class=&#34;reference external&#34; href=&#34;https://protesilaos.com/emacs/denote-sequence&#34;&gt;denote-sequence&lt;/a&gt; package provides a mechanism for encoding hierarchical sequences of related notes which would be perfect for my use case!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Knowledge Graphs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I doubt views like Obsidian’s &lt;a class=&#34;reference external&#34; href=&#34;https://help.obsidian.md/plugins/graph&#34;&gt;graph view&lt;/a&gt; are that useful in practise - but they are cool to look at!
If nothing else it would be a fun excerise to try and build a similar view for this site.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2025/installing-emacs-with-systemd-sysext/</id>
    <link href="https://www.alcarney.me/blog/2025/installing-emacs-with-systemd-sysext" rel="alternate" />
    <published>2025-05-02T00:00:00+00:00</published>
    <updated>2025-05-02T00:00:00+00:00</updated>
    <title>Intstalling Emacs with systemd-sysext</title>
    <content type="html">
      &lt;section id=&#34;intstalling-emacs-with-systemd-sysext&#34;&gt;
&lt;h1&gt;Intstalling Emacs with systemd-sysext&lt;a class=&#34;headerlink&#34; href=&#34;#intstalling-emacs-with-systemd-sysext&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;One issue with building &lt;a class=&#34;reference internal&#34; href=&#34;../notes/20250409T205418/&#34; title=&#34;Building Emacs from Source&#34;&gt;Emacs from source&lt;/a&gt;, or more specifically my hack to ensure that the required system libraries are available on Aurora, is that in some situations the system version of Emacs “wins”.&lt;/p&gt;
&lt;p&gt;For example, I wanted to experiment with running the Emacs daemon through systemd:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ systemctl --user start emacs
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which failed to load my config correctly.
It was only after a closer look did I realise that despite specifying the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--user&lt;/span&gt;&lt;/code&gt; flag, systemd was defaulting to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;emacs.service&lt;/span&gt;&lt;/code&gt; file provided by the system emacs package in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/usr/...&lt;/span&gt;&lt;/code&gt; and was therefore running Emacs v29 and not my v30 build.&lt;/p&gt;
&lt;p&gt;But then I stumbled across systemd-sysext&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;enter-systemd-sysext&#34;&gt;
&lt;h2&gt;Enter systemd-sysext&lt;a class=&#34;headerlink&#34; href=&#34;#enter-systemd-sysext&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I can’t really tell you what a sysext is… I just know that they are yet another potential way to install software on an image based OS.
To quote the &lt;a class=&#34;reference external&#34; href=&#34;https://extensions.fcos.fr/&#34;&gt;extensions.fcos.fr&lt;/a&gt; website&lt;/p&gt;
&lt;blockquote class=&#34;pull-quote&#34;&gt;
&lt;div&gt;&lt;p&gt;systemd system extensions (sysexts) are filesystem images that bundle content (binaries, libraries and configuration files) that can be overlayed on demand on image based systems. The content of the sysexts are “merged” with the base content of the OS using an overlayfs mount.&lt;/p&gt;
&lt;p&gt;If you want to know more about sysexts, you can watch the &lt;a class=&#34;reference external&#34; href=&#34;https://cfp.all-systems-go.io/all-systems-go-2024/talk/HJLF3C/&#34;&gt;Waiter, an OS please, with some sysext sprinkled on top (video)&lt;/a&gt; talk at All systems go! Berlin 2024.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;I saw that there was an Emacs layer(?), so thought I may as well give it a go!&lt;/p&gt;
&lt;section id=&#34;initial-setup&#34;&gt;
&lt;h3&gt;Initial Setup&lt;a class=&#34;headerlink&#34; href=&#34;#initial-setup&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It looks like a “proper” frontend to these things is still &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/bootc-dev/bootc/issues/7&#34;&gt;under development&lt;/a&gt; so for now we need to do the setup ourselves.
Thankfully the page for the &lt;a class=&#34;reference external&#34; href=&#34;https://travier.github.io/fedora-sysexts/&#34;&gt;emacs sysext&lt;/a&gt; provides the steps for us&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create folders to manage sysexts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This step is only necessary when you set up your very first sysext&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo install -d -m 0755 -o 0 -g 0 /var/lib/extensions /var/lib/extensions.d
$ sudo restorecon -RFv /var/lib/extensions /var/lib/extensions.d
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Tell systemd about the sysext&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First we create a folder under &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/etc&lt;/span&gt;&lt;/code&gt; where we can place a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;*.conf&lt;/span&gt;&lt;/code&gt; file&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo install -d -m 0755 -o 0 -g 0 /etc/sysupdate.emacs.d
$ sudo restorecon -RFv /etc/sysupdate.emacs.d
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’m not sure why you would create a folder here per sysext, but I’m sure there must be a good reason to.
In this folder, we place an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;emacs.conf&lt;/span&gt;&lt;/code&gt; file with the following contents&lt;/p&gt;
&lt;div class=&#34;highlight-systemd notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;[Transfer]&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Verify&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;false&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;[Source]&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;url-file&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;https://extensions.fcos.fr/extensions/emacs/&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;MatchPattern&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;emacs-@v-%w-%a.raw&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;[Target]&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;InstancesMax&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;regular-file&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;Path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/var/lib/extensions.d/&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;MatchPattern&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;emacs-@v-%w-%a.raw&lt;/span&gt;
&lt;span class=&#34;na&#34;&gt;CurrentSymlink&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/var/lib/extensions/emacs.raw&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Again, I don’t really know the details, but the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;[Source]&lt;/span&gt;&lt;/code&gt; block appears to be telling systemd where to fetch the emacs sysext from and the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;[Target]&lt;/span&gt;&lt;/code&gt; block seems to be telling it where to put it on disk.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;install-the-sysext&#34;&gt;
&lt;h3&gt;Install the sysext&lt;a class=&#34;headerlink&#34; href=&#34;#install-the-sysext&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We’ve now given systemd enough information to fetch the sysext:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo /usr/lib/systemd/systemd-sysupdate update --component emacs
Discovering installed instances…
Discovering available instances…
⤵️ Acquiring manifest file https://extensions.fcos.fr/extensions/emacs/SHA256SUMS…
Pulling &amp;#39;https://extensions.fcos.fr/extensions/emacs/SHA256SUMS&amp;#39;.
Downloading 406B for https://extensions.fcos.fr/extensions/emacs/SHA256SUMS.
Acquired 406B.
Download of https://extensions.fcos.fr/extensions/emacs/SHA256SUMS complete.
Operation completed successfully.
Exiting.
Determining installed update sets…
Determining available update sets…
Selected update &amp;#39;1-29.4-44.fc41&amp;#39; for install.
Making room for 1 updates…
Removed no instances.
⤵️ Acquiring https://extensions.fcos.fr/extensions/emacs/emacs-1-29.4-44.fc41-41-x86-64.raw → /var/lib/extensions.d/emacs-1-29.4-44.fc41-41-x86-64.raw...
Pulling &amp;#39;https://extensions.fcos.fr/extensions/emacs/emacs-1-29.4-44.fc41-41-x86-64.raw&amp;#39;, saving as &amp;#39;/var/lib/extensions.d/.#sysupdateemacs-1-29.4-44.fc41-41-x86-64.raw6b5d6dfbd735d210&amp;#39;.
Downloading 286.2M for https://extensions.fcos.fr/extensions/emacs/emacs-1-29.4-44.fc41-41-x86-64.raw.
Got 1% of https://extensions.fcos.fr/extensions/emacs/emacs-1-29.4-44.fc41-41-x86-64.raw.
...
Got 98% of https://extensions.fcos.fr/extensions/emacs/emacs-1-29.4-44.fc41-41-x86-64.raw. 268ms left at 17.4M/s.
Acquired 286.2M.
Download of https://extensions.fcos.fr/extensions/emacs/emacs-1-29.4-44.fc41-41-x86-64.raw complete.
Operation completed successfully.
Exiting.
Successfully acquired &amp;#39;https://extensions.fcos.fr/extensions/emacs/emacs-1-29.4-44.fc41-41-x86-64.raw&amp;#39;.
Successfully installed &amp;#39;https://extensions.fcos.fr/extensions/emacs/emacs-1-29.4-44.fc41-41-x86-64.raw&amp;#39; (url-file) as &amp;#39;/var/lib/extensions.d/emacs-1-29.4-44.fc41-41-x86-64.raw&amp;#39; (regular-file).
Updated symlink &amp;#39;/var/lib/extensions/emacs.raw&amp;#39; → &amp;#39;../extensions.d/emacs-1-29.4-44.fc41-41-x86-64.raw&amp;#39;.
✨ Successfully installed update &amp;#39;1-29.4-44.fc41&amp;#39;.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, while we can see the sysext on disk…&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$  ls /var/lib/extensions -l
lrwxrwxrwx. 1 root root 50 Apr 27 19:44 emacs.raw -&amp;gt; ../extensions.d/emacs-1-29.4-44.fc41-41-x86-64.raw
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Emacs itself is still not available&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ emacs
bash: emacs: command not found
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;enabling-the-sysext&#34;&gt;
&lt;h3&gt;Enabling the sysext&lt;a class=&#34;headerlink&#34; href=&#34;#enabling-the-sysext&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The sysext still needs to be enabled - or “merged”&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo systemctl restart systemd-sysext.service
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which, in theory, would finally make Emacs available to my system however running &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;systemd-sysext&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;status&lt;/span&gt;&lt;/code&gt; showed no extensions&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ systemd-sysext status
HIERARCHY EXTENSIONS SINCE
/opt      none       -
/usr      none       -
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And there were errors in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;systemd-sysext.service&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ systemctl status systemd-sysext.service
● systemd-sysext.service - Merge System Extension Images into /usr/ and /opt/
     Loaded: loaded (/usr/lib/systemd/system/systemd-sysext.service; enabled; preset: enabled)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf, 50-keep-warm.conf
     Active: active (exited) since Sun 2025-04-27 19:56:39 BST; 1min 0s ago
 Invocation: 3d34eb06a325454b954ff1697193ba9c
       Docs: man:systemd-sysext.service(8)
    Process: 9596 ExecStart=systemd-sysext refresh (code=exited, status=0/SUCCESS)
   Main PID: 9596 (code=exited, status=0/SUCCESS)
   Mem peak: 4.1M
        CPU: 34ms

Apr 27 19:56:38 aurora systemd[1]: Starting systemd-sysext.service - Merge System Extension Images into /usr/ and /opt/...
Apr 27 19:56:39 aurora (sd-merge)[9612]: No suitable extensions found (1 ignored due to incompatible image(s)).
Apr 27 19:56:39 aurora systemd[1]: Finished systemd-sysext.service - Merge System Extension Images into /usr/ and /opt/.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;digging-deeper&#34;&gt;
&lt;h2&gt;Digging Deeper&lt;a class=&#34;headerlink&#34; href=&#34;#digging-deeper&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Without much to go on I started googling around for some more information.&lt;/p&gt;
&lt;section id=&#34;what-s-in-a-sysext&#34;&gt;
&lt;h3&gt;What’s in a sysext?&lt;a class=&#34;headerlink&#34; href=&#34;#what-s-in-a-sysext&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Eventually I found myself on the &lt;a class=&#34;reference external&#34; href=&#34;https://www.freedesktop.org/software/systemd/man/latest/systemd-sysext.html&#34;&gt;manpage&lt;/a&gt; for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;systemd-sysext&lt;/span&gt;&lt;/code&gt;, trying to get a feel for what this &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;*.raw&lt;/span&gt;&lt;/code&gt; file I downloaded actually looked like.&lt;/p&gt;
&lt;blockquote class=&#34;pull-quote&#34;&gt;
&lt;div&gt;&lt;p&gt;System extension images may be provided in the following formats:&lt;/p&gt;
&lt;ol class=&#34;arabic simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Plain directories or btrfs subvolumes containing the OS tree&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disk images with a GPT disk label, following the Discoverable Partitions Specification&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disk images lacking a partition table, with a naked Linux file system (e.g. erofs, squashfs or ext4)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Oh, so some kind of file system then?&lt;/p&gt;
&lt;p&gt;Digging around in the GitHub Action workflows of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;fedora-sysexts&lt;/span&gt;&lt;/code&gt; project, I &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/travier/fedora-sysexts/blob/c1c589e5214793295c2d0be36c03b5082eed2c67/sysext.just#L634&#34;&gt;found&lt;/a&gt; where the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;*.raw&lt;/span&gt;&lt;/code&gt; files were actually produced:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;${SUDO} mkfs.erofs -z{{compression}} {{name}}-${version}-${version_id}-${arch}.raw rootfs &amp;gt; /dev/null
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Seeing this I wondered if I could just mount this file and take a look around:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo mkdir /run/media/img
$ sudo mount /var/lib/extensions.d/emacs-1-29.4-44.fc41-41-x86-64.raw /run/media/img
$ tree -L 2 /run/media/img
/run/media/img/
└── usr
    ├── bin
    ├── etc
    ├── include
    ├── lib
    ├── lib64
    ├── libexec
    └── share
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Sure enough, it was just a folder hierarchy that contained an installation of Emacs.
While it was nice to get some more details on what I was dealing with, it didn’t actually help me get any closer to figuring out what was wrong - so I kept reading.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;compatibility-checks&#34;&gt;
&lt;h3&gt;Compatibility Checks&lt;a class=&#34;headerlink&#34; href=&#34;#compatibility-checks&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There is a simple check performed when merging a sysext in an attempt to ensure it’s compatible with the base system.&lt;/p&gt;
&lt;blockquote class=&#34;pull-quote&#34;&gt;
&lt;div&gt;&lt;p&gt;A system extension image must carry a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/usr/lib/extension-release.d/extension-release.NAME&lt;/span&gt;&lt;/code&gt; file, which must match its image name, that is compared with the host os-release file: the contained &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ID=&lt;/span&gt;&lt;/code&gt; fields have to match unless &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;quot;_any&amp;quot;&lt;/span&gt;&lt;/code&gt; is set for the extension.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;And here was my issue:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ grep &amp;#39;^ID=&amp;#39; /etc/os-release
ID=aurora

$ grep &amp;#39;^ID=&amp;#39; /run/media/img/usr/lib/extension-release.d/extension-release.emacs
ID=&amp;quot;fedora&amp;quot;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As far as systemd was concerned I am running an incompatible OS, so it refuses to enable the sysext.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;hacking-it-in&#34;&gt;
&lt;h2&gt;Hacking it in&lt;a class=&#34;headerlink&#34; href=&#34;#hacking-it-in&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Just to check that my assumption was correct, I edited my &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/etc/os-release&lt;/span&gt;&lt;/code&gt; file so that the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ID&lt;/span&gt;&lt;/code&gt; field was set to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;fedora&lt;/span&gt;&lt;/code&gt; and tried restarting the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;systemd-sysext.service&lt;/span&gt;&lt;/code&gt; again:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Apr 27 23:26:46 aurora systemd[1]: Starting systemd-sysext.service - Merge System Extension Images into /usr/ and /opt/...
Apr 27 23:26:46 aurora (sd-merge)[15118]: Using extensions &amp;#39;emacs&amp;#39;.
Apr 27 23:26:46 aurora (sd-merge)[15118]: Merged extensions into &amp;#39;/usr&amp;#39;.
Apr 27 23:26:46 aurora systemd[1]: Finished systemd-sysext.service - Merge System Extension Images into /usr/ and /opt/.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which looked promising!
I could even see the extension now using the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;systemd-sysext&lt;/span&gt;&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ systemd-sysext list
NAME  TYPE PATH                          TIME
emacs raw  /var/lib/extensions/emacs.raw Sat 2025-04-26 14:30:33 BST
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;emacs&lt;/span&gt;&lt;/code&gt; command was available!&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ emacs --version
GNU Emacs 29.4
Copyright (C) 2024 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The only issue now is that it’s still not Emacs v30!
While I saw both Emacs v29 and v30 builds were available as sysexts I didn’t think to check which fedora versions they were built for! 🤦‍♂️&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;emacs-1-29.4-44.fc41-41-aarch64.raw
emacs-1-29.4-44.fc41-41-x86-64.raw
emacs-1-30.1-11.fc42-42-aarch64.raw
emacs-1-30.1-11.fc42-42-x86-64.raw
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It turns out Emacs v30 is only available on Fedora 42 - regardless of the installation method used! 😅&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2025/til-navigating-history-with-magit/</id>
    <link href="https://www.alcarney.me/blog/2025/til-navigating-history-with-magit" rel="alternate" />
    <published>2025-02-27T00:00:00+00:00</published>
    <updated>2025-02-27T00:00:00+00:00</updated>
    <title>TIL: Navigating History with Magit</title>
    <content type="html">
      &lt;section id=&#34;til-navigating-history-with-magit&#34;&gt;
&lt;h1&gt;TIL: Navigating History with Magit&lt;a class=&#34;headerlink&#34; href=&#34;#til-navigating-history-with-magit&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;Building on &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2025/til-additional-magit-keybindings/&#34; title=&#34;TIL: Additional magit keybindings&#34;&gt;my previous discovery&lt;/a&gt;, today I figured out a few ways of exploring the history of a project with &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit&lt;/span&gt;&lt;/code&gt;.
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/issues/965&#34;&gt;This issue&lt;/a&gt; provided a nice motivating example to have in mind - the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;exceptiongroup&lt;/span&gt;&lt;/code&gt; Python package was dropped from a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;requirements.txt&lt;/span&gt;&lt;/code&gt; file - in which commit did it happen?&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;from-magit-dispatch&#34;&gt;
&lt;h2&gt;From &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-dispatch&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#from-magit-dispatch&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From any file in the repository you can&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Invoke &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-dispatch&lt;/span&gt;&lt;/code&gt; (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;x&lt;/kbd&gt; &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;M&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;g&lt;/kbd&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the log menu (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;l&lt;/kbd&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limit the log to commits affecting a specific file (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;--&lt;/kbd&gt;) and enter the filename(s) at the minibuffer prompt (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;code/requirements-libs.txt&lt;/span&gt;&lt;/code&gt;) in my case&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate the log for the current branch (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;l&lt;/kbd&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which resulted in the following buffer:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Commits in develop touching code/requirements-libs.txt
a0b08399 * build(deps): bump websockets from 14.1 to 14.2 in /code
d781cdc0 * code: Update dependencies
f88f8ad5 * build(deps): bump tomli from 2.0.2 to 2.2.1 in /code
83e810c6 * code: Update bundled dependencies
d6462b20 * code: Bundle a basic Sphinx env with the extension
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then with point on one of the commits, hitting &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;SPC&lt;/kbd&gt; will open the corresponding diff in a new window:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;commit d781cdc0 limited to file code/requirements-libs.txt
d781cdc087a1846ecc13df36d6ee4b6ad383a3b9
Author:     Alex Carney &amp;lt;alcarneyme@gmail.com&amp;gt;
AuthorDate: Sat Jan 18 20:57:09 2025 +0000
Commit:     Alex Carney &amp;lt;alex.rugby101@gmail.com&amp;gt;
CommitDate: Thu Jan 23 19:56:08 2025 +0000

Parent:     19be4d6b devenv: Use `uv` for dependency resolution
Contained:  develop release
Follows:    esbonio-vscode-extension-v0.96.1 (9)
Precedes:   esbonio-language-server-v1.0.0b10 (32)

code: Update dependencies

1 file changed, 5 insertions(+), 9 deletions(-)
code/requirements-libs.txt | 14 +++++---------

modified   code/requirements-libs.txt
@@ -1,16 +1,12 @@
-#
-# This file is autogenerated by pip-compile with Python 3.9
-# by the following command:
-#
-#    pip-compile --generate-hashes --output-file=requirements-libs.txt requirements-libs.in
-#
+# This file was autogenerated by uv via the following command:
+#    uv pip compile --prerelease=allow --generate-hashes --python-version 3.9 --output-file requirements-libs.txt requirements-libs.in
 aiosqlite==0.20.0 \
     --hash=sha256:36a1deaca0cac40ebe32aac9977a6e2bbc7f5189f23f4a54d5908986729e5bd6 \
     --hash=sha256:6d35c8c256637f4672f843c31021464090805bf925385ac39473fb16eaaca3d7
     # via -r requirements-libs.in
-attrs==24.2.0 \
-    --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \
-    --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2
+attrs==24.3.0 \
+    --hash=sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff \
+    --hash=sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308
     # via
     #   cattrs
     #   lsprotocol

[back]
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-log:&lt;/span&gt;&lt;/code&gt; buffer will still be focused - it turns out navigating up and down the list with &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;n&lt;/kbd&gt; and &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;p&lt;/kbd&gt; will automatically refresh the diff to match the new commit under point!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;from-magit-file-dispatch&#34;&gt;
&lt;h2&gt;From &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-file-dispatch&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#from-magit-file-dispatch&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A perhaps faster way to acheive the same result is to&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Navigate to the file of interest &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;code/requirements-libs.txt&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Invoke &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-file-dispatch&lt;/span&gt;&lt;/code&gt; (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;c&lt;/kbd&gt; &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;M&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;g&lt;/kbd&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select log (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;l&lt;/kbd&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;navigating-history&#34;&gt;
&lt;h2&gt;Navigating history&lt;a class=&#34;headerlink&#34; href=&#34;#navigating-history&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another nice set of commands in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-file-dispatch&lt;/span&gt;&lt;/code&gt; menu are in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Navigate&lt;/span&gt;&lt;/code&gt; column:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;File actions   Inspect                               Navigate        More actions
   s Stage      D Diff...   L Log...   B Blame...     p Prev blob     c Commit
   u Unstage    d Diff      l Log      b Blame        n Next blob     e Edit line
 , x Untrack                t Trace    m Blame echo   v Goto blob
 , r Rename                                           V Goto file
 , k Delete                                           g Goto status
 , c Checkout                                         G Goto magit
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Using &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;n&lt;/kbd&gt; or &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;p&lt;/kbd&gt; you can walk through the history of the current file, or if you know the commit/branch/tag, jump to it directly with &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;v&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;Then if you wish you can view the diff for the current revision with &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;d&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;Now I wonder if it’s possible to integrate &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;n&lt;/kbd&gt; and &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;p&lt;/kbd&gt; with &lt;a class=&#34;reference external&#34; href=&#34;https://karthinks.com/software/it-bears-repeating/&#34;&gt;repeat-mode&lt;/a&gt;… 🤔&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2025/til-additional-magit-keybindings/</id>
    <link href="https://www.alcarney.me/blog/2025/til-additional-magit-keybindings" rel="alternate" />
    <published>2025-02-21T00:00:00+00:00</published>
    <updated>2025-02-21T00:00:00+00:00</updated>
    <title>TIL: Additional magit keybindings</title>
    <content type="html">
      &lt;section id=&#34;til-additional-magit-keybindings&#34;&gt;
&lt;h1&gt;TIL: Additional magit keybindings&lt;a class=&#34;headerlink&#34; href=&#34;#til-additional-magit-keybindings&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;It always helps to spend the time now and again to read the manual for the tools you use!
By simply reading the &lt;a class=&#34;reference external&#34; href=&#34;https://magit.vc/manual/magit/Getting-Started.html&#34;&gt;Getting Started&lt;/a&gt; section of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit&lt;/span&gt;&lt;/code&gt; user manual I found not one but two commands I had never come across before!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Despite using &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit&lt;/span&gt;&lt;/code&gt; on and off for years I had only known about the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-status&lt;/span&gt;&lt;/code&gt; command (bound to &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;x&lt;/kbd&gt; &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;g&lt;/kbd&gt; by default).
However, magit also provides you with the following bindings&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-dispatch&lt;/span&gt;&lt;/code&gt; (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;x&lt;/kbd&gt; &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;M&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;g&lt;/kbd&gt;)&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;This gives you immediate access to any of the commands you would normally invoke from the magit status buffer!&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Transient and dwim commands
 A Apply           i Ignore           r Rebase
 b Branch          I Init             t Tag
 B Bisect          j Display status   T Note
 c Commit          J Display buffer   V Revert
 C Clone           l Log              w Apply patches
 d Diff            L Log (change)     W Format patches
 D Diff (change)   m Merge            X Reset
 e Ediff (dwim)    M Remote           y Show Refs
 E Ediff           N Forge            Y Cherries
 f Fetch           o Submodule        z Stash
 F Pull            O Subtree          Z Worktree
 h Help            P Push             ! Run
                   Q Command
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;dt&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;magit-file-dispatch&lt;/span&gt;&lt;/code&gt; (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;c&lt;/kbd&gt; &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;M&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;g&lt;/kbd&gt;)&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;As the name suggests, this opens a transient containing commands that can be applied to the current file&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;File actions   Inspect                               Navigate        More actions
   s Stage      D Diff...   L Log...   B Blame...     p Prev blob     c Commit
   u Unstage    d Diff      l Log      b Blame        n Next blob     e Edit line
 , x Untrack                t Trace    m Blame echo   v Goto blob
 , r Rename                                           V Goto file
 , k Delete                                           g Goto status
 , c Checkout                                         G Goto magit
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2025/january-2025/</id>
    <link href="https://www.alcarney.me/blog/2025/january-2025" rel="alternate" />
    <published>2025-02-09T00:00:00+00:00</published>
    <updated>2025-02-09T00:00:00+00:00</updated>
    <title>Notes for December/January</title>
    <content type="html">
      &lt;section id=&#34;notes-for-december-january&#34;&gt;
&lt;h1&gt;Notes for December/January&lt;a class=&#34;headerlink&#34; href=&#34;#notes-for-december-january&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;Somehow it is already Feburary…&lt;/p&gt;
&lt;p&gt;So it’s about time I tried another one of these month note things, especially since the last one was in &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2024/notes-november/&#34; title=&#34;Notes for November 2024&#34;&gt;November&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;pygls&#34;&gt;
&lt;h2&gt;pygls&lt;a class=&#34;headerlink&#34; href=&#34;#pygls&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There has been an &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls/issues/433&#34;&gt;issue&lt;/a&gt; in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pygls&lt;/span&gt;&lt;/code&gt; which has affected &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; for a while.
In December I finally got around to trying to fix it and I opened a &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls/pull/516&#34;&gt;pull request&lt;/a&gt; introducing a new way of handling request handlers.&lt;/p&gt;
&lt;p&gt;Some more testing is needed before you can call it ready, but I’m optimistic it’s going to pan out.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;esbonio&#34;&gt;
&lt;h2&gt;esbonio&lt;a class=&#34;headerlink&#34; href=&#34;#esbonio&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I also managed to put a fair amount of work into the upcoming &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;v1&lt;/span&gt;&lt;/code&gt; of  &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; during January&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/937&#34;&gt;Added&lt;/a&gt; a new &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;${venv:&amp;lt;path&amp;gt;}&lt;/span&gt;&lt;/code&gt; config variable, finally making it possible to share &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pythonCommand&lt;/span&gt;&lt;/code&gt; settings for projects that use virtual environments directly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Made it possible to &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/940&#34;&gt;customize&lt;/a&gt; how often Sphinx builds are triggered&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/941&#34;&gt;Re-implemented&lt;/a&gt; completion suggestions for directive arguments&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixed quite a few bugs which made their way into the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/releases/tag/esbonio-language-server-v1.0.0b10&#34;&gt;v1.0.0b10 release&lt;/a&gt; this week.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2025/debugging-go-with-gdb/</id>
    <link href="https://www.alcarney.me/blog/2025/debugging-go-with-gdb" rel="alternate" />
    <published>2025-01-03T00:00:00+00:00</published>
    <updated>2025-01-03T00:00:00+00:00</updated>
    <title>TIL: Debugging go programs with gdb</title>
    <content type="html">
      &lt;section id=&#34;til-debugging-go-programs-with-gdb&#34;&gt;
&lt;h1&gt;TIL: Debugging go programs with &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;gdb&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#til-debugging-go-programs-with-gdb&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;gdb&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--args&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;podman&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;info
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;run&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Starting program: /usr/bin/podman info&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Thread debugging using libthread_db enabled]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;WARN[0000] Found incomplete layer &amp;quot;6748b9a4e6f2d75763acd0d8351dfb92d4281a0b3546cc68042fb8cb5e1b7c3c&amp;quot;, deleting it&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;Thread 9 &amp;quot;podman&amp;quot; received signal SIGSEGV, Segmentation fault.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Switching to Thread 0x7fbacbfff6c0 (LWP 10496)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading source file /usr/src/debug/podman-5.3.1-1.fc41.x86_64/vendor/github.com/containers/storage/layers.go&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;github.com/containers/storage.(*layerStore).load (r=0xc00024c140, lockedForWriting=true, ~r0=&amp;lt;optimized out&amp;gt;, ~r0=&amp;lt;optimized out&amp;gt;, ~r1=..., ~r1=...) at /usr/src/debug/podman-5.3.1-1.fc41.x86_64/vendor/github.com/containers/storage/layers.go:917&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;917                     if layer.Flags == nil {&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&amp;lt;Freeze frame, record scratch&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You might be wondering how I got here…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And no, I wasn’t trying to work on &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/containers/podman&#34;&gt;podman&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;how-i-got-here&#34;&gt;
&lt;span id=&#34;debug-go-with-gdb-getting-here&#34;&gt;&lt;/span&gt;&lt;h2&gt;How I got here&lt;a class=&#34;headerlink&#34; href=&#34;#how-i-got-here&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;This section has nothing to do with using &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;gdb&lt;/span&gt;&lt;/code&gt;, I just find it amusing how many tangents I let myself take!
Feel free to skip this and start with the &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2025/debugging-go-with-gdb/#debug-go-with-gdb-setup&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;next section&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I was working on a &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/937&#34;&gt;PR&lt;/a&gt; for esbonio, and ran into some test failures that I couldn’t easily figure out from the CI logs alone.
Trouble was, the tests all relate to my arch nemesis - Windows file paths.&lt;/p&gt;
&lt;p&gt;No problem! I’ll use &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/quickemu-project/quickemu&#34;&gt;quickemu&lt;/a&gt; to fire up a Windows VM&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$  &lt;/span&gt;quickemu&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--vm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;windows-11.conf
&lt;span class=&#34;go&#34;&gt;ERROR! Requested &amp;#39;spicy&amp;#39; as viewer, but &amp;#39;spicy&amp;#39; is not installed.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Oh yes, I haven’t spun up a VM on this machine yet so don’t have a frontend installed.
I’ve used &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;remote-viewer&lt;/span&gt;&lt;/code&gt; in the past, let’s install that… umm… which package provides this again?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;It was in this moment he made a grave mistake&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Rather than do the sane thing and Google it, I thought this would be a good chance to ask my &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2024/local-llms-with-ollama-and-gptel/&#34; title=&#34;TIL: Local LLMs with Ollama and gptel&#34;&gt;local AI model&lt;/a&gt; for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dnf&lt;/span&gt;&lt;/code&gt; incantation to search for the package that provides the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;remote-viewer&lt;/span&gt;&lt;/code&gt; command.
However, I quickly realised none of my containers were working since almost any podman command resulted in a go panic.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;podman&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;info
&lt;span class=&#34;go&#34;&gt;WARN[0000] Found incomplete layer &amp;quot;6748b9a4e6f2d75763acd0d8351dfb92d4281a0b3546cc68042fb8cb5e1b7c3c&amp;quot;, deleting it&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;panic: runtime error: invalid memory address or nil pointer dereference&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[signal SIGSEGV: segmentation violation code=0x1 addr=0x100 pc=0x55fab5c85217]&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;goroutine 1 gp=0xc0000061c0 m=16 mp=0xc00050f508 [running]:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;panic({0x55fab6c906e0?, 0x55fab7bac9e0?})&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;        /usr/lib/golang/src/runtime/panic.go:804 +0x168 fp=0xc00005eda8 sp=0xc00005ecf8 pc=0x55fab529aa88&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;runtime.panicmem(...)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;        /usr/lib/golang/src/runtime/panic.go:262&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;runtime.sigpanic()&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;[Many, many more lines omitted...]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After a quick rummage around some issue trackers I found that not only was this a known issue, it &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/containers/storage/pull/2185&#34;&gt;has a fix&lt;/a&gt;.
Unfortunately the fix hasn’t made it into my version of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;podman&lt;/span&gt;&lt;/code&gt; yet, so as a workaround, I will have to remove the incomplete layer myself.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;lt;Insert Thanos meme here&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And since I don’t know which file(s)/folder(s) need deleting, I thought the &lt;span class=&#34;line-through&#34;&gt;quickest&lt;/span&gt;, most fun way to figure this out would be to debug the process.&lt;/p&gt;
&lt;p&gt;Which brings us onto the subject of this blog post!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;setup&#34;&gt;
&lt;span id=&#34;debug-go-with-gdb-setup&#34;&gt;&lt;/span&gt;&lt;h2&gt;Setup&lt;a class=&#34;headerlink&#34; href=&#34;#setup&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since I’m using the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;-dx&lt;/span&gt;&lt;/code&gt; version of &lt;a class=&#34;reference external&#34; href=&#34;https://getaurora.dev/&#34;&gt;Aurora&lt;/a&gt;, I found that I already had &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;gdb&lt;/span&gt;&lt;/code&gt; installed.
From there all you have to do is pass it the program (and any arguments) you want it to run&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;gdb&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--args&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;podman
&lt;span class=&#34;go&#34;&gt;GNU gdb (Fedora Linux) 15.2-3.fc41&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Reading symbols from podman...&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;This GDB supports auto-downloading debuginfo from the following URLs:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  &amp;lt;https://debuginfod.fedoraproject.org/&amp;gt;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Enable debuginfod for this session? (y or [n])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You want to say yes to this!&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Debuginfod has been enabled.
To make this setting permanent, add &amp;#39;set debuginfod enabled on&amp;#39; to .gdbinit.
Downloading 70.28 M separate debug info for /usr/bin/podman
Reading symbols from /home/alex/.cache/debuginfod_client/6c1be8511a45f7f8eef6df8bc94c20641d96eb9a/debuginfo...
/var/home/alex/info: No such file or directory.
warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts
of file /var/home/alex/.cache/debuginfod_client/6c1be8511a45f7f8eef6df8bc94c20641d96eb9a/debuginfo.
Use `info auto-load python-scripts [REGEXP]&amp;#39; to list them.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once enabled, &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;gdb&lt;/span&gt;&lt;/code&gt; will be able to download any debug symbols it needs automatically, on demand!&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;run&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Starting program: /usr/bin/podman&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading separate debug info for system-supplied DSO at 0x7f6e30ef1000&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 188.48 K separate debug info for /lib64/libresolv.so.2&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 187.84 K separate debug info for /lib64/libsubid.so.4&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 94.60 K separate debug info for /var/home/alex/.cache/debuginfod_client/05cb3df691d3ecacb634897526293dabb8834d87/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 1.20 M separate debug info for /lib64/libgpgme.so.11&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 2.77 M separate debug info for /var/home/alex/.cache/debuginfod_client/ad0ff4afb064a77890eb5b5dfae388c7598f3180/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 319.12 K separate debug info for /lib64/libseccomp.so.2&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 610.38 K separate debug info for /lib64/libgcc_s.so.1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 6.22 M separate debug info for /var/home/alex/.cache/debuginfod_client/a120aca96a83fdaa1dbff64ccb67f9b3e46a86fc/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 6.70 M separate debug info for /lib64/libc.so.6&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Thread debugging using libthread_db enabled]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Using host libthread_db library &amp;quot;/lib64/libthread_db.so.1&amp;quot;.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 168.53 K separate debug info for /lib64/libaudit.so.1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 30.00 K separate debug info for /var/home/alex/.cache/debuginfod_client/894985c591daedd80a91b4221c8725fc8aacb96b/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 540.78 K separate debug info for /lib64/libselinux.so.1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 82.43 K separate debug info for /var/home/alex/.cache/debuginfod_client/a77b40fbe465e7cfd1b53f220a51f41837976591/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 916.87 K separate debug info for /lib64/libsemanage.so.2&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 15.68 K separate debug info for /var/home/alex/.cache/debuginfod_client/92a110d4e6ddc3d7ec8219622107d2ade30338e3/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 129.88 K separate debug info for /lib64/libeconf.so.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 5.09 K separate debug info for /var/home/alex/.cache/debuginfod_client/12df41e5399f930a9b1520115cc1f2ed776edfa7/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 392.91 K separate debug info for /lib64/libcrypt.so.2&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 61.04 K separate debug info for /var/home/alex/.cache/debuginfod_client/3b22db61e60f5ba97c4e0bb1cbee6a8107f3f313/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 125.27 K separate debug info for /lib64/libacl.so.1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading separate debug info for /var/home/alex/.cache/debuginfod_client/6e078332ae36e8358da618b723ea4463791c70fc/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading separate debug info for /lib64/libattr.so.1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 7.69 K separate debug info for /var/home/alex/.cache/debuginfod_client/45c3b76fd658b1e86c6ff09d1f06babadf71fa78/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 193.53 K separate debug info for /lib64/libpam.so.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading separate debug info for /var/home/alex/.cache/debuginfod_client/dc4d461ec91383087257839ec7862ed0f230a765/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 34.12 K separate debug info for /lib64/libpam_misc.so.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 299.74 K separate debug info for /lib64/libassuan.so.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 555.48 K separate debug info for /lib64/libgpg-error.so.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 28.08 K separate debug info for /var/home/alex/.cache/debuginfod_client/1966004cd3bdfb76ca6c281c7ea322057ca67c08/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading separate debug info for /lib64/libcap-ng.so.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 9.07 K separate debug info for /var/home/alex/.cache/debuginfod_client/32db198012cdf3b3d1fe4db5414ca51ee36474d9/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 1.50 M separate debug info for /lib64/libpcre2-8.so.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 77.46 K separate debug info for /var/home/alex/.cache/debuginfod_client/ecf3f9c874cd4aa76ed4bd9e4f4d87d2d2ab9373/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 2.95 M separate debug info for /lib64/libsepol.so.2&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 163.20 K separate debug info for /lib64/libbz2.so.1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading separate debug info for /var/home/alex/.cache/debuginfod_client/e55f754492a153b4068a131340d25bf80918f8cf/debuginfo&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Downloading 2.09 M separate debug info for /lib64/libm.so.6&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;debugging&#34;&gt;
&lt;h2&gt;Debugging&lt;a class=&#34;headerlink&#34; href=&#34;#debugging&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&#34;admonition seealso&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;See also&lt;/p&gt;
&lt;dl class=&#34;simple&#34;&gt;
&lt;dt&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://go.dev/doc/gdb&#34;&gt;Debugging Go Code with GDB&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;A guide from the GO documentation on using &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;gdb&lt;/span&gt;&lt;/code&gt; to debug a program&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;p&gt;Finally, we’re caught up with where we were at the start of the blog post&lt;/p&gt;
&lt;p&gt;(If you skipped the &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2025/debugging-go-with-gdb/#debug-go-with-gdb-getting-here&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;How I got here&lt;/span&gt;&lt;/a&gt; section, all I’m hoping to acheive is finding out where the incomplete layer is stored, so I can delete it myself)&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;run&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Starting program: /usr/bin/podman info&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Thread debugging using libthread_db enabled]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Using host libthread_db library &amp;quot;/lib64/libthread_db.so.1&amp;quot;.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb1feff6c0 (LWP 19987)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb1f6fe6c0 (LWP 19988)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb1e6fc6c0 (LWP 19990)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb1eefd6c0 (LWP 19989)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb1defb6c0 (LWP 19991)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb1d55a6c0 (LWP 19992)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb1cd096c0 (LWP 19993)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb17fff6c0 (LWP 19994)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb177fe6c0 (LWP 19995)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb16ffd6c0 (LWP 19996)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb167fc6c0 (LWP 19997)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 19998]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 19999]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20001]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20002]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20004]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20005]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20006]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20008]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20009]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20011]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20013]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20015]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Detaching after vfork from child process 20016]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[New Thread 0x7fbb15ffb6c0 (LWP 20017)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;WARN[0000] Found incomplete layer &amp;quot;6748b9a4e6f2d75763acd0d8351dfb92d4281a0b3546cc68042fb8cb5e1b7c3c&amp;quot;, deleting it&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;Thread 11 &amp;quot;podman&amp;quot; received signal SIGSEGV, Segmentation fault.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Switching to Thread 0x7fbb16ffd6c0 (LWP 19996)]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;github.com/containers/storage.(*layerStore).load (r=0xc0004ea000, lockedForWriting=true, ~r0=&amp;lt;optimized out&amp;gt;, ~r0=&amp;lt;optimized out&amp;gt;, ~r1=..., ~r1=...) at /usr/src/debug/podman-5.3.1-1.fc41.x86_64/vendor/github.com/containers/storage/layers.go:917&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;917                     if layer.Flags == nil {&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;l&lt;/span&gt;&lt;/code&gt; command prints the code around where the panic happened.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;l&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;912             // Last step: try to remove anything that a previous&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;913             // user of this storage area marked for deletion but didn&amp;#39;t manage to&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;914             // actually delete.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;915             var incompleteDeletionErrors error // = nil&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;916             for _, layer := range r.layers {&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;917                     if layer.Flags == nil {&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;918                             layer.Flags = make(map[string]interface{})&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;919                     }&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;920                     if layerHasIncompleteFlag(layer) {&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;921                             logrus.Warnf(&amp;quot;Found incomplete layer %#v, deleting it&amp;quot;, layer.ID)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;p&lt;/span&gt;&lt;/code&gt; command allows us to inspect the value of a variable.
As expected, &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;layer&lt;/span&gt;&lt;/code&gt; contains a null pointer.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;p layer&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;github.com/containers/storage.Layer&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;*&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;0x0
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There are limits to gdb’s Go support however, and trying to look at the contents of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;layers&lt;/span&gt;&lt;/code&gt; array does not make much sense to me.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;p r.layers&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;0xc0001d7800,&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;35&lt;/span&gt;,&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cap&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;p r.layers.array&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;github.com/containers/storage.Layer&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;**&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;0xc0001d7800
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This must be some of Go’s implementation details showing through…&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;setting-a-breakpoint&#34;&gt;
&lt;h2&gt;Setting a Breakpoint&lt;a class=&#34;headerlink&#34; href=&#34;#setting-a-breakpoint&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It also doesn’t help that the crash has already happened, I want to inspect the state of the program just before the crash.
Thankfully, the warning message about the incomplete layer provides the ideal place to set the breakpoint.&lt;/p&gt;
&lt;p&gt;After starting a fresh debug session, I can use the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;break&lt;/span&gt;&lt;/code&gt; command to set a breakpoint&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;break /usr/src/debug/podman-5.3.1-1.fc41.x86_64/vendor/github.com/containers/storage/layers.go:921&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Breakpoint 1 at 0xa63324: file /usr/src/debug/podman-5.3.1-1.fc41.x86_64/vendor/github.com/containers/storage/layers.go, line 921.&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;run&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Starting program: /usr/bin/podman info&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[Thread debugging using libthread_db enabled]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Using host libthread_db library &amp;quot;/lib64/libthread_db.so.1&amp;quot;.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;...&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;Thread 13 &amp;quot;podman&amp;quot; hit Breakpoint 1, github.com/containers/storage.(*layerStore).load (r=0xc000622000, lockedForWriting=true, ~r0=&amp;lt;optimized out&amp;gt;, ~r0=&amp;lt;optimized out&amp;gt;, ~r1=..., ~r1=...) at /usr/src/debug/podman-5.3.1-1.fc41.x86_64/vendor/github.com/containers/storage/layers.go:921&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;921                             logrus.Warnf(&amp;quot;Found incomplete layer %#v, deleting it&amp;quot;, layer.ID)&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Using the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;n(ext)&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;s(tep)&lt;/span&gt;&lt;/code&gt; commands I was eventually able to step into the function responsible for removing the layer&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;n&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;921                             logrus.Warnf(&amp;quot;Found incomplete layer %#v, deleting it&amp;quot;, layer.ID)&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;n&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;WARN[0014] Found incomplete layer &amp;quot;6748b9a4e6f2d75763acd0d8351dfb92d4281a0b3546cc68042fb8cb5e1b7c3c&amp;quot;, deleting it&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;922                             err := r.deleteInternal(layer.ID)&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(gdb)&lt;/span&gt; &lt;span class=&#34;go&#34;&gt;s&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;github.com/containers/storage.(*layerStore).deleteInternal (r=0xc0004f4000, id=..., ~r0=...) at /usr/src/debug/podman-5.3.1-1.fc41.x86_64/vendor/github.com/containers/storage/layers.go:1888&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;1888    func (r *layerStore) deleteInternal(id string) error {&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;mt-4 admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;It actually took me a few attempts to step into the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;deleteInternal&lt;/span&gt;&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;podman&lt;/span&gt;&lt;/code&gt; spins up a lot of goroutines and depending on how slow I was, one of the background goroutines would segfault before I could get to it.
This would switch the debugger’s context away from the goroutine I was interested in.&lt;/p&gt;
&lt;p&gt;I am sure there is a way to switch back but I didn’t try looking it up.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;After a few more &lt;cite&gt;n&lt;/cite&gt; commands I arrived at some code that looks like it should be able to tell me where the layers are stored.&lt;/p&gt;
&lt;div class=&#34;highlight-go notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1911&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Remove&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tspath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1912&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;RemoveAll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;datadir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And sure enough I was able to locate the directory where the layer was stored&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;github.com/containers/storage.(*layerStore).tspath (r=0xc000686000, id=...) at /usr/src/debug/podman-5.3.1-1.fc41.x86_64/vendor/github.com/containers/storage/layers.go:1870
1870           return filepath.Join(r.layerdir, id+tarSplitSuffix)
(gdb) p r.layerdir
$7 = 0xc0005a29c0 &amp;quot;/var/home/alex/.local/share/containers/storage/overlay-layers&amp;quot;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;fixing-the-panic&#34;&gt;
&lt;h2&gt;Fixing the Panic&lt;a class=&#34;headerlink&#34; href=&#34;#fixing-the-panic&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Turns out the problematic layer (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;6748b9a4e6f2d75763acd0d8351dfb92d4281a0b3546cc68042fb8cb5e1b7c3c&lt;/span&gt;&lt;/code&gt;) had been removed, but the record of it still existed in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;layers.json&lt;/span&gt;&lt;/code&gt; metadata file.
After manually removing it &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;podman&lt;/span&gt;&lt;/code&gt; once again worked as expected!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2024/notes-november/</id>
    <link href="https://www.alcarney.me/blog/2024/notes-november" rel="alternate" />
    <published>2024-12-04T00:00:00+00:00</published>
    <updated>2024-12-04T00:00:00+00:00</updated>
    <title>Notes for November 2024</title>
    <content type="html">
      &lt;section id=&#34;notes-for-november-2024&#34;&gt;
&lt;h1&gt;Notes for November 2024&lt;a class=&#34;headerlink&#34; href=&#34;#notes-for-november-2024&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;Doubling my streak of writing notes on the &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2024/notes-october/&#34; title=&#34;Notes for October&#34;&gt;previous month&lt;/a&gt; to 2, here are some of the things I worked on in November.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;vscode-wasi-pygls&#34;&gt;
&lt;h2&gt;vscode-wasi-pygls&lt;a class=&#34;headerlink&#34; href=&#34;#vscode-wasi-pygls&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;figure class=&#34;align-default&#34;&gt;
&lt;a class=&#34;reference external image-reference&#34; href=&#34;https://github.com/alcarney/vscode-wasi-pygls/blob/main/screenshot.png?raw=true&#34;&gt;&lt;img alt=&#34;https://github.com/alcarney/vscode-wasi-pygls/blob/main/screenshot.png?raw=true&#34; src=&#34;https://github.com/alcarney/vscode-wasi-pygls/blob/main/screenshot.png?raw=true&#34; /&gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;This project is a proof of concept demonstrating how a pygls powered language server can be run entirely in the browser by making use of VSCode’s &lt;a class=&#34;reference external&#34; href=&#34;https://code.visualstudio.com/blogs/2023/06/05/vscode-wasm-wasi&#34;&gt;support for WebAssembly&lt;/a&gt;.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Thanks to the work I managed to land in pygls in October, this project is now able to use the upstream version of the framework rather than my fork! (&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/vscode-wasi-pygls/pull/3&#34;&gt;PR&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I also pulled in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;#64;vscode/wasm-wasi-lsp&lt;/span&gt;&lt;/code&gt; as a dependency, removing some of the code I had previously taken from the &lt;a class=&#34;extlink-gh reference external&#34; href=&#34;https://github.com/microsoft/vscode-wasm&#34;&gt;microsoft/vscode-wasm&lt;/a&gt; repo (&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/vscode-wasi-pygls/pull/7&#34;&gt;PR&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;esbonio&#34;&gt;
&lt;h2&gt;esbonio&lt;a class=&#34;headerlink&#34; href=&#34;#esbonio&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio&#34;&gt;esbonio&lt;/a&gt; &lt;em&gt;is a language server for your Sphinx documentation projects&lt;/em&gt;&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;I &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/928&#34;&gt;updated esbonio&lt;/a&gt; to the latest pygls &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;v2&lt;/span&gt;&lt;/code&gt; pre-release&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;pytest-lsp&#34;&gt;
&lt;h2&gt;pytest-lsp&lt;a class=&#34;headerlink&#34; href=&#34;#pytest-lsp&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/lsp-devtools&#34;&gt;pytest-lsp&lt;/a&gt; &lt;em&gt;is a pytest plugin for writing end-to-end tests for language servers&lt;/em&gt;&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/lsp-devtools/pull/188&#34;&gt;Updated pytest-lsp&lt;/a&gt; to the latest pygls &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;v2&lt;/span&gt;&lt;/code&gt; pre-release&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;lsp-devtools&#34;&gt;
&lt;h2&gt;lsp-devtools&lt;a class=&#34;headerlink&#34; href=&#34;#lsp-devtools&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/lsp-devtools&#34;&gt;lsp-devtools&lt;/a&gt; &lt;em&gt;is an attempt at building some of the developer tools I wished existed when I first started working on esbonio&lt;/em&gt;&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/lsp-devtools/pull/190&#34;&gt;Dropped support&lt;/a&gt; for Python 3.8&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/lsp-devtools/pull/192&#34;&gt;Updated lsp-devtools&lt;/a&gt; to the latest pygls &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;v2&lt;/span&gt;&lt;/code&gt; pre-release&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2024/inspecting-python-threads/</id>
    <link href="https://www.alcarney.me/blog/2024/inspecting-python-threads" rel="alternate" />
    <published>2024-12-01T00:00:00+00:00</published>
    <updated>2024-12-01T00:00:00+00:00</updated>
    <title>TIL: Inspecting Python Threads</title>
    <content type="html">
      &lt;section id=&#34;til-inspecting-python-threads&#34;&gt;
&lt;h1&gt;TIL: Inspecting Python Threads&lt;a class=&#34;headerlink&#34; href=&#34;#til-inspecting-python-threads&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;One of my favourite things about Python is that pretty much everything about the language can be inspected at runtime and today I found out this is true even for threads.&lt;/p&gt;
&lt;p&gt;While working on &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/928&#34;&gt;this PR&lt;/a&gt; I kept running into issues where the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; process would not terminate, despite everything to my knowledge at least, was being shutdown as expected.
Having encountered issues like this before, I knew the culprit was likely to be some background thread was stuck on something and keeping the process alive.
The problem was I had no idea which thread it could be or what it was doing.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Thanks to &lt;a class=&#34;reference external&#34; href=&#34;https://stackoverflow.com/questions/7189226/program-does-not-exit-how-to-find-out-what-python-is-doing&#34;&gt;this Stack Overflow&lt;/a&gt; post, I discovered Python does provide the tools to figure it out.&lt;/p&gt;
&lt;p&gt;With a breakpoint set just before the point where the process should be exiting, we can first enumerate all the active threads.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;threading&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ident&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;threading&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enumerate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()}&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    140658776004416: &amp;#39;MainThread&amp;#39;,&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    140658503321280: &amp;#39;pydevd.Writer&amp;#39;,&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    140658492835520: &amp;#39;pydevd.Reader&amp;#39;,&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    140658482349760: &amp;#39;pydevd.CommandThread&amp;#39;,&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    140658471864000: &amp;#39;pydevd.CheckAliveThread&amp;#39;,&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    140658444601024: &amp;#39;Thread-6&amp;#39;,&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    140658354423488: &amp;#39;Thread-7&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ignoring all the threads that appear to be part of the debugger (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pydevd.*&lt;/span&gt;&lt;/code&gt;), the issue is probably in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Thread-6&lt;/span&gt;&lt;/code&gt; or &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Thread-7&lt;/span&gt;&lt;/code&gt;.
With the help of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;sys&lt;/span&gt;&lt;/code&gt; module we can get the current stack frame for each thread&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;sys&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;thread_6_stack_frame&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_current_frames&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;140658444601024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;thread_7_stack_frame&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_current_frames&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;140658354423488&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then using the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;traceback&lt;/span&gt;&lt;/code&gt; module we can print the current call stack!&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;traceback&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;print_stack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;thread_6_stack_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/var/home/linuxbrew/.linuxbrew/Cellar/python@3.13/3.13.0_1/lib/python3.13/threading.py&amp;quot;, line 1012, in _bootstrap&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  self._bootstrap_inner()&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/var/home/linuxbrew/.linuxbrew/Cellar/python@3.13/3.13.0_1/lib/python3.13/threading.py&amp;quot;, line 1041, in _bootstrap_inner&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  self.run()&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/var/home/alex/.vscode/extensions/ms-python.debugpy-2024.12.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_daemon_thread.py&amp;quot;, line 53, in run&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  self._on_run()&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/var/home/alex/.vscode/extensions/ms-python.debugpy-2024.12.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_timeout.py&amp;quot;, line 43, in _on_run&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  self._event.wait(wait_time)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/var/home/linuxbrew/.linuxbrew/Cellar/python@3.13/3.13.0_1/lib/python3.13/threading.py&amp;quot;, line 656, in wait&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  with self._cond:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/var/home/linuxbrew/.linuxbrew/Cellar/python@3.13/3.13.0_1/lib/python3.13/threading.py&amp;quot;, line 369, in wait&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  if not gotit:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Hmm, not so useful.. but then again looking closer at the call stack this thread also seems to be related to the debugger.
What about the other thread?&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;traceback&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;print_stack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;thread_7_stack_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/var/home/linuxbrew/.linuxbrew/Cellar/python@3.13/3.13.0_1/lib/python3.13/threading.py&amp;quot;, line 1012, in _bootstrap&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  self._bootstrap_inner()&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/var/home/linuxbrew/.linuxbrew/Cellar/python@3.13/3.13.0_1/lib/python3.13/threading.py&amp;quot;, line 1041, in _bootstrap_inner&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  self.run()&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;File &amp;quot;/home/alex/.local/share/hatch/env/virtual/esbonio/3pU26gTf/hatch-test.py3.13-sphinx6/lib/python3.13/site-packages/aiosqlite/core.py&amp;quot;, line 107, in run&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  tx_item = self._tx.get()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ah! This thread is stuck somewhere in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;aiosqlite&lt;/span&gt;&lt;/code&gt; library, looks like I wasn’t cleaning up all the DB connections like I thought I was!&lt;/p&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2024/local-llms-with-ollama-and-gptel/</id>
    <link href="https://www.alcarney.me/blog/2024/local-llms-with-ollama-and-gptel" rel="alternate" />
    <published>2024-11-16T00:00:00+00:00</published>
    <updated>2024-11-16T00:00:00+00:00</updated>
    <title>TIL: Local LLMs with Ollama and gptel</title>
    <content type="html">
      &lt;section id=&#34;til-local-llms-with-ollama-and-gptel&#34;&gt;
&lt;h1&gt;TIL: Local LLMs with Ollama and gptel&lt;a class=&#34;headerlink&#34; href=&#34;#til-local-llms-with-ollama-and-gptel&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;LLMs don’t look like they’re going to go away anytime soon, so I may as well start playing around with them.
Since I am also using Emacs more and more it also makes sense to try using it as the interface to any models.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;installing-ollama&#34;&gt;
&lt;h2&gt;Installing Ollama&lt;a class=&#34;headerlink&#34; href=&#34;#installing-ollama&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m not terribly interested in messing around with API keys, rate limits and/or billing that seems to come with any of the hosted models.
Thankfully Bluefin/Aurorae &lt;a class=&#34;reference external&#34; href=&#34;https://docs.projectbluefin.io/ai#local-ai&#34;&gt;makes it easy&lt;/a&gt; to get &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/ollama/ollama&#34;&gt;Ollama&lt;/a&gt; up and running locally.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;ujust&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ollama&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;install
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;brew&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;install&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ollama
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;systemctl&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--user&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;start&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ollama
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will make the Ollama API available locally on &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;http://localhost:11434&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;admonition tip&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Tip&lt;/p&gt;
&lt;p&gt;Bluefin/Aurorae also make it easy to spin up an instance of the &lt;a class=&#34;reference external&#34; href=&#34;https://docs.openwebui.com/&#34;&gt;Open Web UI&lt;/a&gt; if you want a Chat GPT style interface&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;ujust&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ollama&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;install-open-webui
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;systemctl&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--user&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;start&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ollama-web
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once everything has spun up, the interface will be available locally on &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;http://localhost:8080&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;choosing-a-model&#34;&gt;
&lt;h2&gt;Choosing a Model&lt;a class=&#34;headerlink&#34; href=&#34;#choosing-a-model&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Installing Ollama by itself however does not give you much, you now have the infrastructure in place to run models and interact with them but it does not come with any models out of the box.&lt;/p&gt;
&lt;p&gt;Unfortunately, there are so many models to choose from!
I have no idea how to pick between them and most of the benchmark scores are meaningless to me.&lt;/p&gt;
&lt;p&gt;However, any model I run will have to run on my CPU so I can let my hardware constraints pick for me.
So looking for something small… ah! &lt;a class=&#34;reference external&#34; href=&#34;https://ollama.com/library/llama3.2&#34;&gt;llama3.2:3b&lt;/a&gt;, it’s a new-ish model, 3b parameters and only a 2GB download, seems as good a choice as any. - Any AI is better then no AI… right? 😅&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;ollama&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;pull&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;llama3.2
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This was all I needed to do in order for the model to show up in Open Web UI however, as I mentioned in the intro I’m interested in interacting with these models via Emacs.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;installing-gptel&#34;&gt;
&lt;h2&gt;Installing gptel&lt;a class=&#34;headerlink&#34; href=&#34;#installing-gptel&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you search for packages that involve AI in some way you will quickly discover a lot of them!
However, stumbling across this &lt;a class=&#34;reference external&#34; href=&#34;https://www.youtube.com/watch?v=bsRnh_brggM&#34;&gt;video demo&lt;/a&gt; of &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/karthink/gptel&#34;&gt;gptel&lt;/a&gt; was enough to sell me on it.&lt;/p&gt;
&lt;p&gt;All it takes is a few lines of elisp to point &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;gptel&lt;/span&gt;&lt;/code&gt; at the local Ollama API.&lt;/p&gt;
&lt;div class=&#34;highlight-elisp notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;package-install&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;&amp;#39;gptel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;setq&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;gptel-model&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;&amp;#39;llama3.2:latest&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;gptel-backend&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;gptel-make-ollama&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Ollama&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                      &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:host&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;localhost:11434&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                      &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:stream&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                      &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;:models&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;llama3.2:latest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And I can now call &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;M-x&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;gptel&lt;/span&gt;&lt;/code&gt; to open a dedicated chat buffer with the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;llama3.2&lt;/span&gt;&lt;/code&gt; model.
Now all I have to do is figure out what these models are actually useful for!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2024/notes-october/</id>
    <link href="https://www.alcarney.me/blog/2024/notes-october" rel="alternate" />
    <published>2024-11-03T00:00:00+00:00</published>
    <updated>2024-11-03T00:00:00+00:00</updated>
    <title>Notes for October</title>
    <content type="html">
      &lt;section id=&#34;notes-for-october&#34;&gt;
&lt;h1&gt;Notes for October&lt;a class=&#34;headerlink&#34; href=&#34;#notes-for-october&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;I want to try and get into the habit of writing more, so taking inspiration from Simon Willison’s &lt;a class=&#34;reference external&#34; href=&#34;https://simonwillison.net/tags/weeknotes/&#34;&gt;weeknotes&lt;/a&gt; here’s a quick writeup of what I have been doing in the month of October.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;esbonio&#34;&gt;
&lt;h2&gt;Esbonio&lt;a class=&#34;headerlink&#34; href=&#34;#esbonio&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio&#34;&gt;esbonio&lt;/a&gt; &lt;em&gt;is a language server for your Sphinx documentation projects&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Work towards the big &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;1.0&lt;/span&gt;&lt;/code&gt; release continues and in the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/releases/tag/esbonio-vscode-extension-v0.96.0&#34;&gt;latest pre-release&lt;/a&gt; of the VSCode extension, it should now be possible to preview documentation builds when running on Codespaces.
(&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/issue/896&#34;&gt;Issue&lt;/a&gt;, &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/905&#34;&gt;PR&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Up until now, Esbonio has required a correctly configured Python environment in order to work at all.
However, one of the most common issues I see is people struggling with this initial setup step and Esbonio will refuse to try anything until it is complete.&lt;/p&gt;
&lt;p&gt;This isn’t ideal and in reality there is plenty Esbonio could do even if the Python environment is has access to is not complete!
So this month I started looking into ways to make the server useful in more situations&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;The VSCode extension now comes with a default Python enviroment to use when the user does not provide their own
(&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/915&#34;&gt;PR&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The language server can now continue to work if one of the required Sphinx extensions is not available
(&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/913&#34;&gt;PR&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The language server will fallback to Sphinx’s default &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;alabaster&lt;/span&gt;&lt;/code&gt; theme if the requested HTML theme is not available
(&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/916&#34;&gt;PR&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There will, of course, be many more situations to handle but it’s a start!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;pygls&#34;&gt;
&lt;h2&gt;pygls&lt;a class=&#34;headerlink&#34; href=&#34;#pygls&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls&#34;&gt;pygls&lt;/a&gt; &lt;em&gt;is the language server framework I help to maintain and use in Esbonio&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Work towards the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;2.0&lt;/span&gt;&lt;/code&gt; release continues and this month I finally was able to tackle the migration from Python’s low-level to high-level asyncio APIs&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls/pull/506&#34;&gt;Move JsonRPCServer.start_io to high-level asyncio API&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls/pull/507&#34;&gt;Migrate JsonRPCServer.start_tcp and JsonRPCServer.start_ws to high level asyncio APIs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls/pull/508&#34;&gt;Replace “transports” with “writers”&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also was able to add TCP and WebSocket support to the language client&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls/pull/501&#34;&gt;Add TCP support to pygls’ LanguageClient&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls/pull/503&#34;&gt;Add start_ws method to pygls’ LanguageClient&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, I was able to clean up the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls/pull/509&#34;&gt;library’s support&lt;/a&gt; for &lt;a class=&#34;reference external&#34; href=&#34;https://pyodide.org/&#34;&gt;Pyodide&lt;/a&gt; and started thinking about what it would take to embed a simple language client into the docs for demos - disappointingly, it may be harder than I would like!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2023/python-wasi-nix/</id>
    <link href="https://www.alcarney.me/blog/2023/python-wasi-nix" rel="alternate" />
    <published>2023-09-18T00:00:00+00:00</published>
    <updated>2023-09-18T00:00:00+00:00</updated>
    <title>Setting up a Python WASI Environment with Nix</title>
    <content type="html">
      &lt;section id=&#34;setting-up-a-python-wasi-environment-with-nix&#34;&gt;
&lt;h1&gt;Setting up a Python WASI Environment with Nix&lt;a class=&#34;headerlink&#34; href=&#34;#setting-up-a-python-wasi-environment-with-nix&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;In this blog post I look at setting up a local development environment for the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/brettcannon/cpython-wasi-build&#34;&gt;WASI build of Python&lt;/a&gt;  using Nix.
You can see the final result &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/python-wasi-nix&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;why&#34;&gt;
&lt;h2&gt;Why?&lt;a class=&#34;headerlink&#34; href=&#34;#why&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&#34;admonition-wasm-and-pyodide-and-wasi-oh-my admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;WASM and Pyodide and WASI, Oh My!&lt;/p&gt;
&lt;p&gt;See Brett Cannon’s &lt;a class=&#34;reference external&#34; href=&#34;https://snarky.ca/webassembly-and-its-platform-targets/&#34;&gt;blog post&lt;/a&gt; for a good overview of the different flavours of WebAssembly platforms.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Some &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2021/bringing-esbonio-to-the-browser/&#34; title=&#34;Bringing Esbonio to the Browser&#34;&gt;time ago&lt;/a&gt; now, I stated that I wanted to get the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio&#34;&gt;esbonio&lt;/a&gt; language server running in &lt;a class=&#34;reference external&#34; href=&#34;https://vscode.dev&#34;&gt;vscode.dev&lt;/a&gt;.
While there
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/pull/438&#34;&gt;has been&lt;/a&gt;
some
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/commit/046d63d8ca07d647498d800fb88f76792bd88ee8&#34;&gt;progress&lt;/a&gt;
towards this goal it’s been little more than proof of concepts.&lt;/p&gt;
&lt;p&gt;One of the biggest challenges has been sharing the contents of the workspace with the &lt;a class=&#34;reference external&#34; href=&#34;https://pyodide.org/en/stable/&#34;&gt;pyodide&lt;/a&gt; runtime I was using to host the language server.
But now that the VSCode team are turning &lt;a class=&#34;reference external&#34; href=&#34;https://code.visualstudio.com/blogs/2023/06/05/vscode-wasm-wasi&#34;&gt;VSCode into a WASI runtime&lt;/a&gt; it might finally be possible to port &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; to the web!&lt;/p&gt;
&lt;p&gt;As a bonus, since &lt;a class=&#34;reference external&#34; href=&#34;https://wasi.dev&#34;&gt;WASI&lt;/a&gt; is a standard, I can use &lt;a class=&#34;reference external&#34; href=&#34;https://wasmtime.dev&#34;&gt;wasmtime&lt;/a&gt; as the host when working on the port locally.
Which brings us to the topic of this blog post.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;ok-but-why-use-nix&#34;&gt;
&lt;h2&gt;Ok, but why use Nix?&lt;a class=&#34;headerlink&#34; href=&#34;#ok-but-why-use-nix&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m sure you could achieve everything that I do here with a bash script but I’ve been playing with Nix &lt;span class=&#34;xref std std-ref&#34;&gt;a lot&lt;/span&gt; recently and I think it’s cool!&lt;/p&gt;
&lt;p&gt;If you want Python + WASI without the Nix see &lt;a class=&#34;reference external&#34; href=&#34;https://snarky.ca/testing-a-project-using-the-wasi-build-of-cpython-with-pytest/&#34;&gt;this blog post&lt;/a&gt;, which I used as the basis for figuring this out.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;building-python&#34;&gt;
&lt;h2&gt;“Building” Python&lt;a class=&#34;headerlink&#34; href=&#34;#building-python&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As an initial step, let’s see if we can get to the point where we can launch a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; in which we can run the WASI version of Python.&lt;/p&gt;
&lt;p&gt;To get the WASM build of Python onto our machine we’ll write a derivation that “builds” it by downloading the release artifact from GitHub and copying it to the output folder&lt;/p&gt;
&lt;div class=&#34;admonition-this-is-wrong admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;This is “wrong”&lt;/p&gt;
&lt;p&gt;To do this the “right” way, I should be using Nix to build the WASI version of Python from source.
But since Brett Cannon is &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/brettcannon/cpython-wasi-build&#34;&gt;publishing builds&lt;/a&gt; on GitHub I’m going to leave that as an exercise for the reader.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/python-wasi.nix&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; fetchzip&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; stdenv &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

stdenv&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mkDerivation &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;python-wasi&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;3.11.4&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; fetchzip &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;https://github.com/brettcannon/cpython-wasi-build/releases/download/v3.11.4/python-3.11.4-wasi_sdk-16.zip&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;stripRoot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;sha256&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;sha256-AZGdgpRvHcu6FY/a7capldjDhTpkfhGkqYnm127nAN8=&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;buildCommand&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;   mkdir $out&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;   cp -r $src/* $out&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;  &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In a corresponding &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; file we can define a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; containing both the WASI build of Python and the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wasmtime&lt;/span&gt;&lt;/code&gt; program required to execute it&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./flake.nix&lt;/span&gt;
utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystem&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;python-wasi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/python-wasi.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{};&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

    devShells&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;wasi&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;shellHook&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;         export PYTHON_WASI=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;python-wasi&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;      &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; wasmtime &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which will be enough to give an an environment where we can try to run a simple Python script:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(nix-shell) $ wasmtime run $PYTHON_WASI/python.wasm -- -c &amp;quot;import sys;print(sys.platform)&amp;quot;
Could not find platform independent libraries &amp;lt;prefix&amp;gt;
Could not find platform dependent libraries &amp;lt;exec_prefix&amp;gt;
Python path configuration:
  PYTHONHOME = (not set)
  PYTHONPATH = (not set)
  program name = &amp;#39;python.wasm&amp;#39;
  isolated = 0
  environment = 1
  user site = 1
  safe_path = 0
  import site = 1
  is in build tree = 0
  stdlib dir = &amp;#39;/usr/local/lib/python3.11&amp;#39;
  sys._base_executable = &amp;#39;&amp;#39;
  sys.base_prefix = &amp;#39;/usr/local&amp;#39;
  sys.base_exec_prefix = &amp;#39;/usr/local&amp;#39;
  sys.platlibdir = &amp;#39;lib&amp;#39;
  sys.executable = &amp;#39;&amp;#39;
  sys.prefix = &amp;#39;/usr/local&amp;#39;
  sys.exec_prefix = &amp;#39;/usr/local&amp;#39;
  sys.path = [
    &amp;#39;/usr/local/lib/python311.zip&amp;#39;,
    &amp;#39;/usr/local/lib/python3.11&amp;#39;,
    &amp;#39;/usr/local/lib/python3.11/lib-dynload&amp;#39;,
  ]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named &amp;#39;encodings&amp;#39;

Current thread 0x00000000 (most recent call first):
  &amp;lt;no Python frame&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Well, that was the plan at least! 😅&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;making-it-work&#34;&gt;
&lt;h2&gt;Making it work&lt;a class=&#34;headerlink&#34; href=&#34;#making-it-work&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Of course… introducing Nix is going to bring its own set of challenges.
Looking at the error message above we can see that Python assumes it has been installed on a traditional Linux operating system and is looking for its standard library under &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/usr/local&lt;/span&gt;&lt;/code&gt;.
However, looking at the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHON_WASI&lt;/span&gt;&lt;/code&gt; environment variable we can see this is not the case:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(nix-shell) $ echo $PYTHON_WASI
/nix/store/5n0m7jxcnksmnp52maxa4li1q91gwq2v-python-wasi-3.11.4

(nix-shell) $ ls $PYTHON_WASI
lib/  python.wasm*
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Thankfully, it’s easy enough to fix with the &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/using/cmdline.html#envvar-PYTHONHOME&#34;&gt;PYTHONHOME&lt;/a&gt; environment variable, we can rename &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHON_WASI&lt;/span&gt;&lt;/code&gt; to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHONHOME&lt;/span&gt;&lt;/code&gt; in the shell’s &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;shellHook&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;shellHook&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;    export PYTHONHOME=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;python-wasi&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, since &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wasmtime&lt;/span&gt;&lt;/code&gt; implements a &lt;a class=&#34;reference external&#34; href=&#34;https://en.wikipedia.org/wiki/Capability-based_security&#34;&gt;capability security model&lt;/a&gt;
we also have to grant access to the both the environment variable &lt;strong&gt;and&lt;/strong&gt; the folder it points to:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ wasmtime run $PYTHONHOME/python.wasm --env PYTHONHOME=$PYTHONHOME --dir $PYTHONHOME -- -c &amp;quot;import sys; print(sys.platform)&amp;quot;
wasi
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;creating-a-wrapper&#34;&gt;
&lt;h2&gt;Creating a Wrapper&lt;a class=&#34;headerlink&#34; href=&#34;#creating-a-wrapper&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While we can now run the WASI Python build, the command to invoke it is rather unwieldy… and we’re not doing anything interesting yet!
Thankfully, we can also use Nix to hide some of these details for us.&lt;/p&gt;
&lt;p&gt;A common pattern you will see in &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs&#34;&gt;nixpkgs&lt;/a&gt; is to have a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;program-name&amp;gt;-unwrapped&lt;/span&gt;&lt;/code&gt; package whose job it is to build said program into a folder in the nix store.
Then a second &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;program-name&amp;gt;&lt;/span&gt;&lt;/code&gt; package containing a bash script that handles the details of invoking the program from within the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/nix/store&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So let’s do the same here!&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/python.nix&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; wasmtime&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; python-wasi&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; writeShellScriptBin &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

writeShellScriptBin &lt;span class=&#34;s2&#34;&gt;&amp;quot;python&amp;quot;&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;wasmtime&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt;/bin/wasmtime run &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;python-wasi&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt;/python.wasm \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     --env PYTHONHOME=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;python-wasi&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt; \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     --dir &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;python-wasi&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt; \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     -- &amp;quot;$@&amp;quot;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which allows us to update our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; definition to the following.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystem&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;python-wasi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/python-wasi.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{};&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/python.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;python-wasi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python-wasi&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

    devShells&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;wasi&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; python &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
 &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Notice how we don’t even need to reference &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wasmtime&lt;/span&gt;&lt;/code&gt; here anymore?
In fact (assuming the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; is active), we can call Python as we would normally!:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ python -c &amp;quot;import sys; print(sys.platform)&amp;quot;
linux

$ nix develop
(nix-shell) $ python -c &amp;quot;import sys; print(sys.platform)&amp;quot;
wasi
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;🤯&lt;/p&gt;
&lt;div class=&#34;admonition tip&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Tip&lt;/p&gt;
&lt;p&gt;You can see the contents of the wrapper script we generated by running:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(nix-shell) $ cat $(command -v python)
#!/nix/store/ir0j7zqlw9dc49grmwplppc7gh0s40yf-bash-5.2-p15/bin/bash
/nix/store/kv8y59aqkz8havf9whvvknm7z05by2dk-wasmtime-11.0.1/bin/wasmtime run /nix/store/5n0m7jxcnksmnp52maxa4li1q91gwq2v-python-wasi-3.11.4/python.wasm \
  --env PYTHONHOME=/nix/store/5n0m7jxcnksmnp52maxa4li1q91gwq2v-python-wasi-3.11.4 \
  --dir /nix/store/5n0m7jxcnksmnp52maxa4li1q91gwq2v-python-wasi-3.11.4 \
  -- &amp;quot;$@&amp;quot;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;But we’re not done yet!
Our Python process does not have access to any files outside of the stdlib&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Python&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;3.11.4&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v3&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.11.4&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d2340ef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Jun&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2023&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;00&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;39&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Clang&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;14.0.4&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;github&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;llvm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;llvm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;project&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;29&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f1039a7285a5c3a9c353d05414&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wasi&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Type&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;copyright&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;credits&amp;quot;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;license&amp;quot;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;more&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;information&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;os&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;ne&#34;&gt;PermissionError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Errno&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;76&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Capabilities&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;insufficient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;But passing an additional &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--dir&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;.&lt;/span&gt;&lt;/code&gt; argument to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wasmtime&lt;/span&gt;&lt;/code&gt; will solve that for us.
The more challenging issue to solve is passing through third party libraries&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Python&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;3.11.4&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v3&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.11.4&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d2340ef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Jun&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2023&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;00&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;39&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Clang&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;14.0.4&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;github&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;llvm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;llvm&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;project&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;29&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f1039a7285a5c3a9c353d05414&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wasi&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Type&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;copyright&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;credits&amp;quot;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;license&amp;quot;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;more&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;information&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;attrs&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;ne&#34;&gt;ModuleNotFoundError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;No&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;named&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;attrs&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;installing-packages&#34;&gt;
&lt;h2&gt;Installing packages&lt;a class=&#34;headerlink&#34; href=&#34;#installing-packages&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is where I’m going to take another shortcut, to do this “correctly” I should probably look at overriding the base Python derivation so that it (and everything that depends on it) uses the WASI build of Python.
This would trigger Nix to (lazily) rebuild all of the Python packages in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nixpkgs&lt;/span&gt;&lt;/code&gt; against that version of Python.&lt;/p&gt;
&lt;p&gt;However, there’s a strong chance that a lot of builds will break and in reality all we really need is a folder full of Python files to import.&lt;/p&gt;
&lt;div class=&#34;admonition-what-about-packages-like-numpy admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;What about packages like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;numpy&lt;/span&gt;&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;While I think there are some moves towards enabling support for packages like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;numpy&lt;/span&gt;&lt;/code&gt; (via the WASM Component Model?),
if you want to use packages that contain native code in WebAssembly, &lt;a class=&#34;reference external&#34; href=&#34;https://pyodide.org/en/stable/&#34;&gt;pyodide&lt;/a&gt;  is probably the best bet for the time being, especially for data science libraries.&lt;/p&gt;
&lt;p&gt;This however, is beyond the scope of this blog post.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So why not reuse the packages already in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nixpkgs&lt;/span&gt;&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;We can take a list of Python package derivations and construct a string to set as the &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH&#34;&gt;PYTHONPATH&lt;/a&gt; environment variable - making all of the required dependencies available to the interpreter.&lt;/p&gt;
&lt;section id=&#34;gathering-dependencies&#34;&gt;
&lt;h3&gt;Gathering Dependencies&lt;a class=&#34;headerlink&#34; href=&#34;#gathering-dependencies&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first thing we need to do is to figure out when given a Python package, is what all of its dependencies are.
Thankfully, to help us figure it out we can use the Nix REPL allowing us to inspect derivations and evaluate expressions:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ nix repl
Welcome to Nix 2.11.1. Type :? for help.

nix-repl&amp;gt; :lf .    # Load the flake located in the current directory
Added 9 variables.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;First let’s locate a package that we’re interested in, note that the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;inputs&lt;/span&gt;&lt;/code&gt; variable corresponds to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;inputs&lt;/span&gt;&lt;/code&gt; attribute set we declared in our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nix-repl&amp;gt; pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux.python311Packages
nix-repl&amp;gt; pkgs.attrs
«derivation /nix/store/bcgw61xp6ss6vaad5ghwqfbm2m795a2g-python3.11-attrs-22.2.0.drv»
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To find out what attributes this derivation has we can type &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pkgs.attrs.&lt;/span&gt;&lt;/code&gt; and then hit &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;Tab&lt;/kbd&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nix&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;repl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LANG&lt;/span&gt;                         &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;outPath&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__ignoreNulls&lt;/span&gt;                &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;outputName&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__structuredAttrs&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;outputs&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;all&lt;/span&gt;                          &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;override&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;                         &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;overrideAttrs&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buildInputs&lt;/span&gt;                  &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;overrideDerivation&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;                      &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;overridePythonAttrs&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmakeFlags&lt;/span&gt;                   &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;passthru&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configureFlags&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;patches&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depsBuildBuild&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pname&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depsBuildBuildPropagated&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;postFixup&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depsBuildTarget&lt;/span&gt;              &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;postInstall&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depsBuildTargetPropagated&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;propagatedBuildInputs&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depsHostHost&lt;/span&gt;                 &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;propagatedNativeBuildInputs&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depsHostHostPropagated&lt;/span&gt;       &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pythonImportsCheck&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depsTargetTarget&lt;/span&gt;             &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pythonModule&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depsTargetTargetPropagated&lt;/span&gt;   &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pythonPath&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disallowedReferences&lt;/span&gt;         &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;requiredPythonModules&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dist&lt;/span&gt;                         &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;doCheck&lt;/span&gt;                      &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stdenv&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;doInstallCheck&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;strictDeps&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;drvAttrs&lt;/span&gt;                     &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;drvPath&lt;/span&gt;                      &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;testout&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inputDerivation&lt;/span&gt;              &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tests&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mesonFlags&lt;/span&gt;                   &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meta&lt;/span&gt;                         &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;updateScript&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;                         &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;userHook&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nativeBuildInputs&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;version&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Well &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;requiredPythonModules&lt;/span&gt;&lt;/code&gt; looks interesting:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nix-repl&amp;gt; pkgs.attrs.requiredPythonModules
[ «derivation /nix/store/2dml7fbspshiwb1j896jd3ajrsq81nl5-python3-3.11.4.drv» ]
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I guess the only dependencies &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;attrs&lt;/span&gt;&lt;/code&gt; has is Python itself, that’s good to know as we will have to drop that from the list of dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nix-repl&amp;gt; lib = inputs.nixpkgs.lib
nix-repl&amp;gt; python = inputs.nixpkgs.legacyPackages.x86_64-linux.python311
nix-repl&amp;gt; python
«derivation /nix/store/2dml7fbspshiwb1j896jd3ajrsq81nl5-python3-3.11.4.drv»

nix-repl&amp;gt; lib.remove python pkgs.attrs.requiredPythonModules
[ ]
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now, how about another package?:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nix-repl&amp;gt; lib.remove python pkgs.pygls.requiredPythonModules
[
  «derivation /nix/store/dsx8aalkf97pi0ja8xs9mlss5lk4bzhv-python3.11-lsprotocol-2023.0.0a2.drv»
  «derivation /nix/store/86933r4czjpmyq3ikz5444f1k1q9rij6-python3.11-typeguard-2.13.3.drv»
  «derivation /nix/store/bcgw61xp6ss6vaad5ghwqfbm2m795a2g-python3.11-attrs-22.2.0.drv»
  «derivation /nix/store/f19ymrh2zv9hzh00wjvjv73v529n3ds4-python3.11-cattrs-23.1.2.drv»
]
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Based on some experiments I think &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;requiredPythonModules&lt;/span&gt;&lt;/code&gt; automatically handles transitive dependencies for us!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;setting-pythonpath&#34;&gt;
&lt;h3&gt;Setting &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHONPATH&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#setting-pythonpath&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ll spare you the trial and error and skip to the following lines of nix code which take a list of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pyPackages&lt;/span&gt;&lt;/code&gt; and converts it into a value we can use with &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHONPATH&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;pyDeps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;concatMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pkg&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;remove pkg&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pythonModule pkg&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;requiredPythonModules&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; pyPackages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;ss&#34;&gt;allPackages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;unique &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyPackages &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; pyDeps&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;ss&#34;&gt;pythonPath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;concatMapStringsSep &lt;span class=&#34;s2&#34;&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pkg&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pkg&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/lib/python3.11/site-packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; allPackages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Don’t forget we will also have to grant the process access to each of the folders we add to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHONPATH&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;concatMapStringsSep &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pkg&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;--dir &amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pkg&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/lib/python3.11/site-packages&amp;#39; &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; allPackages
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;mkpythonwasishell&#34;&gt;
&lt;h3&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mkPythonWASIShell&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#mkpythonwasishell&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We now have everything we need to rewrite our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;./nix/python.nix&lt;/span&gt;&lt;/code&gt; file to define a helper function  which takes a list of Python packages and creates a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; containing the WASI build of Python and all of our declared dependencies.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/python.nix&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Dependencies for our function (mostly) coming from `nixpkgs`&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; lib
&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; python-wasi
&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; mkShell
&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; stdenv
&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; wasmtime
&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; writeShellScriptBin
&lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Arguments the user can set when invoking the function&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; pyPackages &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Implementation details&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pyDeps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;concatMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pkg&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;remove pkg&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pythonModule pkg&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;requiredPythonModules&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; pyPackages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;allPackages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;unique &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyPackages &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; pyDeps&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pythonPath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;concatMapStringsSep &lt;span class=&#34;s2&#34;&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pkg&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pkg&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/lib/python3.11/site-packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; allPackages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# This should look familiar...&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; writeShellScriptBin &lt;span class=&#34;s2&#34;&gt;&amp;quot;python&amp;quot;&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;wasmtime&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt;/bin/wasmtime run &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;python-wasi&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt;/python.wasm \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     --env PYTHONHOME=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;python-wasi&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt; \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     --env PYTHONPATH=&amp;#39;.:&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pythonPath&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39; \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     --dir &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;python-wasi&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt; \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;concatMapStringsSep &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pkg&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;--dir &amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pkg&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/lib/python3.11/site-packages&amp;#39; &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; allPackages&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt; \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     --dir . \&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;     -- &amp;quot;$@&amp;quot;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;  &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Our function&amp;#39;s return value&lt;/span&gt;
mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;python-wasi&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; python &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The function only gets a name when we import it into the top-level &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; file&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;ss&#34;&gt;python-wasi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/python-wasi.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{};&lt;/span&gt;
&lt;span class=&#34;ss&#34;&gt;mkPythonWASIShell&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/python.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;python-wasi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python-wasi&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;callPackage&lt;/span&gt;&lt;/code&gt; function uses some kind of ✨magic✨ to automatically pass through all the dependencies (like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wasmtime&lt;/span&gt;&lt;/code&gt;) we declared in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;./nix/python.nix&lt;/span&gt;&lt;/code&gt; - except for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python-wasi&lt;/span&gt;&lt;/code&gt; which we pass through by hand.&lt;/p&gt;
&lt;p&gt;Defining an environment based on &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mkPythonWASIShell&lt;/span&gt;&lt;/code&gt; would then look something like the following&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;devShells&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; mkPythonWASIShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pyPackages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;python311Packages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    pygls
  &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which we can now try to develop with:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ nix develop
(nix-shell) $ python
Python 3.11.4 (tags/v3.11.4-dirty:d2340ef, Jun  8 2023, 00:39:32) [Clang 14.0.4 (https://github.com/llvm/llvm-project 29f1039a7285a5c3a9c353d05414 on wasi
Type &amp;quot;help&amp;quot;, &amp;quot;copyright&amp;quot;, &amp;quot;credits&amp;quot; or &amp;quot;license&amp;quot; for more information.
&amp;gt;&amp;gt;&amp;gt; from pygls.server import LanguageServer
Traceback (most recent call last):
  File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;
  File &amp;quot;/nix/store/g4p26w5gh74nndclnskypc74ni37jqm6-python3.11-pygls-1.0.1/lib/python3.11/site-packages/pygls/server.py&amp;quot;, line 42, in &amp;lt;module&amp;gt;
    from multiprocessing.pool import ThreadPool
ModuleNotFoundError: No module named &amp;#39;multiprocessing&amp;#39;
&amp;gt;&amp;gt;&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Assuming the packages support the WASI runtime that is! 😅&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;next-steps&#34;&gt;
&lt;h2&gt;Next steps&lt;a class=&#34;headerlink&#34; href=&#34;#next-steps&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are interested you can find the final version of the code &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/python-wasi-nix&#34;&gt;here&lt;/a&gt;.
I’m not really sure where it will go from here, as it’s now “good enough” for me to start hacking on the WASI runtime, but there’s certainly plenty that could be improved.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Building Python WASI from source&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatically choosing the right Python package set to use with &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mkPythonWASIShell&lt;/span&gt;&lt;/code&gt;, like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python.withPackages&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extending &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mkPythonWASIShell&lt;/span&gt;&lt;/code&gt; to allow the user to set the permissions for the Python process&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Overriding a base &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python&lt;/span&gt;&lt;/code&gt; derivation so that packages are built against this version of Python.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extending this to work with packages that contain native modules?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2023/nix-day-to-day/</id>
    <link href="https://www.alcarney.me/blog/2023/nix-day-to-day" rel="alternate" />
    <published>2023-07-27T00:00:00+00:00</published>
    <updated>2023-07-27T00:00:00+00:00</updated>
    <title>Nix: Day to Day Usage</title>
    <content type="html">
      &lt;section id=&#34;nix-day-to-day-usage&#34;&gt;
&lt;h1&gt;Nix: Day to Day Usage&lt;a class=&#34;headerlink&#34; href=&#34;#nix-day-to-day-usage&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;This blog post marks a change in my usage of Nix, I’m (just!) past the point of trying to get &lt;em&gt;something&lt;/em&gt; to work and now starting to incorporate it into some of my regular workflows.
So instead of trying to accomplish some major task, this post is a small collection of things I’ve learned over the past few weeks.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;a-better-devshell-definition&#34;&gt;
&lt;h2&gt;A better &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; definition&lt;a class=&#34;headerlink&#34; href=&#34;#a-better-devshell-definition&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The original issue I’m trying to solve dates back to my &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2022/first-steps-with-nix/&#34; title=&#34;My First Steps with Nix&#34;&gt;first post&lt;/a&gt; on using Nix.
That is, defining a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; containing the dependencies of a local Python package doesn’t mean that the local package itself is importable when the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; is activated.&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ nix develop .#py310
(nix-shell) $ pytest
================================================= test session starts =================================================
platform linux -- Python 3.10.12, pytest-7.2.1, pluggy-1.0.0
rootdir: /var/home/alex/Projects/lsp-devtools/lib/pytest-lsp, configfile: pyproject.toml
plugins: typeguard-3.0.2, asyncio-0.20.3
asyncio: mode=auto
collected 16 items / 1 error

======================================================= ERRORS ========================================================
________________________________________ ERROR collecting tests/test_client.py ________________________________________
ImportError while importing test module &amp;#39;/var/home/alex/Projects/lsp-devtools/lib/pytest-lsp/tests/test_client.py&amp;#39;.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/nix/store/1r6n7v2wam7gkr18gxccpg7p5ywgw551-python3-3.10.12/lib/python3.10/importlib/__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
tests/test_client.py:9: in &amp;lt;module&amp;gt;
    import pytest_lsp
E   ModuleNotFoundError: No module named &amp;#39;pytest_lsp&amp;#39;
=============================================== short test summary info ===============================================
ERROR tests/test_client.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================== 1 error in 0.16s ===================================================
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Initially I tried to solve this by also including the Nix package defined for the local Python package itself in the definition of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; but with any &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2023/nix-overlays-p2/#nix-overlays-disable-tests&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;tests disabled&lt;/span&gt;&lt;/a&gt;.
While this worked, it wasn’t very useful when trying to do any real development with it.&lt;/p&gt;
&lt;p&gt;The problem is that upon activating the shell, Nix will freeze the source as part of the build process.
Which means for any edits to take effect, you have to exit the shell and re-enter it to trigger another build to pick up the changes.
Not only does this fill your &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/nix/store&lt;/span&gt;&lt;/code&gt; with 100s of copies of your project, it gets tedious very quickly!&lt;/p&gt;
&lt;p&gt;Since then however, I’ve learned that when installating a Python package, Nix is only adding the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/nix/store&lt;/span&gt;&lt;/code&gt; path for it to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHONPATH&lt;/span&gt;&lt;/code&gt; environment variable:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(nix-shell) $ echo $PYTHONPATH | tr &amp;#39;:&amp;#39; &amp;#39;\n&amp;#39;
/nix/store/99i2wwkhcgr98kjn5wnr25sb87dk4zkk-python3.10-pygls-1.0.1/lib/python3.10/site-packages
/nix/store/ckmh39zca1gjagq4cmharbvzggcmm4qx-python3.10-lsprotocol-2023.0.0a2/lib/python3.10/site-packages
/nix/store/n80x8k099gfslvbg4s13hpaiiynimsw5-python3.10-attrs-22.2.0/lib/python3.10/site-packages
/nix/store/1r6n7v2wam7gkr18gxccpg7p5ywgw551-python3-3.10.12/lib/python3.10/site-packages
/nix/store/aiabj9kh174a3ybdr00q3zpm7w6vqv99-python3.10-cattrs-22.2.0/lib/python3.10/site-packages
/nix/store/4bv2ic5mbp639xi0r75y5aq3d8yd04qa-python3.10-exceptiongroup-1.1.0/lib/python3.10/site-packages
/nix/store/jxpkywimbcxzmsc604gfgibdvlj8x3ch-python3.10-typeguard-3.0.2/lib/python3.10/site-packages
/nix/store/5vwslcxd6w3ck9dlgf8zw87ha2cnf5zz-python3.10-importlib-metadata-6.0.0/lib/python3.10/site-packages
/nix/store/4s0w0rp502c09f7vngmnwdmxaans4k70-python3.10-toml-0.10.2/lib/python3.10/site-packages
/nix/store/6zrrhy4mv339hd6rhc19immll0qpm9fr-python3.10-zipp-3.15.0/lib/python3.10/site-packages
/nix/store/082nwhxg32ykrc4bcd9wacj1pzgyf7ii-python3.10-typing-extensions-4.5.0/lib/python3.10/site-packages
/nix/store/hzv8xjxk35i72jrljvjhl9y5i00vnsqn-python3.10-pytest-7.2.1/lib/python3.10/site-packages
/nix/store/064q1k7k7g05ls3m7cqdh32nisj51pgw-python3.10-iniconfig-2.0.0/lib/python3.10/site-packages
/nix/store/c5fh1flbs76jpgmvzz96xa26c3fwsq2s-python3.10-packaging-23.0/lib/python3.10/site-packages
/nix/store/0mkyiplpq1iy1y4kvkpj4gwcfism1bkw-python3.10-pluggy-1.0.0/lib/python3.10/site-packages
/nix/store/4k182588zcl6j9n08qmy8395qanxw86r-python3.10-py-1.11.0/lib/python3.10/site-packages
/nix/store/k40s1gy6pkzdzb7l14jhsmfamwjmpgnk-python3.10-tomli-2.0.1/lib/python3.10/site-packages
/nix/store/3k5y2a1my07fpbv1p24a7gplk6nqpnpf-python3.10-pytest-asyncio-0.20.3/lib/python3.10/site-packages
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So why not put our local package’s source there as well?&lt;/p&gt;
&lt;p&gt;All we need to do is add a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;shellHook&lt;/span&gt;&lt;/code&gt; to the devShell’s definiton that adds the working directory to the existing &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHONPATH&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shellHook&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PYTHONPATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;./:$PYTHONPATH&amp;quot;&lt;/span&gt;
&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; behaves like an &lt;a class=&#34;reference external&#34; href=&#34;https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs&#34;&gt;editable install&lt;/a&gt; of a Python package - no rebuilds required!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;defining-a-build-matrix&#34;&gt;
&lt;h2&gt;Defining a build matrix&lt;a class=&#34;headerlink&#34; href=&#34;#defining-a-build-matrix&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far, all my &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; definitions have been making use of a function I wrote called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachPythonVersion&lt;/span&gt;&lt;/code&gt; (see &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2022/first-steps-with-nix/#first-steps-nix-multiple-python-versions&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;this section&lt;/span&gt;&lt;/a&gt; for more details) which would let me define a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; once, but reuse it across multiple Python versions&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;shellHook&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;          export PYTHONPATH=&amp;quot;./:$PYTHONPATH&amp;quot;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;        &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
          pygls
          pytest
          pytest-asyncio
        &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, if you look at the implementation of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachPythonVersion&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;listToAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; f version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;it&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;only supports parametrising a single version number&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;only supports producing a single ‘thing’ for each version number&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;is not easily adapatable to other situations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Currently I’m working on the next major version of &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio&#34;&gt;esbonio&lt;/a&gt; and need to be able to define multiple &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShells&lt;/span&gt;&lt;/code&gt; per Python version each containing a different version of Sphinx.&lt;/p&gt;
&lt;p&gt;So ideally, I’d want to be able to define my build matrix&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;buildMatrix&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;py&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;sphinx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;5&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;6&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;7&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and then apply it over some function to get definitions for all combinations of supported versions&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  applyMatrix buildMatrix &lt;span class=&#34;p&#34;&gt;({&lt;/span&gt; py&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; sphinx&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;py&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;-esbonio&amp;quot;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;          &lt;span class=&#34;c1&#34;&gt;# A shell without sphinx avaialable at all&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;py&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;-sphinx&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;sphinx&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# A shell containing the given sphinx verison&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;details&gt;&lt;summary&gt;Which expands into a lot of devShells!&lt;/summary&gt;&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ nix flake show
git+file:///var/home/alex/Projects/esbonio-beta?dir=lib%2fesbonio
├───devShells
│   ├───aarch64-darwin
│   │   ├───py310-esbonio: development environment &amp;#39;py310-esbonio&amp;#39;
│   │   ├───py310-sphinx5: development environment &amp;#39;py310-sphinx5&amp;#39;
│   │   ├───py310-sphinx6: development environment &amp;#39;py310-sphinx6&amp;#39;
│   │   ├───py310-sphinx7: development environment &amp;#39;py310-sphinx7&amp;#39;
│   │   ├───py311-esbonio: development environment &amp;#39;py311-esbonio&amp;#39;
│   │   ├───py311-sphinx5: development environment &amp;#39;py311-sphinx5&amp;#39;
│   │   ├───py311-sphinx6: development environment &amp;#39;py311-sphinx6&amp;#39;
│   │   ├───py311-sphinx7: development environment &amp;#39;py311-sphinx7&amp;#39;
│   │   ├───py38-esbonio: development environment &amp;#39;py38-esbonio&amp;#39;
│   │   ├───py38-sphinx5: development environment &amp;#39;py38-sphinx5&amp;#39;
│   │   ├───py38-sphinx6: development environment &amp;#39;py38-sphinx6&amp;#39;
│   │   ├───py38-sphinx7: development environment &amp;#39;py38-sphinx7&amp;#39;
│   │   ├───py39-esbonio: development environment &amp;#39;py39-esbonio&amp;#39;
│   │   ├───py39-sphinx5: development environment &amp;#39;py39-sphinx5&amp;#39;
│   │   ├───py39-sphinx6: development environment &amp;#39;py39-sphinx6&amp;#39;
│   │   └───py39-sphinx7: development environment &amp;#39;py39-sphinx7&amp;#39;
│   ├───aarch64-linux
│   │   ├───py310-esbonio: development environment &amp;#39;py310-esbonio&amp;#39;
│   │   ├───py310-sphinx5: development environment &amp;#39;py310-sphinx5&amp;#39;
│   │   ├───py310-sphinx6: development environment &amp;#39;py310-sphinx6&amp;#39;
│   │   ├───py310-sphinx7: development environment &amp;#39;py310-sphinx7&amp;#39;
│   │   ├───py311-esbonio: development environment &amp;#39;py311-esbonio&amp;#39;
│   │   ├───py311-sphinx5: development environment &amp;#39;py311-sphinx5&amp;#39;
│   │   ├───py311-sphinx6: development environment &amp;#39;py311-sphinx6&amp;#39;
│   │   ├───py311-sphinx7: development environment &amp;#39;py311-sphinx7&amp;#39;
│   │   ├───py38-esbonio: development environment &amp;#39;py38-esbonio&amp;#39;
│   │   ├───py38-sphinx5: development environment &amp;#39;py38-sphinx5&amp;#39;
│   │   ├───py38-sphinx6: development environment &amp;#39;py38-sphinx6&amp;#39;
│   │   ├───py38-sphinx7: development environment &amp;#39;py38-sphinx7&amp;#39;
│   │   ├───py39-esbonio: development environment &amp;#39;py39-esbonio&amp;#39;
│   │   ├───py39-sphinx5: development environment &amp;#39;py39-sphinx5&amp;#39;
│   │   ├───py39-sphinx6: development environment &amp;#39;py39-sphinx6&amp;#39;
│   │   └───py39-sphinx7: development environment &amp;#39;py39-sphinx7&amp;#39;
│   ├───x86_64-darwin
│   │   ├───py310-esbonio: development environment &amp;#39;py310-esbonio&amp;#39;
│   │   ├───py310-sphinx5: development environment &amp;#39;py310-sphinx5&amp;#39;
│   │   ├───py310-sphinx6: development environment &amp;#39;py310-sphinx6&amp;#39;
│   │   ├───py310-sphinx7: development environment &amp;#39;py310-sphinx7&amp;#39;
│   │   ├───py311-esbonio: development environment &amp;#39;py311-esbonio&amp;#39;
│   │   ├───py311-sphinx5: development environment &amp;#39;py311-sphinx5&amp;#39;
│   │   ├───py311-sphinx6: development environment &amp;#39;py311-sphinx6&amp;#39;
│   │   ├───py311-sphinx7: development environment &amp;#39;py311-sphinx7&amp;#39;
│   │   ├───py38-esbonio: development environment &amp;#39;py38-esbonio&amp;#39;
│   │   ├───py38-sphinx5: development environment &amp;#39;py38-sphinx5&amp;#39;
│   │   ├───py38-sphinx6: development environment &amp;#39;py38-sphinx6&amp;#39;
│   │   ├───py38-sphinx7: development environment &amp;#39;py38-sphinx7&amp;#39;
│   │   ├───py39-esbonio: development environment &amp;#39;py39-esbonio&amp;#39;
│   │   ├───py39-sphinx5: development environment &amp;#39;py39-sphinx5&amp;#39;
│   │   ├───py39-sphinx6: development environment &amp;#39;py39-sphinx6&amp;#39;
│   │   └───py39-sphinx7: development environment &amp;#39;py39-sphinx7&amp;#39;
│   └───x86_64-linux
│       ├───py310-esbonio: development environment &amp;#39;py310-esbonio&amp;#39;
│       ├───py310-sphinx5: development environment &amp;#39;py310-sphinx5&amp;#39;
│       ├───py310-sphinx6: development environment &amp;#39;py310-sphinx6&amp;#39;
│       ├───py310-sphinx7: development environment &amp;#39;py310-sphinx7&amp;#39;
│       ├───py311-esbonio: development environment &amp;#39;py311-esbonio&amp;#39;
│       ├───py311-sphinx5: development environment &amp;#39;py311-sphinx5&amp;#39;
│       ├───py311-sphinx6: development environment &amp;#39;py311-sphinx6&amp;#39;
│       ├───py311-sphinx7: development environment &amp;#39;py311-sphinx7&amp;#39;
│       ├───py38-esbonio: development environment &amp;#39;py38-esbonio&amp;#39;
│       ├───py38-sphinx5: development environment &amp;#39;py38-sphinx5&amp;#39;
│       ├───py38-sphinx6: development environment &amp;#39;py38-sphinx6&amp;#39;
│       ├───py38-sphinx7: development environment &amp;#39;py38-sphinx7&amp;#39;
│       ├───py39-esbonio: development environment &amp;#39;py39-esbonio&amp;#39;
│       ├───py39-sphinx5: development environment &amp;#39;py39-sphinx5&amp;#39;
│       ├───py39-sphinx6: development environment &amp;#39;py39-sphinx6&amp;#39;
│       └───py39-sphinx7: development environment &amp;#39;py39-sphinx7&amp;#39;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;&lt;p&gt;The question is, how do we implement &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;applyMatrix&lt;/span&gt;&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Well, fast forwarding through plenty of trial and error and a few “aha!” moments I’m now able to tell you!&lt;/p&gt;
&lt;p&gt;First, we need to take the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;buildMatrix&lt;/span&gt;&lt;/code&gt; and expand it out into all possible combinations - thankfully &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nixpkgs&lt;/span&gt;&lt;/code&gt; provides a function that does exactly that&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ nix repl
&amp;gt; buildMatrix = { py = [ &amp;quot;38&amp;quot; &amp;quot;39&amp;quot; &amp;quot;310&amp;quot; &amp;quot;311&amp;quot; ]; sphinx = [ &amp;quot;5&amp;quot; &amp;quot;6&amp;quot; &amp;quot;7&amp;quot; ]; }
&amp;gt; allCombinations = nixpkgs.lib.cartesianProductOfSets buildMatrix
&amp;gt; :p allCombinations  # &amp;#39;:p&amp;#39; Overrides nix&amp;#39;s lazy evaluation to print the
                      # fully expanded version of an object
[
  { py = &amp;quot;38&amp;quot;; sphinx = &amp;quot;5&amp;quot;; }
  { py = &amp;quot;38&amp;quot;; sphinx = &amp;quot;6&amp;quot;; }
  { py = &amp;quot;38&amp;quot;; sphinx = &amp;quot;7&amp;quot;; }
  { py = &amp;quot;39&amp;quot;; sphinx = &amp;quot;5&amp;quot;; }
  { py = &amp;quot;39&amp;quot;; sphinx = &amp;quot;6&amp;quot;; }
  { py = &amp;quot;39&amp;quot;; sphinx = &amp;quot;7&amp;quot;; }
  { py = &amp;quot;310&amp;quot;; sphinx = &amp;quot;5&amp;quot;; }
  { py = &amp;quot;310&amp;quot;; sphinx = &amp;quot;6&amp;quot;; }
  { py = &amp;quot;310&amp;quot;; sphinx = &amp;quot;7&amp;quot;; }
  { py = &amp;quot;311&amp;quot;; sphinx = &amp;quot;5&amp;quot;; }
  { py = &amp;quot;311&amp;quot;; sphinx = &amp;quot;6&amp;quot;; }
  { py = &amp;quot;311&amp;quot;; sphinx = &amp;quot;7&amp;quot;; }
]
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next we need to apply some function over this list to produce the corresponding environment&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&amp;gt; shells = builtins.map ({py, sphinx}: {&amp;quot;py${py}-sphinx${sphinx}&amp;quot; = { }; }) allCombinations
&amp;gt; :p shells
[
  { py38-sphinx5 = { }; }
  { py38-sphinx6 = { }; }
  { py38-sphinx7 = { }; }
  { py39-sphinx5 = { }; }
  { py39-sphinx6 = { }; }
  { py39-sphinx7 = { }; }
  { py310-sphinx5 = { }; }
  { py310-sphinx6 = { }; }
  { py310-sphinx7 = { }; }
  { py311-sphinx5 = { }; }
  { py311-sphinx6 = { }; }
  { py311-sphinx7 = { }; }
]
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally, we need to merge the list of attribute sets down into a single set containing all of the definitions&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&amp;gt; result = builtins.foldl&amp;#39; (x: y: x // y) {} shells
&amp;gt; :p result
{
  py310-sphinx5 = { };
  py310-sphinx6 = { };
  py310-sphinx7 = { };
  py311-sphinx5 = { };
  py311-sphinx6 = { };
  py311-sphinx7 = { };
  py38-sphinx5 = { };
  py38-sphinx6 = { };
  py38-sphinx7 = { };
  py39-sphinx5 = { };
  py39-sphinx6 = { };
  py39-sphinx7 = { };
}
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Bringing it all together results in a surprisingly compact function definition!&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;applyMatrix&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; matrix&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;foldl&amp;#39; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;x&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; y&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; x &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; y&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map&lt;/span&gt; f &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;nixpkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;cartesianProductOfSets matrix&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;flakes-and-monorepos&#34;&gt;
&lt;h2&gt;Flakes and Monorepos&lt;a class=&#34;headerlink&#34; href=&#34;#flakes-and-monorepos&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2023/integrate-esbonio-nvim-with-nix/&#34; title=&#34;Integrating Esbonio with Neovim Using Nix&#34;&gt;Previously&lt;/a&gt; I tried adding a “top-level” &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; to the git repository for the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio&#34;&gt;esbonio&lt;/a&gt; language server that depended on another &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; within a sub directory of the same repository.&lt;/p&gt;
&lt;p&gt;It… &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/issues/570&#34;&gt;didn’t work&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m still trying to figure out the best way to approach this but I’m currently leaning towards keeping the multiple &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; files where&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;the top-level &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; contains “public” entry-points e.g. &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;apps&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;overlays&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“local” &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; files for each sub-project containing entry-points that are mainly useful for contributors to the project e.g. &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShells&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rather than have the top-level  &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; depend on the “local” flakes, use Nix’s &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;import&lt;/span&gt;&lt;/code&gt; statement to pull in reusable snippets of Nix code from the subprojects.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;🤞 it works out!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2023/integrate-esbonio-nvim-with-nix/</id>
    <link href="https://www.alcarney.me/blog/2023/integrate-esbonio-nvim-with-nix" rel="alternate" />
    <published>2023-04-21T00:00:00+00:00</published>
    <updated>2023-04-21T00:00:00+00:00</updated>
    <title>Integrating Esbonio with Neovim Using Nix</title>
    <content type="html">
      &lt;section id=&#34;integrating-esbonio-with-neovim-using-nix&#34;&gt;
&lt;h1&gt;Integrating Esbonio with Neovim Using Nix&lt;a class=&#34;headerlink&#34; href=&#34;#integrating-esbonio-with-neovim-using-nix&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;So far I’ve been learning how to use Nix by trying to package and define development shells for &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio&#34;&gt;esbonio&lt;/a&gt; (see &lt;span class=&#34;xref std std-ref&#34;&gt;here&lt;/span&gt; if you are interested).
While useful, the end result is not too dissimilar to what you can get with standard Python tooling.
Indeed, the main reason I started looking into Nix was the promise of it being able to manage more than just Python libraries.&lt;/p&gt;
&lt;p&gt;Since &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; is a language server, it would be useful for Nix to create standardised environments where the language server is pre-configured for a given editor - great for debugging and demos!&lt;/p&gt;
&lt;p&gt;In this blog post I try to define an environment in which Neovim is installed and configured to use the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; language server for reStructuredText files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition-try-it-yourself admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Try it yourself!&lt;/p&gt;
&lt;p&gt;If I’ve done all my homework right, you &lt;strong&gt;should&lt;/strong&gt; be able to try the result of this blog post for yourself
Assuming you have nix installed&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;run&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;github:alcarney/esbonio?rev&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;a077efeed176dcad2ae5e4fd221179d266f88ca1
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;should be the only command you need.
Let me know if you run into any issues!&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;defining-applications&#34;&gt;
&lt;h2&gt;Defining Applications&lt;a class=&#34;headerlink&#34; href=&#34;#defining-applications&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.wiki/wiki/Flakes#Output_schema&#34;&gt;defined flake outputs&lt;/a&gt; is &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;apps.&amp;lt;system&amp;gt;.&amp;lt;name&amp;gt;&lt;/span&gt;&lt;/code&gt; which as the name suggests allows you to export applications from a flake.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;Esbonio&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;inputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    nixpkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:NixOS/nixpkgs/nixpkgs-unstable&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:numtide/flake-utils&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; utils &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;
    utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystem &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        apps&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;program&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;neovim&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/bin/nvim&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This simple &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; exports neovim as an application which we can launch by running &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;.&lt;/span&gt;&lt;/code&gt; from the folder containing this flake.&lt;/p&gt;
&lt;figure class=&#34;align-center&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/nix-nvim-myconfig.png&#34; src=&#34;https://www.alcarney.me/_images/nix-nvim-myconfig.png&#34; style=&#34;width: 50%;&#34; /&gt;
&lt;/figure&gt;
&lt;p&gt;Which works as expected however, it’s also picking up my personal config - not so useful when you’re trying to create a standard, isolated environment.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;isolated-configuration&#34;&gt;
&lt;h2&gt;Isolated Configuration&lt;a class=&#34;headerlink&#34; href=&#34;#isolated-configuration&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As with most things in Nix, the neovim package definition allows for certain fields to be overridden - including the config.
Let’s start by trying provide an empty &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;init.vim&lt;/span&gt;&lt;/code&gt; file.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystem &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
     &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
     &lt;span class=&#34;ss&#34;&gt;neovim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;neovim&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;override &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;configure&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;customRC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;         &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
       &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
     apps&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;program&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;neovim&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/bin/nvim&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
 &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And try &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;.&lt;/span&gt;&lt;/code&gt; again&lt;/p&gt;
&lt;figure class=&#34;align-center&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/nix-nvim-emptyconfig.png&#34; src=&#34;https://www.alcarney.me/_images/nix-nvim-emptyconfig.png&#34; style=&#34;width: 50%;&#34; /&gt;
&lt;/figure&gt;
&lt;p&gt;Which worked! Sort of… well… not really. 😕&lt;/p&gt;
&lt;p&gt;It worked in the sense that it loaded the empty &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;init.vim&lt;/span&gt;&lt;/code&gt; file we specified (notice that the screenshot above has no line numbers).
However, it’s not truly isolated since it went ahead and loaded my plugins anyway due to my user’s home folder being included in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;runtimepath&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;admonition tip&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Tip&lt;/p&gt;
&lt;p&gt;To get the contents of your &lt;a class=&#34;reference external&#34; href=&#34;https://neovim.io/doc/user/options.html#&#39;runtimepath&#39;&#34;&gt;runtimepath&lt;/a&gt;
into a buffer.&lt;/p&gt;
&lt;ol class=&#34;arabic simple&#34;&gt;
&lt;li&gt;&lt;p&gt;In &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;INSERT&lt;/span&gt;&lt;/code&gt; mode type &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;c-r&amp;gt;=&amp;amp;rtp&lt;/span&gt;&lt;/code&gt; and hit enter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replace all commas with newlines &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;:%s/,/\r/g&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;p&gt;So how can we exclude them?&lt;/p&gt;
&lt;section id=&#34;nvim-clean&#34;&gt;
&lt;h3&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nvim&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;--clean&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#nvim-clean&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reading through &lt;a class=&#34;reference external&#34; href=&#34;https://neovim.io/doc/user/options.html#&#39;runtimepath&#39;&#34;&gt;:h ‘runtimepath’&lt;/a&gt; there’s a lot of detail around which paths are searched by default and in what order.
But right at the end there’s a little note&lt;/p&gt;
&lt;blockquote class=&#34;pull-quote&#34;&gt;
&lt;div&gt;&lt;p&gt;With &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--clean&lt;/span&gt;&lt;/code&gt; the home directory entries are not included.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Which sounds like just what we need!
The question is… how do we start &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nvim&lt;/span&gt;&lt;/code&gt; with that flag?&lt;/p&gt;
&lt;p&gt;Looking around the nixpkgs repo for a bit I found a set of
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/d8f05d468eb7b0a97cef73b9b6631613cfac13a7/pkgs/applications/editors/neovim/tests/default.nix&#34;&gt;test cases&lt;/a&gt;
that made use of a
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/d8f05d468eb7b0a97cef73b9b6631613cfac13a7/pkgs/applications/editors/neovim/utils.nix#L24&#34;&gt;utility&lt;/a&gt;
for generating a config, along with a
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/d8f05d468eb7b0a97cef73b9b6631613cfac13a7/pkgs/applications/editors/neovim/wrapper.nix&#34;&gt;wrapper&lt;/a&gt;
which converts the given config into a shell script.
This shell script pulls together various components from &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/nix/store&lt;/span&gt;&lt;/code&gt;, before ultimately launching our isolated instance of neovim.&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Example wrapper script&lt;/summary&gt;&lt;p&gt;Here is an example of a wrapper script generated by nix.&lt;/p&gt;
&lt;div class=&#34;highlight-bash notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ch&#34;&gt;#! /nix/store/0hx32wk55ml88jrb1qxwg5c5yazfm6gf-bash-5.2-p15/bin/bash -e&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;NVIM_SYSTEM_RPLUGIN_MANIFEST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/nix/store/jjl5fy7dc5cxvc7mi781vxbk8ag89ih0-neovim-0.8.3-esbonio/rplugin.vim&amp;#39;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;GEM_HOME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/nix/store/4mmkiw8n1nhlfsnh4g2kijzkxnp6fyxb-neovim-ruby-env/lib/ruby/gems/2.7.0&amp;#39;&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PATH&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PATH&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;!&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;*&lt;span class=&#34;s1&#34;&gt;&amp;#39;:&amp;#39;&amp;#39;/nix/store/4mmkiw8n1nhlfsnh4g2kijzkxnp6fyxb-neovim-ruby-env/bin&amp;#39;&amp;#39;:&amp;#39;&lt;/span&gt;*&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PATH&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/nix/store/4mmkiw8n1nhlfsnh4g2kijzkxnp6fyxb-neovim-ruby-env/bin&amp;#39;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;PATH
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LUA_PATH&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&amp;#39;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/share/lua/5.1/?/init.lua&amp;#39;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/share/lua/5.1/?/init.lua&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LUA_PATH&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;LUA_PATH
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LUA_PATH&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&amp;#39;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/share/lua/5.1/?.lua&amp;#39;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/share/lua/5.1/?.lua&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LUA_PATH&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_PATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;LUA_PATH
&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LUA_CPATH&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&amp;#39;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/lib/lua/5.1/?.so&amp;#39;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/lib/lua/5.1/?.so&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$LUA_CPATH&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LUA_CPATH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;LUA_CPATH
&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-a&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;/nix/store/1czj8mydgi30kyfimq6q4ifh06q131ch-neovim-unwrapped-0.8.3/bin/nvim&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;-u&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/nix/store/fqjv4r08pl8k3vhy6ijxddrn8gpq2h7z-init.vim&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;--cmd&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;let g:loaded_node_provider=0 | let g:loaded_python_provider=0 | let g:python3_host_prog=&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#39;&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/nix/store/jjl5fy7dc5cxvc7mi781vxbk8ag89ih0-neovim-0.8.3-esbonio/bin/nvim-python3&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#39;&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; | let g:ruby_host_prog=&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#39;&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/nix/store/jjl5fy7dc5cxvc7mi781vxbk8ag89ih0-neovim-0.8.3-esbonio/bin/nvim-ruby&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#39;&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;&lt;p&gt;After some trial and error I was able to put together the following&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystem &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;nvim-cfg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;neovimUtils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;makeNeovimConfig &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;extraName&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;-esbonio&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;customRC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;        set number&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;      &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;neovim-config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;attrsets&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;updateManyAttrsByPath &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;wrapperArgs&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;update&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; old&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; old &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
          &lt;span class=&#34;s2&#34;&gt;&amp;quot;--add-flags&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;--clean&amp;quot;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; nvim-cfg&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;neovim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;wrapNeovimUnstable pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;neovim-unwrapped neovim-config&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    apps&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;program&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;neovim&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/bin/nvim&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To summarize&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pkgs.neovimUtils.makeNeovimConfig&lt;/span&gt;&lt;/code&gt; as the name suggests is a utility that generates a neovim “config”.
“config” in this case is an attribute set containing all the arguments required to call &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pkgs.wrapNeovimUnstable&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One of these arguments is called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wrapperArgs&lt;/span&gt;&lt;/code&gt; which contains the list of cli arguments to pass to the wrapped instance of neovim. Well almost.&lt;/p&gt;
&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wrapperArgs&lt;/span&gt;&lt;/code&gt; aren’t passed through to neovim directly, they are passed to a utility called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;makeWrapper&lt;/span&gt;&lt;/code&gt; which is a small program with it’s own
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh#L13-L35&#34;&gt;set of arguments&lt;/a&gt;
that allow you to describe how you want to wrap an underlying executable.
This is why I’m appending &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;quot;--add-flags&amp;quot;&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;&amp;quot;--clean&amp;quot;&lt;/span&gt;&lt;/code&gt; to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wrapperArgs&lt;/span&gt;&lt;/code&gt; and not just &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--clean&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, the config and base neovim derivation are passed to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pkgs.wrapNeovimUnstable&lt;/span&gt;&lt;/code&gt; to bring it all together.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately, after all that I still didn’t end up with the result I was looking for&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id1&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/nix-nvim-clean.png&#34; src=&#34;https://www.alcarney.me/_images/nix-nvim-clean.png&#34; style=&#34;width: 50%;&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;No plugins, but also note no line numbers 😢&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id1&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Not only does the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--clean&lt;/span&gt;&lt;/code&gt; flag prevent neovim from loading the plugins in my home folder, it also stopped neovim from loading the contents of my &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;customRC&lt;/span&gt;&lt;/code&gt; - something I would’ve found out if I’d actually read the help text for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--clean&lt;/span&gt;&lt;/code&gt; itself&lt;/p&gt;
&lt;blockquote class=&#34;pull-quote&#34;&gt;
&lt;div&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--clean&lt;/span&gt;&lt;/code&gt; - Mimics a fresh install of Nvim:&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Skips initializations from files and environment variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No ‘shada’ file is read or written.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Excludes user directories from ‘runtimepath’&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loads builtin plugins, unlike -u NONE -i NONE.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;It should be possible to work around this though by telling neovim to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;source&lt;/span&gt;&lt;/code&gt; our init file as well as giving it the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--clean&lt;/span&gt;&lt;/code&gt; flag.
Let’s take a look at the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;exec&lt;/span&gt;&lt;/code&gt; command nix is currently generating for us in the wrapper script.&lt;/p&gt;
&lt;div class=&#34;highlight-bash notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-a&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;/nix/store/1czj8mydgi30kyfimq6q4ifh06q131ch-neovim-unwrapped-0.8.3/bin/nvim&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;-u&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/nix/store/fqjv4r08pl8k3vhy6ijxddrn8gpq2h7z-init.vim&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;--cmd&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;--clean&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;-u&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;/nix/store/fqj...-init.vim&lt;/span&gt;&lt;/code&gt; argument contains the contents of our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;customRC&lt;/span&gt;&lt;/code&gt; and I think changing the command to something like&lt;/p&gt;
&lt;div class=&#34;highlight-bash notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-a&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;/nix/store/1czj8mydgi30kyfimq6q4ifh06q131ch-neovim-unwrapped-0.8.3/bin/nvim&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;--clean&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;--cmd&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;source /nix/store/fqjv4r08pl8k3vhy6ijxddrn8gpq2h7z-init.vim&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;will result in the behaviour I’m looking for.&lt;/p&gt;
&lt;div class=&#34;admonition tip&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Tip&lt;/p&gt;
&lt;p&gt;So far I’ve neglected to mention how I’m finding the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/nix/store&lt;/span&gt;&lt;/code&gt; path containing this wrapper script.
Using the nix repl you can load your flake and inspect the values it contains.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;repl
&lt;span class=&#34;go&#34;&gt;Welcome to Nix 2.11.1. Type :? for help.&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;nix-repl&amp;gt; :lf .        # load the flake located at &amp;#39;.&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;warning: Git tree &amp;#39;/var/home/alex/Projects/esbonio-nix&amp;#39; is dirty&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Added 9 variables.&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;nix-repl&amp;gt; outputs.apps.x86_64-linux.default&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;{ program = &amp;quot;/nix/store/knr1nfdmg9ld0xg813hb7ljl68060jlv-neovim-0.8.3-esbonio/bin/nvim&amp;quot;; type = &amp;quot;app&amp;quot;; }&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It’s also useful for figuring out how the many utilities in nixpkgs work&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;go&#34;&gt;nix-repl&amp;gt; pkgs = import inputs.nixpkgs {system = &amp;quot;x86_64-linux&amp;quot;; }&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;nix-repl&amp;gt; config = pkgs.neovimUtils.makeNeovimConfig { customRC = &amp;quot;set number&amp;quot;; }&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;nix-repl&amp;gt; config.wrapperArgs&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;[ &amp;quot;--inherit-argv0&amp;quot; &amp;quot;--add-flags&amp;quot; &amp;quot;&amp;#39;--cmd&amp;#39; &amp;#39;let g:loaded_node_provider=0 | let g:loaded_python_provider=0 | let g:python3_host_prog=&amp;#39;\\&amp;#39;&amp;#39;/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9/bin/nvim-python3&amp;#39;\\&amp;#39;&amp;#39; | let g:ruby_host_prog=&amp;#39;\\&amp;#39;&amp;#39;/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9/bin/nvim-ruby&amp;#39;\\&amp;#39;&amp;#39;&amp;#39;&amp;quot; &amp;quot;--set&amp;quot; &amp;quot;GEM_HOME&amp;quot; &amp;quot;/nix/store/4mmkiw8n1nhlfsnh4g2kijzkxnp6fyxb-neovim-ruby-env/lib/ruby/gems/2.7.0&amp;quot; &amp;quot;--suffix&amp;quot; &amp;quot;PATH&amp;quot; &amp;quot;:&amp;quot; &amp;quot;/nix/store/4mmkiw8n1nhlfsnh4g2kijzkxnp6fyxb-neovim-ruby-env/bin&amp;quot; &amp;quot;--prefix&amp;quot; &amp;quot;LUA_PATH&amp;quot; &amp;quot;;&amp;quot; &amp;quot;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/share/lua/5.1/?.lua;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/share/lua/5.1/?/init.lua&amp;quot; &amp;quot;--prefix&amp;quot; &amp;quot;LUA_CPATH&amp;quot; &amp;quot;;&amp;quot; &amp;quot;/nix/store/nlmk08cmald0zi7fc6hgpdqrjz7lh8qj-luajit-2.1.0-2022-10-04-env/lib/lua/5.1/?.so&amp;quot; ]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&#34;m-0 text-white dark:text-gray-800&#34;&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately, I could not see an obvious way to rewrite the arguments to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;exec&lt;/span&gt;&lt;/code&gt;.
The store path for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;init.vim&lt;/span&gt;&lt;/code&gt; file is only generated in the depths of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wrapNeovimUnstable&lt;/span&gt;&lt;/code&gt; as it is written to disk and trying to manipulate &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wrapperArgs&lt;/span&gt;&lt;/code&gt; to extract it isn’t something I’m willing to attempt in Nix just yet!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;a-new-approach&#34;&gt;
&lt;h3&gt;A New Approach&lt;a class=&#34;headerlink&#34; href=&#34;#a-new-approach&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It was at this point I started looking around to see what other people have come up with and before long I found
&lt;a class=&#34;reference external&#34; href=&#34;https://www.reddit.com/r/neovim/comments/v45zkv/any_solution_for_isolated_neovimvim_environments/&#34;&gt;this reddit thread&lt;/a&gt;
which linked
&lt;a class=&#34;reference external&#34; href=&#34;https://git.sr.ht/~whynothugo/dotfiles/tree/e7c0e701/item/v/flake.nix&#34;&gt;this flake&lt;/a&gt;
that looked very promising.
Not only did it provide a way of creating an isolated config but it also showed how to manage plugins and external binaries!&lt;/p&gt;
&lt;p&gt;Following its example I was able to come up with the following definition&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystem &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;initVim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;      set number&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;    &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;paths&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;makeBinPath &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;neovim
    &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;pluginList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;vimPlugins&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      nvim-lspconfig
    &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;plugins&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;stdenv&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mkDerivation &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;esbonio-nvim-plugins&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;buildCommand&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;        mkdir -p $out/nvim/site/pack/plugins/start/&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;concatMapStringsSep &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;path&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;ln -s &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;path&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; $out/nvim/site/pack/plugins/start/&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  pluginList &lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;      &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;neovim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;writeShellScriptBin &lt;span class=&#34;s2&#34;&gt;&amp;quot;nvim&amp;quot;&lt;/span&gt; &lt;span class=&#34;s s-Multiline&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;      export PATH=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;paths&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt;:$PATH&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;      export XDG_CONFIG_DIRS=&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;      export XDG_DATA_DIRS=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;plugins&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;outPath&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;      nvim --clean --cmd source &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;writeText &lt;span class=&#34;s2&#34;&gt;&amp;quot;init.vim&amp;quot;&lt;/span&gt; initVim&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s s-Multiline&#34;&gt; &amp;quot;$@&amp;quot;&lt;/span&gt;
&lt;span class=&#34;s s-Multiline&#34;&gt;    &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
     apps&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;program&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;neovim&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/bin/nvim&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And trying &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;.&lt;/span&gt;&lt;/code&gt; once more&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id2&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/nix-nvim-isolated.png&#34; src=&#34;https://www.alcarney.me/_images/nix-nvim-isolated.png&#34; style=&#34;width: 50%;&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;Success!&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id2&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Not only did I end up with the correct configuration, the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;runtimepath&lt;/span&gt;&lt;/code&gt; finally contains just the paths that are necessary!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;integrating-esboino&#34;&gt;
&lt;h2&gt;Integrating Esboino&lt;a class=&#34;headerlink&#34; href=&#34;#integrating-esboino&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next we need to make sure the esbonio language server is available in this environment and include the necessary configuration for it in the config.&lt;/p&gt;
&lt;p&gt;Including the server should be pretty straightforward as we get to reuse the overlay defined &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2023/nix-overlays-p2/&#34; title=&#34;Nix Overlays: A follow up&#34;&gt;previously&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight-diff notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt; inputs = {
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;   nixpkgs.url = &amp;quot;github:NixOS/nixpkgs/nixpkgs-unstable&amp;quot;;
&lt;span class=&#34;gi&#34;&gt;+   esbonio.url = &amp;quot;path:lib/esbonio&amp;quot;;&lt;/span&gt;
&lt;span class=&#34;gi&#34;&gt;+   esbonio.inputs.nixpkgs.follows = &amp;quot;nixpkgs&amp;quot;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;   utils.url = &amp;quot;github:numtide/flake-utils&amp;quot;;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt; };

&lt;span class=&#34;gd&#34;&gt;- outputs = { self, nixpkgs, utils }:&lt;/span&gt;
&lt;span class=&#34;gi&#34;&gt;+ outputs = { self, nixpkgs, esbonio, utils }:&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;utils.lib.eachDefaultSystem (system:
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;  let
&lt;span class=&#34;gd&#34;&gt;-    pkgs = import nixpkgs { inherit system ; };&lt;/span&gt;
&lt;span class=&#34;gi&#34;&gt;+    pkgs = import nixpkgs { inherit system ; overlays = [ esbonio.overlays.default ];};&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;    initVim = &amp;#39;&amp;#39;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;      set number
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;    &amp;#39;&amp;#39;;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;    paths = pkgs.lib.makeBinPath [
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;      pkgs.neovim
&lt;span class=&#34;gi&#34;&gt;+      pkgs.python310Packages.esbonio&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;    ];
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Should&lt;/strong&gt; being the key word here…&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;run&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.
&lt;span class=&#34;go&#34;&gt;warning: Git tree &amp;#39;/var/home/alex/Projects/esbonio-nix&amp;#39; is dirty&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;warning: updating lock file &amp;#39;/var/home/alex/Projects/esbonio-nix/flake.lock&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;• Added input &amp;#39;esbonio&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    &amp;#39;path:lib/esbonio?lastModified=1&amp;amp;narHash=sha256-WiFypw4lUZo7P9h82NMudwb5DFV0Nde5cOu1SqDmhVQ=&amp;#39; (1970-01-01)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;• Added input &amp;#39;esbonio/nixpkgs&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    follows &amp;#39;nixpkgs&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;• Added input &amp;#39;esbonio/pytest-lsp&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    &amp;#39;github:swyddfa/lsp-devtools/6ae80a24b55d2b6943b9d30805cf02440ebbaf5c?dir=lib%2fpytest-lsp&amp;#39; (2023-04-02)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;• Added input &amp;#39;esbonio/pytest-lsp/nixpkgs&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    follows &amp;#39;esbonio/nixpkgs&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;• Added input &amp;#39;esbonio/pytest-lsp/utils&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    &amp;#39;github:numtide/flake-utils/93a2b84fc4b70d9e089d029deacc3583435c2ed6&amp;#39; (2023-03-15)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;• Added input &amp;#39;esbonio/utils&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    &amp;#39;github:numtide/flake-utils/5aed5285a952e0b949eb3ba02c12fa4fcfef535f&amp;#39; (2022-11-02)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;warning: Git tree &amp;#39;/var/home/alex/Projects/esbonio-nix&amp;#39; is dirty&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;error: undefined variable &amp;#39;pytest-lsp&amp;#39;&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;       at /nix/store/96z740kkay7j0cbgmccj2mzbn5z8agvp-source/nix/esbonio-overlay.nix:22:11:&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;           21|           mock&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;           22|           pytest-lsp&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;             |           ^&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;           23|           pytest-timeout&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(use &amp;#39;--show-trace&amp;#39; to show detailed location information)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The overlay exported by the language server’s flake doesn’t include its dependency &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; which is provided through an overlay of its own.
A quick “fix” would be to also pull in the flake for pytest-lsp, but really the language server’s flake should be exporting all of its dependencies.&lt;/p&gt;
&lt;section id=&#34;composing-overlays&#34;&gt;
&lt;h3&gt;Composing Overlays&lt;a class=&#34;headerlink&#34; href=&#34;#composing-overlays&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Thankfully, nixpkgs provides a function
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/3eb57ca9451406a7131f54b8a90b82462ad89252/lib/fixed-points.nix#L86&#34;&gt;composeManyExtensions&lt;/a&gt;
that handles this for us.
When exporting the overlay from within the language server’s flake we can use it to merge the overlay from pytest-lsp with the overlay containing esbonio.&lt;/p&gt;
&lt;div class=&#34;highlight-default notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In lib/esbonio/flake.nix&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;overlays&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;super&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nixpkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;composeManyExtensions&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;pytest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lsp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;overlay&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;esbonio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;overlay&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;super&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, since &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.lock&lt;/span&gt;&lt;/code&gt; freezes the language server’s flake as it was before we made this change we need to also update the lock file before trying again&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;flake&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;lock&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--update-input&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;esbonio
&lt;span class=&#34;go&#34;&gt;warning: Git tree &amp;#39;/var/home/alex/Projects/esbonio-nix&amp;#39; is dirty&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;warning: updating lock file &amp;#39;/var/home/alex/Projects/esbonio-nix/flake.lock&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;• Updated input &amp;#39;esbonio&amp;#39;:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    &amp;#39;path:lib/esbonio?lastModified=1&amp;amp;narHash=sha256-WiFypw4lUZo7P9h82NMudwb5DFV0Nde5cOu1SqDmhVQ=&amp;#39; (1970-01-01)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  → &amp;#39;path:lib/esbonio?lastModified=1&amp;amp;narHash=sha256-QgSDxOPSrtsaqjeStalef07+bUE3qkzz7pJC4y43ltw=&amp;#39; (1970-01-01)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;warning: Git tree &amp;#39;/var/home/alex/Projects/esbonio-nix&amp;#39; is dirty&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now trying &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;.&lt;/span&gt;&lt;/code&gt; again neovim launches as before, running the command &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;:r&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;!python&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;-m&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;--help&lt;/span&gt;&lt;/code&gt; we can verify that the language server is indeed available to the editor.&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id3&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/nix-nvim-esbonio-help.png&#34; src=&#34;https://www.alcarney.me/_images/nix-nvim-esbonio-help.png&#34; style=&#34;width: 50%;&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;Almost there!&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id3&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&#34;admonition-editor-s-note admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Editor’s Note&lt;/p&gt;
&lt;p&gt;Since writing this section and taking the above screenshot, I have been unable to re-produce it!
Now &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;:r&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;!python&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;-m&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;--help&lt;/span&gt;&lt;/code&gt; results in a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio:&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;Module&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;found&lt;/span&gt;&lt;/code&gt; error…&lt;/p&gt;
&lt;p&gt;When debugging this, I’m not sure how the original ever worked since the flake definition does not include
a Python interpreter meaning that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;-m&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;--help&lt;/span&gt;&lt;/code&gt; is running under the system Python.&lt;/p&gt;
&lt;p&gt;The fix then, was to switch from &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;-m&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;--help&lt;/span&gt;&lt;/code&gt; to calling &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;--help&lt;/span&gt;&lt;/code&gt; directly, which thankfully, did not require me to change any of the Nix code.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;configuring-neovim&#34;&gt;
&lt;h3&gt;Configuring Neovim&lt;a class=&#34;headerlink&#34; href=&#34;#configuring-neovim&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now all that’s left to do is updating our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;initVim&lt;/span&gt;&lt;/code&gt; variable to contain the relevant configuration for the language server.
Thanks to the
&lt;a class=&#34;reference external&#34; href=&#34;https://swyddfa.github.io/esbonio/docs/latest/en/lsp/getting-started.html?editor=neovim-lspconfig#examples&#34;&gt;example configuration&lt;/a&gt;
available in the documentation, this can be as straightforward as replacing our hardcoded configuration with a call to Nix (the language’s) builtin
&lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/manual/nix/stable/language/builtins.html#builtins-readFile&#34;&gt;readFile&lt;/a&gt;
function.&lt;/p&gt;
&lt;div class=&#34;highlight-diff notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;utils.lib.eachDefaultSystem (system:
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;  let
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;    pkgs = import nixpkgs { inherit system ; overlays = [ esbonio.overlays.default ];};
&lt;span class=&#34;gd&#34;&gt;-    initVim = &amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&#34;gd&#34;&gt;-      set number&lt;/span&gt;
&lt;span class=&#34;gd&#34;&gt;-    &amp;#39;&amp;#39;;&lt;/span&gt;
&lt;span class=&#34;gi&#34;&gt;+    initVim = builtins.readFile ./docs/lsp/editors/nvim-lspconfig/init.vim;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;    paths = pkgs.lib.makeBinPath [
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;      pkgs.neovim
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;      pkgs.python310Packages.esbonio
&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;    ];
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And try opening a Sphinx project with it&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id4&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/nix-nvim-esbonio-minimal.png&#34; src=&#34;https://www.alcarney.me/_images/nix-nvim-esbonio-minimal.png&#34; style=&#34;width: 50%;&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;It’s not pretty, but it works!&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id4&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;wrapping-up&#34;&gt;
&lt;h2&gt;Wrapping Up&lt;a class=&#34;headerlink&#34; href=&#34;#wrapping-up&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The experience as is currently stands is not that inspiring however, with the nix foundations laid it’s now more of a configuring neovim problem rather than a nix one!
I am mildly disappointed that this required to dive so deep on the specifics of how neovim is configured, since that probably means you’d have to go to a similar depth to incorporate other editors.
That said, once you’ve solved it for a given editor it’s probably solved “forever”.&lt;/p&gt;
&lt;p&gt;Next I think I’d be interested in exploring how (or if it’s even possible) to make these Nix definitions more dynamic e.g.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Using the language server from &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;$EDITOR&lt;/span&gt;&lt;/code&gt; using Python &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;3.x&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the language server tests, but with a local checkout of &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls&#34;&gt;pygls&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Edit docs for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;$PROJECT&lt;/span&gt;&lt;/code&gt; using Sphinx &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;vX&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Obviously, you could achieve a lot of that by just editing the Nix definitions and rebuilding but I wonder if it’s possible to build in support for swapping parts out that can be wrapped up in a Makefile or similar 🤔&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2023/nix-overlays-p2/</id>
    <link href="https://www.alcarney.me/blog/2023/nix-overlays-p2" rel="alternate" />
    <published>2023-04-02T00:00:00+00:00</published>
    <updated>2023-04-02T00:00:00+00:00</updated>
    <title>Nix Overlays: A follow up</title>
    <content type="html">
      &lt;section id=&#34;nix-overlays-a-follow-up&#34;&gt;
&lt;h1&gt;Nix Overlays: A follow up&lt;a class=&#34;headerlink&#34; href=&#34;#nix-overlays-a-follow-up&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;It turns out there were a few issues with the setup I put together in my &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2023/nix-overlays/&#34; title=&#34;My Next Steps with Nix: Overlays&#34;&gt;previous post&lt;/a&gt;.
This time I try and resolve them and get to the point where I have working overlays for both
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/lsp-devtools/tree/develop/lib/pytest-lsp&#34;&gt;pytest-lsp&lt;/a&gt;
and
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio&#34;&gt;esbonio&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;dependency-is-not-of-valid-type&#34;&gt;
&lt;h2&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Dependency&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;valid&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;type&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#dependency-is-not-of-valid-type&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At the end of the previous post, I was left scratching my head after encountering a cryptic error message&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: Dependency is not of a valid type: element 4 of nativeBuildInputs for py310&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(use &amp;#39;--show-trace&amp;#39; to show detailed location information)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which was coming from the following &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;The Esbonio language server&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;inputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    nixpkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:NixOS/nixpkgs/nixpkgs-unstable&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;    pytest-lsp&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:swyddfa/lsp-devtools?dir=lib/pytest-lsp&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;    utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:numtide/flake-utils&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;hll&#34;&gt;  &lt;span class=&#34;ss&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; pytest-lsp&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; utils &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;
&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;esbonio-overlay&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./nix/esbonio-overlay.nix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;listToAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; f version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

    overlays&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; esbonio-overlay&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

    &lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
          &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
          &lt;span class=&#34;ss&#34;&gt;overlays&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; pytest-lsp&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overlays&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest-lsp esbonio-overlay &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
        eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
          &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
            &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
              esbonio
              mock
              pytest
&lt;span class=&#34;hll&#34;&gt;              pytest-lsp
&lt;/span&gt;              pytest-timeout
            &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Originally, I thought this was caused by naming conflicts introduced by using &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; to reference both &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; the flake, and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; the Python package.
Indeed, changing the name of the flake input to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytestlsp&lt;/span&gt;&lt;/code&gt; seemed to at least change the error message I was seeing…&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: undefined variable &amp;#39;pytest-lsp&amp;#39;&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;       at /nix/store/dihmz79kgwxj1v5mqvxrj0f3ifgvpm9f-source/lib/esbonio/flake.nix:38:15:&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;           37|               pytest&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;           38|               pytest-lsp&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;             |               ^&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;           39|               pytest-timeout&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(use &amp;#39;--show-trace&amp;#39; to show detailed location information)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;How can that be?!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;conflicting-overlays&#34;&gt;
&lt;h2&gt;Conflicting Overlays&lt;a class=&#34;headerlink&#34; href=&#34;#conflicting-overlays&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It turns out that the overlays &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytestlsp.overlays.pytest-lsp&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio-overlay&lt;/span&gt;&lt;/code&gt; conflict with each other!
I am not sure what originally led me to try it, but by reversing their order in the array passed to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nixpkgs&lt;/span&gt;&lt;/code&gt; I could produce a similar error for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; package.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: undefined variable &amp;#39;esbonio&amp;#39;&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;       at /nix/store/vqff8bn03r11m1fg4f0b7ixnj731g9br-source/lib/esbonio/flake.nix:34:15:&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;           33|             packages = with pkgs.&amp;quot;python${pyVersion}Packages&amp;quot;; [&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;           34|               esbonio&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;             |               ^&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;           35|&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(use &amp;#39;--show-trace&amp;#39; to show detailed location information)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;But why? 🤔
I thought the whole point of overlays were so that they could be… well, overlayed on an underlying package set without conflicting with each other??&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;use-the-source-luke&#34;&gt;
&lt;h2&gt;Use the Source Luke&lt;a class=&#34;headerlink&#34; href=&#34;#use-the-source-luke&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To find the answer, I had to remind myself that Nix is &lt;strong&gt;not&lt;/strong&gt; magic (although it can appear to be!) and instead, at it’s core, Nix is a programming language.
Which means this concept of “overlays” must be implemented in code &lt;em&gt;somewhere&lt;/em&gt; and we can look for ourselves to see how they are handled.
Sure enough, after some splunking through the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nixpkgs&lt;/span&gt;&lt;/code&gt; repo I was able to track down
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/commit/f5dfe78a1eb5ff8dfcc7ab37cfc132c5f31d3cef&#34;&gt;the commit&lt;/a&gt;
introducing the concept.&lt;/p&gt;
&lt;p&gt;The majority of that commit appears to be just passing the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;overlays&lt;/span&gt;&lt;/code&gt; array through to all the places that require it and updating the documentation.
The interesting part is where the overlays are actually applied at the bottom of
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/f5dfe78a1eb5ff8dfcc7ab37cfc132c5f31d3cef/pkgs/top-level/stage.nix#L84-L96&#34;&gt;pkgs/top-level/stage.nix&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;# The complete chain of package set builders, applied from top to bottom&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;toFix&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;foldl&amp;#39; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;flip lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;extends&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{})&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;
    stdenvBootstappingAndPlatforms
    stdenvAdapters
    trivialBuilders
    allPackages
    aliases
    stdenvOverrides
    configOverrides
    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; overlays&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;# Return the complete set of packages.&lt;/span&gt;
  lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;fix toFix
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;From what I understand&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/f5dfe78a1eb5ff8dfcc7ab37cfc132c5f31d3cef/lib/lists.nix#L61&#34;&gt;lib.foldl’&lt;/a&gt;
applies some combination function - &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;(lib.flip&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;lib.extends)&lt;/span&gt;&lt;/code&gt; in this case, to a list resulting in a single aggregated value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/f5dfe78a1eb5ff8dfcc7ab37cfc132c5f31d3cef/lib/trivial.nix#L82&#34;&gt;lib.flip&lt;/a&gt;
switches the order of the arguments given to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;lib.extends&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/f5dfe78a1eb5ff8dfcc7ab37cfc132c5f31d3cef/lib/trivial.nix#L54&#34;&gt;lib.extends&lt;/a&gt;
is the function we’re actually interested in as it is responsible for applying the overlays.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/f5dfe78a1eb5ff8dfcc7ab37cfc132c5f31d3cef/lib/trivial.nix#L29&#34;&gt;lib.fix&lt;/a&gt;
appears to resolve all references to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;self&lt;/span&gt;&lt;/code&gt; in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;toFix&lt;/span&gt;&lt;/code&gt; to a “proper” value, but I’m not entirely sure how.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is the implementation of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;lib.extends&lt;/span&gt;&lt;/code&gt; as of the commit introducing overlays&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; rattrs&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;super&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; rattrs self&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; super &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; f self super&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As with most things in Nix, I don’t really understand the fine details but it’s interesting to see that it uses the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;//&lt;/span&gt;&lt;/code&gt; operator to merge the result of an overlay (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;f&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;self&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;super&lt;/span&gt;&lt;/code&gt;) with the current state of the package set (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;super&lt;/span&gt;&lt;/code&gt;).
One thing that’s interesting to note, when combining attribute sets with the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;//&lt;/span&gt;&lt;/code&gt; operator, if both sets contain the same key, then the value from the original set is replaced with the value provided by the second.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;repl
&lt;span class=&#34;go&#34;&gt;Welcome to Nix 2.11.1. Type :? for help.&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;nix-repl&amp;gt; x = {a = 1 ; b = 2; c = 3;}&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;nix-repl&amp;gt; y = {d = 4; c = 5;}&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;nix-repl&amp;gt; x // y&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;{ a = 1; b = 2; c = 5; d = 4; }&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Foreshadowing…&lt;/em&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;the-problem&#34;&gt;
&lt;h2&gt;The Problem&lt;a class=&#34;headerlink&#34; href=&#34;#the-problem&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Armed with my new found knowledge I had another look at the definitions of the problematic overlays.&lt;/p&gt;
&lt;div class=&#34;flex flex-col md-flex-row justify-between gap-4 docutils container&#34;&gt;
&lt;div class=&#34;overflow-x-auto highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# pytest-lsp-overlay.nix&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;

self&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; super&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;

eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;  super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;override &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&#34;ss&#34;&gt;packageOverrides&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pyself&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; pysuper&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;pytest-lsp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;buildPythonPackage &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;overflow-x-auto highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# esbonio-overlay.nix&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;

self&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; super&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;

eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;  super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;override &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&#34;ss&#34;&gt;packageOverrides&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pyself&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; pysuper&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;buildPythonPackage &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Well no wonder they conflict with each other, they’re overriding the base &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pythonXY&lt;/span&gt;&lt;/code&gt; package directly!
Any &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;packageOverrides&lt;/span&gt;&lt;/code&gt; provided by the first overlay would be wiped out when the second is applied.
Surely then there must be a better way to provide your own Python package definitions 🤔&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;the-solution&#34;&gt;
&lt;h2&gt;The Solution&lt;a class=&#34;headerlink&#34; href=&#34;#the-solution&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Somewhat buried on the &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/manual/nixpkgs/stable/#python&#34;&gt;Python page&lt;/a&gt; in the Nixpkgs manual is this handy FAQ question&lt;/p&gt;
&lt;blockquote class=&#34;pull-quote&#34;&gt;
&lt;div&gt;&lt;p&gt;17.27.3.9. How to override a Python package for all Python versions using extensions?&lt;/p&gt;
&lt;p&gt;The following overlay overrides the call to buildPythonPackage for the foo package for all interpreters by appending a Python extension to the pythonPackagesExtensions list of extensions.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;final&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; prev&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pythonPackagesExtensions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; prev&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pythonPackagesExtensions &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
       python-final&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; python-prev&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python-prev&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;foo&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overridePythonAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;oldAttrs&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
       &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;This might be just what we need!
Not only do we avoid messing with the base Python package, we also get our packages automatically added to each Python version without the need to roll our own &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachPythonVerison&lt;/span&gt;&lt;/code&gt; helper!&lt;/p&gt;
&lt;p&gt;Converting my &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2023/nix-overlays/#nix-overlays-sharing&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;previous overlay attempts&lt;/span&gt;&lt;/a&gt; to the above approach results in overlay definitions that are a lot more straight forward.
Notice that I was even able to enable tests for them now!&lt;/p&gt;
&lt;div class=&#34;flex flex-col md-flex-row justify-between gap-4 docutils container&#34;&gt;
&lt;div class=&#34;overflow-x-auto highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# pytest-lsp-overlay.nix&lt;/span&gt;
final&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; prev&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pythonPackagesExtensions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; prev&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pythonPackagesExtensions &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;
    python-final&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; python-prev&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;pytest-lsp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python-prev&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;buildPythonPackage &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;pname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;pytest-lsp&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;0.2.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./..&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;propagatedBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; python-prev&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
          pygls
          pytest
          pytest-asyncio
        &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;doCheck&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;nativeCheckInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; python-prev&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
          pytestCheckHook
        &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;pythonImportsCheck&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;pytest_lsp&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;)];&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;overflow-x-auto highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# esbonio-overlay.nix&lt;/span&gt;
final&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; prev&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pythonPackagesExtensions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; prev&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pythonPackagesExtensions &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;
    python-final&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; python-prev&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python-prev&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;buildPythonPackage &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;pname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;esbonio&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;0.16.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./..&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;propagatedBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; python-prev&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
          appdirs
          pygls
          pyspellchecker
          sphinx
          &lt;span class=&#34;c1&#34;&gt;# typing-extensions; only required for Python 3.7&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;doCheck&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;nativeCheckInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; python-prev&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
          mock
          pytest-lsp
          pytest-timeout
          pytestCheckHook
        &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;pythonImportsCheck&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;esbonio.lsp&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;)];&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;All that is left to do is to try and enter the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; for esbonio again&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: builder for &amp;#39;/nix/store/027wakjv9wvws6190c66nf5gxc6smc54-python3.10-esbonio-0.16.1.drv&amp;#39; failed with exit code 2;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       last 10 log lines:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; /nix/store/l69b9xl4pnqqgdx9vp1yg1cbckgcjsfx-python3.10-pytest-7.2.0/lib/python3.10/site-packages/_pytest/assertion/rewrite.py:168: in exec_module&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt;     exec(co, module.__dict__)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; tests/sphinx-default/conftest.py:53: in &amp;lt;module&amp;gt;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt;     ClientServerConfig(&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; E   TypeError: ClientServerConfig.__init__() got an unexpected keyword argument &amp;#39;client&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; =========================== short test summary info ============================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; ERROR  - TypeError: ClientServerConfig.__init__() got an unexpected keyword argument...&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; !!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; =============================== 1 error in 0.60s ===============================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; /nix/store/3yfs41f4b60jya2gk6xikx4s97zsxjr0-stdenv-linux/setup: line 1573: pop_var_context: head of shell_variables not a function context&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;For full logs, run &amp;#39;nix log /nix/store/027wakjv9wvws6190c66nf5gxc6smc54-python3.10-esbonio-0.16.1.drv&amp;#39;.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;error: 1 dependencies of derivation &amp;#39;/nix/store/nms3hs5pz1fmyki4k547gfs1281klgl3-py310-env.drv&amp;#39; failed to build&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Hey! At least the Nix part is finally working!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;disabling-tests&#34;&gt;
&lt;span id=&#34;nix-overlays-disable-tests&#34;&gt;&lt;/span&gt;&lt;h2&gt;Disabling Tests&lt;a class=&#34;headerlink&#34; href=&#34;#disabling-tests&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s one final detail left to clear up.&lt;/p&gt;
&lt;p&gt;Of course, if you are consuming a package (like how &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; is pulling in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt;) it’s good to have the tests run so that you can verify everything is working as expected.
However, when you are setting up a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; to work on a package, you don’t really want the tests to run since they will prevent you entering the shell if they fail - as is the case here.&lt;/p&gt;
&lt;p&gt;Thankfully, it should just be a case of setting the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;doCheck&lt;/span&gt;&lt;/code&gt; flag for esbonio to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;false&lt;/span&gt;&lt;/code&gt; when using it within the flake’s &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; definition.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;overlays&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; pytest-lsp-overlay esbonio-overlay &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
    eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
      pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

        &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
          esbonio&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overridePythonAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;_&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;doCheck&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;

          mock
          &lt;span class=&#34;c1&#34;&gt;# Still necessary to avoid a naming conflict with pytest-lsp, the flake&lt;/span&gt;
          pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest-lsp
          pytest-timeout
        &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And activating the shell as normal.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: Dependency is not of a valid type: element 1 of nativeBuildInputs for py310&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(use &amp;#39;--show-trace&amp;#39; to show detailed location information)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;No! Not again! 😭&lt;/p&gt;
&lt;p&gt;To be honest, I nearly gave up on the whole idea then and there but in a last ditch attempt I moved the overriden &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; package out into a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;let&lt;/span&gt;&lt;/code&gt; binding.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
     &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
       &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;overlays&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; pytest-lsp-overlay esbonio-overlay &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
     eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;

       &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;         &lt;span class=&#34;ss&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;esbonio&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overridePythonAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;_&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;doCheck&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;       &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;

       pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

         &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
           esbonio

           mock
           pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest-lsp
           pytest-timeout
         &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
       &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
 &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And tried again&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-L&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# -L = enable verbose logging, useful to actually see what the builds are doing.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Sourcing python-remove-tests-dir-hook&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Sourcing python-catch-conflicts-hook.sh&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Sourcing python-remove-bin-bytecode-hook.sh&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Sourcing setuptools-build-hook&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Using setuptoolsBuildPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Using setuptoolsShellHook&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Sourcing pip-install-hook&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Using pipInstallPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; patching script interpreter paths in /nix/store/a9xjjxv1zh3dmhfaxgph8kq0zaxl92g3-python3.10-esbonio-0.16.1-dist&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Rewriting #!/nix/store/sp5x6s8n36gjlwck74xhj1i61p66vcpa-python3-3.10.9/bin/python3.10 to #!/nix/store/sp5x6s8n36gjlwck74xhj1i61p66vcpa-python3-3.10.9&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; wrapping `/nix/store/91b7mh7ib0fxwn2kgv47v0sdpl05xqh1-python3.10-esbonio-0.16.1/bin/esbonio&amp;#39;...&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Rewriting #!/nix/store/sp5x6s8n36gjlwck74xhj1i61p66vcpa-python3-3.10.9/bin/python3.10 to #!/nix/store/sp5x6s8n36gjlwck74xhj1i61p66vcpa-python3-3.10.9&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; wrapping `/nix/store/91b7mh7ib0fxwn2kgv47v0sdpl05xqh1-python3.10-esbonio-0.16.1/bin/esbonio-sphinx&amp;#39;...&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Executing pythonRemoveTestsDir&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Finished executing pythonRemoveTestsDir&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; pythonCatchConflictsPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; pythonRemoveBinBytecodePhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; pythonImportsCheckPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Executing pythonImportsCheckPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;python3.10-esbonio&amp;gt; Check whether the following modules can be imported: esbonio.lsp&lt;/span&gt;

&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(nix-shell)&lt;/span&gt; &lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And it actually worked! 🤯&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;conclusion&#34;&gt;
&lt;h2&gt;Conclusion&lt;a class=&#34;headerlink&#34; href=&#34;#conclusion&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have no idea why Nix needed me to move the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;overridePythonAttrs&lt;/span&gt;&lt;/code&gt; call out into a separate &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;let&lt;/span&gt;&lt;/code&gt; binding, but hey it works!&lt;/p&gt;
&lt;p&gt;I’ve finally managed to recreate the setup I had in my &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2022/first-steps-with-nix/&#34; title=&#34;My First Steps with Nix&#34;&gt;original&lt;/a&gt; blog post, spinning up &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShells&lt;/span&gt;&lt;/code&gt; in order to test &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; against a range of Python versions - just with the added flexibility that working with overlays can bring.&lt;/p&gt;
&lt;p&gt;If you’re interested you can find the final version of all my &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;*.nix&lt;/span&gt;&lt;/code&gt; files
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/lsp-devtools/commit/6ae80a24b55d2b6943b9d30805cf02440ebbaf5c&#34;&gt;here (pytest-lsp)&lt;/a&gt;
and
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/esbonio/commit/6830a5fd0fe4c4f197d591d35d189a17fc561146&#34;&gt;here (esbonio)&lt;/a&gt;.
Hopefully next time we can build on this and finally use Nix for something you can’t get out of standard Python tooling! 😅&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2023/nix-overlays/</id>
    <link href="https://www.alcarney.me/blog/2023/nix-overlays" rel="alternate" />
    <published>2023-01-25T00:00:00+00:00</published>
    <updated>2023-01-25T00:00:00+00:00</updated>
    <title>My Next Steps with Nix: Overlays</title>
    <content type="html">
      &lt;section id=&#34;my-next-steps-with-nix-overlays&#34;&gt;
&lt;h1&gt;My Next Steps with Nix: Overlays&lt;a class=&#34;headerlink&#34; href=&#34;#my-next-steps-with-nix-overlays&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2022/first-steps-with-nix/&#34; title=&#34;My First Steps with Nix&#34;&gt;Last time&lt;/a&gt;, I experimented with writing a flake that defined development environments for the &lt;a class=&#34;extlink-pypi reference external&#34; href=&#34;https://pypi.org/project/esbonio&#34;&gt;esbonio&lt;/a&gt; package spanning multiple Python versions.
During that process I also packaged &lt;a class=&#34;extlink-pypi reference external&#34; href=&#34;https://pypi.org/project/pytest-lsp&#34;&gt;pytest-lsp&lt;/a&gt; using an ad-hoc nix expression as part of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; repo.&lt;/p&gt;
&lt;p&gt;In this post I look into writing a similar flake for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; package itself, but this time using overlays to override and extend the nixpkgs package set.&lt;/p&gt;
&lt;p&gt;If you are interested, you can find the final version of the code
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/lsp-devtools/commit/a7b8d545364cc14c1cd054fd56831d0bd3517659&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;packaging-pytest-lsp&#34;&gt;
&lt;h2&gt;Packaging &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#packaging-pytest-lsp&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adapting the
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/esbonio/commit/f62e1d486bb7899d802bfd668f98f21b71702317#diff-12d8883e85761c056008578af1202737eabc12dbdb4cee164b96cdb77a8be96b&#34;&gt;flake.nix&lt;/a&gt;
file and using the
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/esbonio/commit/f62e1d486bb7899d802bfd668f98f21b71702317#diff-592a771a0632b893c90066d07d7b260e4847eff70e8b47e9dcd0806014dcfc6d&#34;&gt;package definition&lt;/a&gt;
from the previous post, it’s easy enough to sketch out a flake that should give us a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; to work on the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;However, trying to activate one we encounter a problem.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-c&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: builder for &amp;#39;/nix/store/dfd5bixdgkvfcnfa7f9z0ibp4m5zlhkz-python3.10-pytest-lsp-0.2.1.drv&amp;#39; failed with exit code 1;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       last 10 log lines:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; installing&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Executing pipInstallPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; /build/pytest-lsp/dist /build/pytest-lsp&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Processing ./pytest_lsp-0.2.1-py3-none-any.whl&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Requirement already satisfied: appdirs in /nix/store/yidjmqc5q1j0fz2dk79qgk1fy7dqcliy-python3.10-appdirs-1.4.4/lib/python3.10/site-packages (from pytest-lsp==0.2.1) (1.4.4)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Requirement already satisfied: pytest-asyncio in /nix/store/dvz12bivdc0dkn6849zm58754ga06hs6-python3.10-pytest-asyncio-0.20.3/lib/python3.10/site-packages (from pytest-lsp==0.2.1) (0.20.3)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Requirement already satisfied: pytest in /nix/store/z5pkmmsdg3bmb35pmsv4rjca1qi7dbnf-python3.10-pytest-7.2.0/lib/python3.10/site-packages (from pytest-lsp==0.2.1) (7.2.0)&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt; ERROR: Could not find a version that satisfies the requirement pygls&amp;gt;=1.0.0 (from pytest-lsp) (from versions: none)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;hll&#34;&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt; ERROR: No matching distribution found for pygls&amp;gt;=1.0.0&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       For full logs, run &amp;#39;nix log /nix/store/dfd5bixdgkvfcnfa7f9z0ibp4m5zlhkz-python3.10-pytest-lsp-0.2.1.drv&amp;#39;.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;error: 1 dependencies of derivation &amp;#39;/nix/store/kfzlz750xdk71fxwvsgpdbw1w00jbvf9-py310-env.drv&amp;#39; failed to build&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In the time between writing the previous blog post and this one, the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; package has been migrated to the latest version of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pygls&lt;/span&gt;&lt;/code&gt;.
The version available through nixpkgs however, is still the previous release.&lt;/p&gt;
&lt;p&gt;While there is an open &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/pull/204457&#34;&gt;pull request&lt;/a&gt; updating &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pygls&lt;/span&gt;&lt;/code&gt; to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;1.0&lt;/span&gt;&lt;/code&gt;, at the time of writing it’s blocked on downstream packages which haven’t migrated yet.&lt;/p&gt;
&lt;p&gt;That said, we don’t have to wait for nixpkgs but can instead use an overlay to update it just for this project.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;overriding-pygls-version&#34;&gt;
&lt;h2&gt;Overriding pygls’ version&lt;a class=&#34;headerlink&#34; href=&#34;#overriding-pygls-version&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Overlays can be used to override sections of an existing package definition.&lt;/p&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;As I mentioned in the previous post, I’m probably not the best person to learn Nix from.
Instead, here are some resources you might useful which go into more detail.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;The NixOS &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.wiki/wiki/Overlays&#34;&gt;wiki page&lt;/a&gt; on Overlays&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nix Pills: &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/guides/nix-pills/override-design-pattern.html&#34;&gt;Chapter 14. Override design pattern&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;As far as I understand it:&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Overlays are a useful design pattern, rather than a fundamental concept of the Nix language.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They are “just” a nix function that have access to both the modified version (usually called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;self&lt;/span&gt;&lt;/code&gt; or &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;final&lt;/span&gt;&lt;/code&gt;) of the “thing” they’re modifying, as well as the unmodified version of it (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;super&lt;/span&gt;&lt;/code&gt; or &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;prev&lt;/span&gt;&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;These functions make use of attributes like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;override&lt;/span&gt;&lt;/code&gt; or &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;overrideAttrs&lt;/span&gt;&lt;/code&gt; to make their modifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I have no idea how to make something overridable 😅&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After reading through the &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.wiki/wiki/Overlays&#34;&gt;wiki page&lt;/a&gt; on overlays a few times, particuarly the sections on overriding a version and python package overlays, I was able to put together an overlay which looked like it should work.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# In ./nix/pygls-overlay.nix&lt;/span&gt;
 self&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; super&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

   &lt;span class=&#34;ss&#34;&gt;python3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;python3&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;override &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
     &lt;span class=&#34;ss&#34;&gt;packageOverrides&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pyself&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; pysuper&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

       &lt;span class=&#34;ss&#34;&gt;pygls&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pygls&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overrideAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;old&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;fetchFromGitHub &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
           &lt;span class=&#34;ss&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;openlawlibrary&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
           &lt;span class=&#34;ss&#34;&gt;repo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;pygls&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
           &lt;span class=&#34;ss&#34;&gt;rev&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;v&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
           &lt;span class=&#34;ss&#34;&gt;hash&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;sha256-31J4+giK1RDBS52Q/Ia3Y/Zak7fp7gRVTQ7US/eFjtM=&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
         &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
       &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;python3Packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python3&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Using this in the flake is a matter of importing it and passing it to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;overlays&lt;/span&gt;&lt;/code&gt; attribute when importing nixpkgs&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In flake.nix&lt;/span&gt;
&lt;span class=&#34;ss&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; utils &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

 &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;   &lt;span class=&#34;ss&#34;&gt;pygls-overlay&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./nix/pygls-overlay.nix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;   &lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
 &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

 &lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;     &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;overlays&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; pygls-overlay &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;   &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
     eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;37&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
       &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;pytest-lsp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/pytest-lsp.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;pythonPackages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
       &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With some luck, running &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;develop&lt;/span&gt;&lt;/code&gt; this time should bring in the latest &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pygls&lt;/span&gt;&lt;/code&gt; version&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-c&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: builder for &amp;#39;/nix/store/1sha5j0dfyn2g4z82rpk4yqv32awmjfr-python3.10-pytest-lsp-0.2.1.drv&amp;#39; failed with exit code 1;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       ...&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; ERROR: No matching distribution found for pygls&amp;gt;=1.0.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Huh, same error… 🤔&lt;/p&gt;
&lt;p&gt;Let’s take a closer look at where we pull in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; package definition in the flake…&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;pytest-lsp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/pytest-lsp.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pythonPackages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Assuming we’re trying to enter the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python310&lt;/span&gt;&lt;/code&gt; devShell, then we’re passing in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python310Packages&lt;/span&gt;&lt;/code&gt; package set.
But in the overlay, we’re overriding the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python3Packages&lt;/span&gt;&lt;/code&gt; package set, I wonder if we change the overlay to match the flake…&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/pygls-overlay.nix&lt;/span&gt;
self&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; super&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;python310&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;python310&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;override &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;python310Packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python310&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And try again&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34; id=&#34;nix-overlays-build-pygls-output&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: builder for &amp;#39;/nix/store/jl23ai588n2b6amaicy5532bdxjiciyy-python3.10-pygls-0.13.0.drv&amp;#39; failed with exit code 1;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       last 10 log lines:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; removing build/bdist.linux-x86_64/wheel&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Finished executing setuptoolsBuildPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; installing&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Executing pipInstallPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; /build/source/dist /build/source&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Processing ./pygls-0.13.0-py3-none-any.whl&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Requirement already satisfied: typeguard&amp;lt;3,&amp;gt;=2.10.0 in /nix/store/m4jjcrvbi928pi2d14qh8np1miqfvc0b-python3.10-typeguard-2.13.3/lib/python3.10/site-packages (from pygls==0.13.0) (2.13.3)&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt; ERROR: Could not find a version that satisfies the requirement lsprotocol (from pygls) (from versions: none)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;hll&#34;&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt; ERROR: No matching distribution found for lsprotocol&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       For full logs, run &amp;#39;nix log /nix/store/jl23ai588n2b6amaicy5532bdxjiciyy-python3.10-pygls-0.13.0.drv&amp;#39;.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;error: 1 dependencies of derivation &amp;#39;/nix/store/f5vasy4x9zpdhcq9jh9rz06qpvriblwp-python3.10-pytest-lsp-0.2.1.drv&amp;#39; failed to build&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;error: 1 dependencies of derivation &amp;#39;/nix/store/86v8bcxvjq1g9dhpx1wgmckba8bnag7h-py310-env.drv&amp;#39; failed to build&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Progress!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;packaging-lsprotocol&#34;&gt;
&lt;h2&gt;Packaging &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;lsprotocol&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#packaging-lsprotocol&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;pygls is failing to build as the package definition in nixpkgs is missing the new &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;lsprotcol&lt;/span&gt;&lt;/code&gt; dependency, easy enough to fix - if it was available in nixpkgs.
Thankfully, overlays can do more than just override attributes on existing packages, they can be used to extend a package set with entirely new definitions!&lt;/p&gt;
&lt;p&gt;We just need to know how to package &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;lsprotocol&lt;/span&gt;&lt;/code&gt; itself and thanks to the PR linked above we get to cheat a little.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/pygls-overlay.nix&lt;/span&gt;
&lt;span class=&#34;ss&#34;&gt;lsprotocol&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;buildPythonPackage &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;lsprotocol&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;2022.0.0a9&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;pyproject&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;fetchFromGitHub &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;microsoft&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;repo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pname&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;rev&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;hash&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;sha256-6XecPKuBhwtkmZrGozzO+VEryI5wwy9hlvWE1oV6ajk=&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;nativeBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;python310Packages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    flit-core
  &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;propagatedBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;python310Packages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    cattrs
    attrs
  &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Disable tests&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;doCheck&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note that I’ve cut some corners by disabling any tests, but it allows me to dodge packaging anything else 😅&lt;/p&gt;
&lt;p&gt;Then we can also override pygls’ dependencies and reference the newly created &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;lsprotocol&lt;/span&gt;&lt;/code&gt; package from the modified version of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python310Packages&lt;/span&gt;&lt;/code&gt; set.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;pygls&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pygls&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overrideAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;_&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;propagatedBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; self&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;python310Packages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    lsprotocol
    typeguard
  &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With that taken care of, we should be good to go right?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;unlucky-0-13&#34;&gt;
&lt;h2&gt;Unlucky &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;0.13&lt;/span&gt;&lt;/code&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#unlucky-0-13&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Attempting to enter the devShell yet again we encounter a familiar error message&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;go&#34;&gt;error: builder for &amp;#39;/nix/store/s5xp7fr2r9faxgqw7rvs6ffah10f2fz7-python3.10-pytest-lsp-0.2.1.drv&amp;#39; failed with exit code 1;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       last 10 log lines:&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Finished executing setuptoolsBuildPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; installing&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Executing pipInstallPhase&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; /build/pytest-lsp/dist /build/pytest-lsp&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Processing ./pytest_lsp-0.2.1-py3-none-any.whl&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Requirement already satisfied: pytest-asyncio in /nix/store/dvz12bivdc0dkn6849zm58754ga06hs6-python3.10-pytest-asyncio-0.20.3/lib/python3.10/site-packages (from pytest-lsp==0.2.1) (0.20.3)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       &amp;gt; Requirement already satisfied: pytest in /nix/store/z5pkmmsdg3bmb35pmsv4rjca1qi7dbnf-python3.10-pytest-7.2.0/lib/python3.10/site-packages (from pytest-lsp==0.2.1) (7.2.0)&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt; ERROR: Could not find a version that satisfies the requirement pygls&amp;gt;=1.0.0 (from pytest-lsp) (from  versions: none)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;hll&#34;&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt; ERROR: No matching distribution found for pygls&amp;gt;=1.0.0&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#34;go&#34;&gt;       &amp;gt;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;       For full logs, run &amp;#39;nix log /nix/store/s5xp7fr2r9faxgqw7rvs6ffah10f2fz7-python3.10-pytest-lsp-0.2.1.drv&amp;#39;.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;error: 1 dependencies of derivation &amp;#39;/nix/store/a0smpmj63fw1fzp78i3z53xvd0zsvvhp-py310-env.drv&amp;#39; failed to build&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;But we just upgraded pygls to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;1.0&lt;/span&gt;&lt;/code&gt; right? That’s why we had to package &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;lsprotocol&lt;/span&gt;&lt;/code&gt; in the previous section?&lt;/p&gt;
&lt;p&gt;You might have already noticed in the log output &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2023/nix-overlays/#nix-overlays-build-pygls-output&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;above&lt;/span&gt;&lt;/a&gt;, that despite overriding the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;version&lt;/span&gt;&lt;/code&gt; field to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;1.0&lt;/span&gt;&lt;/code&gt; the Python package was still coming out as &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;0.13.0&lt;/span&gt;&lt;/code&gt; - despite it containing the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;1.0&lt;/span&gt;&lt;/code&gt; version of the codebase!&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;go&#34;&gt;&amp;gt; Processing ./pygls-0.13.0-py3-none-any.whl&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Plenty of head scratching later, I finally remembered that pygls uses &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/pypa/setuptools_scm&#34;&gt;setuptools_scm&lt;/a&gt; to automatically derive the version number based on tags in its git repository.
But the build is not taking place in a git repo… so nix must be setting that version somehow right?&lt;/p&gt;
&lt;p&gt;Yep. A quick trip to the actual file containing pygls’ package definition on nixpkgs (and not just the diff view in the PR!) reveals an additional attribute that needed to be overriden&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/pygls-overlay.nix&lt;/span&gt;
&lt;span class=&#34;ss&#34;&gt;pygls&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pygls&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overrideAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;_&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
     &lt;span class=&#34;ss&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
     &lt;span class=&#34;ss&#34;&gt;SETUPTOOLS_SCM_PRETEND_VERSION&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
     &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now if we try activating that devShell?&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(nix-shell)&lt;/span&gt; &lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;pytest
&lt;span class=&#34;go&#34;&gt;================================== test session starts =================================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;platform linux -- Python 3.10.9, pytest-7.2.0, pluggy-1.0.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;rootdir: /var/home/alex/Projects/lsp-devtools/lib/pytest-lsp, configfile: pyproject.toml&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;plugins: lsp-0.2.1, typeguard-2.13.3, asyncio-0.20.3&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;asyncio: mode=auto&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;collected 27 items&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;tests/test_client.py ...                                    [ 11%]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;tests/test_client_methods.py ...................            [ 81%]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;tests/test_plugin.py ....                                   [ 96%]&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;tests/test_server.py .                                      [100%]&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;================================= 27 passed in 8.57s ==================================&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;I’m not 100% sure if I’ve overriden the pygls’ version number correctly, since inspecting the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PYTHONPATH&lt;/span&gt;&lt;/code&gt; the devShell is using shows that the version number of the nix package is &lt;em&gt;still&lt;/em&gt; &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;0.13.0&lt;/span&gt;&lt;/code&gt;!&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(nix-shell)&lt;/span&gt; &lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PYTHONPATH&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;tr&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;grep&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;pygls
&lt;span class=&#34;go&#34;&gt;/nix/store/s5jh5s9m5f1163hxzj8768jc5li7cdfg-python3.10-pygls-0.13.0/lib/python3.10/site-packages&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;But in Python land, everything appears at least, to be consistent, so I’m going with it for now.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;mutliple-python-versions&#34;&gt;
&lt;h2&gt;Mutliple Python Versions&lt;a class=&#34;headerlink&#34; href=&#34;#mutliple-python-versions&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we’ve got it working for Python 3.10, we need to generalise the overlay so that we can use it with any of the Python versions supported by &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ideally, what we’d want is to write an expression like the following&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/pygls-overlay.nix&lt;/span&gt;
self&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; super&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;

eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;37&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;override &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;packageOverrides&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pyself&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; pysuper&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

       &lt;span class=&#34;ss&#34;&gt;lsprotocol&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;buildPythonPackage &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
         &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;nativeBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
           flit-core
         &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

         &lt;span class=&#34;ss&#34;&gt;propagatedBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
           cattrs
           attrs
         &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
       &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

       &lt;span class=&#34;ss&#34;&gt;pygls&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pygls&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overrideAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;_&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
         &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;propagatedBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; self&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
           lsprotocol
           typeguard
         &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And have the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachPythonVersion&lt;/span&gt;&lt;/code&gt; function handle the details of performing all the overrides.&lt;/p&gt;
&lt;p&gt;To start with, let’s define a helper &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;doPythonOverride&lt;/span&gt;&lt;/code&gt; that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachPythonVersion&lt;/span&gt;&lt;/code&gt; can use.
It should take a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;version&lt;/span&gt;&lt;/code&gt; and a function &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;f&lt;/span&gt;&lt;/code&gt; and use it to perform the override for a single Python version, something like the following pseudo code.&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;doPythonOverride(version, f) = { &amp;quot;python${version}&amp;quot; = f(version);
                                 &amp;quot;python${version}Packages&amp;quot; = &amp;quot;python${version}&amp;quot;.pkgs; }
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The only issue is that (as far as I can tell), you can’t use strings as keys in a nix attribute set.
However, you can use the
&lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs&#34;&gt;builtins.listToAttrs&lt;/a&gt;
function to build an attribute set from a list of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;&amp;quot;xxx&amp;quot;;&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;123;&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;}&lt;/span&gt;&lt;/code&gt; attribute sets, which allows us to define &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;doPythonOverride&lt;/span&gt;&lt;/code&gt; as follows.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;doPythonOverride&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;overridenPython&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; f version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;listToAttrs &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; overridenPython&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
                           &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; overridenPython&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}];&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;From there, we can define &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachPythonVersion&lt;/span&gt;&lt;/code&gt; to map the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;doPythonOverride&lt;/span&gt;&lt;/code&gt; helper across each of the given Python versions and merge the results into a single attribute set using the
&lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/manual/nix/stable/language/builtins.html#builtins-foldl&#39;&#34;&gt;foldl’&lt;/a&gt;
function.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;foldl&amp;#39; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;a&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; b&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; a &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; b&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; doPythonOverride version f&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now we should have successfully overriden pygls’ version across all supported Python versions!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;sharing-overlays&#34;&gt;
&lt;span id=&#34;nix-overlays-sharing&#34;&gt;&lt;/span&gt;&lt;h2&gt;Sharing Overlays&lt;a class=&#34;headerlink&#34; href=&#34;#sharing-overlays&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Up until now, I’ve been mostly focusing on the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShells&lt;/span&gt;&lt;/code&gt; output of a flake.
There are, however, &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.wiki/wiki/Flakes#Output_schema&#34;&gt;many other&lt;/a&gt; items that can be exported from a flake - including overlays.
Following the same pattern as the previous section it’s easy enough to convert the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; package definition into an overlay&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/pytest-lsp-overlay.nix&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;doPythonOverride&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;overridenPython&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; f version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
      &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;listToAttrs &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; overridenPython &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
                             &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; overridenPython&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pkgs &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}];&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;foldl&amp;#39; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;a&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; b&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; a &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; b&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; doPythonOverride version f&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;

self&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; super&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;

eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;37&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
  super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;override &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;packageOverrides&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pyself&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; pysuper&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;pytest-lsp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pysuper&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;buildPythonPackage &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;pname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;pytest-lsp&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;0.2.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./..&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;propagatedBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; super&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
          pygls
          pytest
          pytest-asyncio
        &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We can then include it in the main &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; file just as we did with the pygls overlay, but also assign it to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;overlays&lt;/span&gt;&lt;/code&gt; output to make it available to other projects.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In flake.nix&lt;/span&gt;
&lt;span class=&#34;ss&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; utils &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;pygls-overlay&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./nix/pygls-overlay.nix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;   &lt;span class=&#34;ss&#34;&gt;pytest-lsp-overlay&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./nix/pytest-lsp-overlay.nix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

&lt;span class=&#34;hll&#34;&gt; overlays&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;pytest-lsp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pytest-lsp-overlay&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;
 &lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;     &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;overlays&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; pygls-overlay pytest-lsp-overlay &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;   &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
     &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In theory, we can update the flake we previously wrote for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; to use this overlay to provide the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; package definition&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In esbonio/flake.nix&lt;/span&gt;

&lt;span class=&#34;ss&#34;&gt;inputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  nixpkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:NixOS/nixpkgs/nixpkgs-unstable&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;  pytest-lsp&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:swyddfa/lsp-devtools?dir=lib/pytest-lsp&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;  utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:numtide/flake-utils&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;ss&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; pytest-lsp&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; utils &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;pygls-overlay&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./nix/pygls-overlay.nix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
&lt;span class=&#34;hll&#34;&gt;      &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;overlays&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; pygls-overlay pytest-lsp&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;overlays&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest-lsp &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
      &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally, we should be able to activate a devShell for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; as before.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310
&lt;span class=&#34;go&#34;&gt;error: Dependency is not of a valid type: element 5 of nativeBuildInputs for py310&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(use &amp;#39;--show-trace&amp;#39; to show detailed location information)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ah, well, perhaps that’s a job for another day! 😅&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2022/first-steps-with-nix/</id>
    <link href="https://www.alcarney.me/blog/2022/first-steps-with-nix" rel="alternate" />
    <published>2022-12-27T00:00:00+00:00</published>
    <updated>2022-12-27T00:00:00+00:00</updated>
    <title>My First Steps with Nix</title>
    <content type="html">
      &lt;section id=&#34;my-first-steps-with-nix&#34;&gt;
&lt;h1&gt;My First Steps with Nix&lt;a class=&#34;headerlink&#34; href=&#34;#my-first-steps-with-nix&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;Nix, depending on the context, can refer to a &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/manual/nix/stable/language/index.html&#34;&gt;programming language&lt;/a&gt;, a &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/manual/nixpkgs/stable/#preface&#34;&gt;package manager&lt;/a&gt; or a &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/manual/nixos/stable/#sec-installation&#34;&gt;Linux Distro&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Personally, I’m most insterested in the package manager aspect and the promise of it being able to create declarative, reproducable development environments.
With a configuration file and the &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html&#34;&gt;nix develop&lt;/a&gt; command you can activate a kind of “virtual environment” that contains not just your Python packages - but &lt;em&gt;any&lt;/em&gt; program defined by the configuration!&lt;/p&gt;
&lt;p&gt;I find that idea particuarly exciting when working on a language server like &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio/&#34;&gt;esbonio&lt;/a&gt;, since it needs to be able to work against a variety of Python versions, Sphinx versions, as well as various code editors and all their versions!
Having the ability to define a particular configuration and have some tool automatically recreate it would be amazing.&lt;/p&gt;
&lt;p&gt;But I’m getting ahead of myself, let’s see if I can get to a point where I can easily test &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; against a range of Python versions.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;intalling-nix&#34;&gt;
&lt;h2&gt;Intalling Nix&lt;a class=&#34;headerlink&#34; href=&#34;#intalling-nix&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What a nightmare! 😭&lt;/p&gt;
&lt;p&gt;I should say though, my issues aren’t really Nix’s fault.
Trying to install Nix directly on &lt;a class=&#34;reference external&#34; href=&#34;https://kinoite.fedoraproject.org/&#34;&gt;Fedora Kinoite&lt;/a&gt; means dealing with issues caused by SELinux (which the Nix installer does &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nix/issues/2374&#34;&gt;not support&lt;/a&gt;) and working around the immutable root filesystem.&lt;/p&gt;
&lt;p&gt;Basically, don’t do as I do! 😄&lt;/p&gt;
&lt;p&gt;If you do find yourself in my situation though, here’s a few things you might find useful&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://gist.github.com/matthewpi/08c3d652e7879e4c4c30bead7021ff73&#34;&gt;This guide&lt;/a&gt; will get you 90% of the way, I was able to piece together the remaining steps from links in the comments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Nix installer has been updated since the guide was written to bail if it detects that SELinux has been enabled.
You will need to patch out the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;check_selinux&lt;/span&gt;&lt;/code&gt; function in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;install-multi-user&lt;/span&gt;&lt;/code&gt; script in the release tarball that the Nix installer downloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you get a cryptic&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;error: could not set permissions on &amp;#39;/nix/var/nix/profiles/per-user&amp;#39; to 755: Operation not permitted
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;message whenever you run a nix command, chances are the nix-daemon is not running.
Use &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;nix-daemon.service&lt;/span&gt;&lt;/code&gt; to check its status.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you see an error in the output of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;nix-daemon.service&lt;/span&gt;&lt;/code&gt; along the lines of:&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nix-daemon.service: Failed to locate executable /nix/store/xdlpraypxdimjyfrr4k06narrv8nmfgh-nix-2.11.1/bin/nix-daemon: Permission denied
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;you need to re-apply the SELinux policies defined in the guide linked above by running &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;sudo&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;restorecon&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;-RF&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;/nix&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;a-simple-flake&#34;&gt;
&lt;h2&gt;A Simple Flake&lt;a class=&#34;headerlink&#34; href=&#34;#a-simple-flake&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;I’m not the best person to learn how to use Nix from - I’m still trying to figure it out myself!
Instead here are a few resources that I’ve found useful which go into more detail.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://xeiaso.net/blog/nix-flakes-1-2022-02-21&#34;&gt;Nix Flakes: An Introduction&lt;/a&gt;, part one of a &lt;a class=&#34;reference external&#34; href=&#34;https://xeiaso.net/blog/series/nix-flakes&#34;&gt;series&lt;/a&gt; of posts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Jon Ringer’s &lt;a class=&#34;reference external&#34; href=&#34;https://www.youtube.com/&amp;#64;elitespartan117j27&#34;&gt;Youtube Channel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;From what I can gather, &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.wiki/wiki/Flakes&#34;&gt;flakes&lt;/a&gt; are a good starting point as they have a well defined structure and seem to be where things are going when it comes to Nix based workflows.&lt;/p&gt;
&lt;p&gt;As mentioned in the intro I’d like to get to the point where I can easily test &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; against a range of Python versions, so let’s start off by writing a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; that provides a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; containing Python.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;The Esbonio language server&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;inputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    nixpkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:NixOS/nixpkgs/nixpkgs-unstable&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;github:numtide/flake-utils&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; utils &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;
    utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystem &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;devShell&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
         mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
            &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; python3 &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
         &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Using &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;flake&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;show&lt;/span&gt;&lt;/code&gt; we can see what outputs are produced by this flake&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;flake&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;show
&lt;span class=&#34;go&#34;&gt;warning: Git tree &amp;#39;/var/home/alex/Projects/esbonio&amp;#39; is dirty&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;error: getting status of &amp;#39;/nix/store/9s8zs1hrqiingklv86fd18x2mbgsfw0w-source/lib/esbonio/flake.nix&amp;#39;: No such file or directory&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Oh! I always forget, when working with flakes nix will only see a file if it is tracked by git - we don’t need to commit it, but it needs to at least be staged.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;git&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;add&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;flake.nix
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;flake&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;show
&lt;span class=&#34;go&#34;&gt;warning: Git tree &amp;#39;/var/home/alex/Projects/esbonio&amp;#39; is dirty&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;git+file:///var/home/alex/Projects/esbonio?dir=lib%&lt;/span&gt;2fesbonio
&lt;span class=&#34;go&#34;&gt;└───devShell&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;   ├───aarch64-darwin: development environment &amp;#39;nix-shell&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;   ├───aarch64-linux: development environment &amp;#39;nix-shell&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;   ├───x86_64-darwin: development environment &amp;#39;nix-shell&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;   └───x86_64-linux: development environment &amp;#39;nix-shell&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This shows that we’ve already defined development environments for MacOS and Linux on both x86 and Arm platforms!
To “activate” the correct environment we only need to run &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;develop&lt;/span&gt;&lt;/code&gt;.
Nix is smart enough to choose the one compatible with our current system and will proceed to setup all the packages required for that environment.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(nix-shell)&lt;/span&gt; &lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-v&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;python
&lt;span class=&#34;go&#34;&gt;/nix/store/qc8rlhdcdxaf6dwbvv0v4k50w937fyzj-python3-3.10.8/bin/python&lt;/span&gt;

&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(nix-shell)&lt;/span&gt; &lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;python
&lt;span class=&#34;go&#34;&gt;Python 3.10.8 (main, Oct 11 2022, 11:35:05) [GCC 11.3.0] on linux&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Type &amp;quot;help&amp;quot;, &amp;quot;copyright&amp;quot;, &amp;quot;credits&amp;quot; or &amp;quot;license&amp;quot; for more information.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Nice!&lt;/p&gt;
&lt;div class=&#34;admonition tip&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Tip&lt;/p&gt;
&lt;p&gt;See &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/dotfiles/blob/90d90d1d2f67a03a7f8b73803784b13362027e13/bash/20-prompt#L12-L20&#34;&gt;here&lt;/a&gt; for details on how I configured my bash prompt to detect if I’m in a nix shell or not.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;adding-python-packages&#34;&gt;
&lt;h2&gt;Adding Python Packages&lt;a class=&#34;headerlink&#34; href=&#34;#adding-python-packages&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Of course, this environment isn’t that useful at the moment as any of the packages required for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; and its test suite are not available&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(nix-shell)&lt;/span&gt; &lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;pytest
&lt;span class=&#34;go&#34;&gt;bash: pytest: command not found&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If we’re lucky, the packages we need are already part of &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs&#34;&gt;nixpkgs&lt;/a&gt; and we just need to add them to the devShell’s &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;packages&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;devShell&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
      python3

      &lt;span class=&#34;c1&#34;&gt;# esbonio&amp;#39;s dependencies&lt;/span&gt;
      python3Packages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;appdirs
      python3Packages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;sphinx
      python3Packages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pygls
      python3Packages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;typing-extensions

      &lt;span class=&#34;c1&#34;&gt;# test suite dependencies&lt;/span&gt;
      python3Packages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mock
      python3Packages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest
      python3Packages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest-lsp
      python3Packages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest-timeout
    &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And reactivate the environment&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop
&lt;span class=&#34;go&#34;&gt;warning: Git tree &amp;#39;/var/home/alex/Projects/esbonio&amp;#39; is dirty&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;error: attribute &amp;#39;pytest-lsp&amp;#39; missing&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;      at /nix/store/ll2pir6ii65n4cplan9iykxy7cksw6k8-source/lib/esbonio/flake.nix:27:13:&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;         26|             python3Packages.pytest&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;         27|             python3Packages.pytest-lsp&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;           |             ^&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;         28|             python3Packages.pytest-timeout&lt;/span&gt;
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(use &amp;#39;--show-trace&amp;#39; to show detailed location information)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Unfortunately, &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; is not available through nixpkgs but since it’s an unknown library I wrote to help test &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; I can’t say I’m surprised! 😄
It should however, be relatively straightforward to package it ourselves, especially if we use &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/development/python-modules/pytest-timeout/default.nix&#34;&gt;an example&lt;/a&gt; from the nixpkgs repo as a guide.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/pytest-lsp.nix&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; pythonPackages &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

pythonPackages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;buildPythonPackage &lt;span class=&#34;k&#34;&gt;rec&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;pname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;pytest-lsp&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;0.1.3&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pythonPackages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;fetchPypi &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; pname version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;sha256&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;sha256-WxTh9G3tWyGzYx1uHufkwg3hN6jTbRjlGLKJR1eUNtY=&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;buildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    pythonPackages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;appdirs
    pythonPackages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pygls
    pythonPackages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest
  &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;propagatedBuildInputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    pythonPackages&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest-asyncio
  &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Disable tests&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;doCheck&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You probably don’t want to use this as an example of packaging a Python package with Nix, as I don’t fully understand what I’m doing and I’ve taken a few shortcuts (like disabling tests), but here’s a few notes.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;pythonPackages&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;:&lt;/span&gt;&lt;/code&gt; syntax at the top of the file is defining a function that accepts &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pythonPackages&lt;/span&gt;&lt;/code&gt; as an argument.
This is what allows this definition to be used with multiple Python versions later on in this blog post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As the name implies, the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;fetchPypi&lt;/span&gt;&lt;/code&gt; function is used to pull the sources for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pytest-lsp&lt;/span&gt;&lt;/code&gt; straight from PyPi.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;propagtedBuildInputs&lt;/span&gt;&lt;/code&gt; are also available for use at runtime, while &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;buildInputs&lt;/span&gt;&lt;/code&gt; are “hidden” from the final runtime environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, to use this package definition in our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake.nix&lt;/span&gt;&lt;/code&gt; file we use the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;callPackage&lt;/span&gt;&lt;/code&gt; function and pass it the correct python package set.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34; id=&#34;first-steps-nix-call-pytest-lsp&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./flake.nix&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;pytest-lsp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/pytest-lsp.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;pythonPackages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;python3Packages&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;devShell&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
     mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
         &lt;span class=&#34;c1&#34;&gt;# ...&lt;/span&gt;
         pytest-lsp
       &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Hopefully, we now have all we need to run the test suite.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(nix-shell)&lt;/span&gt; &lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;pytest
&lt;span class=&#34;go&#34;&gt;=========================================================================================================== test session starts ============================================================================================================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;platform linux -- Python 3.10.8, pytest-7.1.3, pluggy-1.0.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;rootdir: /var/home/alex/Projects/esbonio/lib/esbonio, configfile: pyproject.toml&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;plugins: typeguard-2.13.3, lsp-0.1.3, asyncio-0.19.0, timeout-2.1.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;asyncio: mode=auto&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;collected 0 items / 1 error&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;================================================================================================================== ERRORS ==================================================================================================================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;______________________________________________________________________________________________________ ERROR collecting test session _______________________________________________________________________________________________________&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;/nix/store/qc8rlhdcdxaf6dwbvv0v4k50w937fyzj-python3-3.10.8/lib/python3.10/importlib/__init__.py:126: in import_module&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;   ...&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;tests/sphinx-default/conftest.py:12: in &amp;lt;module&amp;gt;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;   from esbonio.lsp.sphinx import InitializationOptions&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;E   ModuleNotFoundError: No module named &amp;#39;esbonio&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;========================================================================================================= short test summary info ==========================================================================================================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;ERROR  - ModuleNotFoundError: No module named &amp;#39;esbonio&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ah… looks like we have to package &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;esbonio&lt;/span&gt;&lt;/code&gt; itself, but we already know how to do that, aside from dependencies the only major difference is where we fetch the sources from.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ./nix/esbonio.nix&lt;/span&gt;

&lt;span class=&#34;ss&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;l&#34;&gt;./..&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now we should have everything setup correctly! 🤞&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;go&#34;&gt;==================================== test session starts =====================================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;platform linux -- Python 3.10.8, pytest-7.1.3, pluggy-1.0.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;rootdir: /var/home/alex/Projects/esbonio/lib/esbonio, configfile: pyproject.toml&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;plugins: typeguard-2.13.3, lsp-0.1.3, asyncio-0.19.0, timeout-2.1.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;asyncio: mode=auto&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;collected 2487 items&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;...&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;=============== 2475 passed, 4 skipped, 8 xfailed in 132.96s (0:02:12) =======================&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;multiple-python-versions&#34;&gt;
&lt;span id=&#34;first-steps-nix-multiple-python-versions&#34;&gt;&lt;/span&gt;&lt;h2&gt;Multiple Python Versions&lt;a class=&#34;headerlink&#34; href=&#34;#multiple-python-versions&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Switching to a Nix-ish style of pseudo code for a moment, let’s summarize how our flake is currently defined.
We defined a function which takes a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;system&lt;/span&gt;&lt;/code&gt; and produces an attribute set (think Python dictionary) with a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; field&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;f(system) = { devShell = &amp;lt;devShell for system&amp;gt; }
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We then passed that function to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachDefaultSystem&lt;/span&gt;&lt;/code&gt; helper from the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/numtide/flake-utils&#34;&gt;flake-utils&lt;/a&gt; repo.
This calls our function with each of the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/numtide/flake-utils/blob/5aed5285a952e0b949eb3ba02c12fa4fcfef535f/default.nix#L3-L8&#34;&gt;default system architectures&lt;/a&gt; before transforming it into a structure compatible with the flake &lt;a class=&#34;reference external&#34; href=&#34;https://nixos.wiki/wiki/Flakes#Output_schema&#34;&gt;output schema&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;eachDefaultSystem(f) = applyTransform { aarch64-linux = f(aarch64-linux), ... }
                     = applyTransform { aarch64-linux = { devShell = &amp;lt;devShell for aarch64-linux&amp;gt; }, ... }
                     = { devShell.aarch64-linux.default = &amp;lt;devShell for aarch64-linux&amp;gt;, ... }
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now that we want to support multiple Python versions however, we want to define a function that returns an attribute set with a devShell for each Python version&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;f(system) = { py37 = &amp;lt;py37 devShell for system&amp;gt;, py38 = &amp;lt;py38 devShell for system&amp;gt;, ... }
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which we can then pass to a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mysteryHelper&lt;/span&gt;&lt;/code&gt; function to perform a similar (but structurally distinct!) transformation on the results of our function &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;f&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;devShells = mysteryHelper(f)
          = applyTransform { aarch64-linux = f(aarch64-linux), ... }
          = applyTransform {
                             aarch64-linux  = { py37 = &amp;lt;py37 devShell for aarch64-linux&amp;gt;,
                                                py38 = &amp;lt;py38 devShell for aarch64-linux&amp;gt;,
                                                ...
                                              },
                             ...,
                           }
          = {
              aarch64-linux.py37 = &amp;lt;py37 devShell for aarch64-linux&amp;gt;,
              aarch64-linux.py38 = &amp;lt;py38 devShell for aarch64-linux&amp;gt;,
              ...
            }
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That’s the idea at least, now to translate it into real Nix code.&lt;/p&gt;
&lt;p&gt;Thankfully, finding an implementation for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mysteryHelper&lt;/span&gt;&lt;/code&gt; isn’t too difficult as the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;flake-utils&lt;/span&gt;&lt;/code&gt; repo provides &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachDefaultSystemMap&lt;/span&gt;&lt;/code&gt; which does precisely what we want.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; utils &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;
  &lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    f system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now to replace our imaginary function &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;f&lt;/span&gt;&lt;/code&gt; with an expression that defines our devShells.&lt;/p&gt;
&lt;div class=&#34;admonition important&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Important&lt;/p&gt;
&lt;p&gt;Notice that we now assign to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShells&lt;/span&gt;&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;It turns out that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt;&lt;/code&gt; the command line tool does a little
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/NixOS/nix/blob/3dbf9b5af5950b615ec685c1f4155b1c8698bb78/src/nix/flake.cc#L517&#34;&gt;transformation&lt;/a&gt;
to turn a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShell&lt;/span&gt;&lt;/code&gt; entry into a valid &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShells&lt;/span&gt;&lt;/code&gt; entry.
Unfortunately, this transformation only works when you define a single shell per system!&lt;/p&gt;
&lt;p&gt;Now that we’re defining multiple shells per system, we have to make sure to use &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;devShells&lt;/span&gt;&lt;/code&gt; - it took me a &lt;em&gt;long&lt;/em&gt; time to spot this!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;We could simply copy-paste the devShell definition from the previous section a bunch of times and switch out the Python version.&lt;/p&gt;
&lt;p&gt;However, since the definitions for each Python version are going to be so similar, a better approach would be to define our own helper that would map a function over a list of versions and have it build the attribute set for us.&lt;/p&gt;
&lt;p&gt;It turns out that the
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/numtide/flake-utils/blob/5aed5285a952e0b949eb3ba02c12fa4fcfef535f/default.nix#L150&#34;&gt;implementation&lt;/a&gt;
of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;eachDefaultSystemMap&lt;/span&gt;&lt;/code&gt; is almost identical to what we need, so it was easy enough to adapt it to this use case.&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;listToAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; f version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Bringing it all together gives us this final flake definition&lt;/p&gt;
&lt;div class=&#34;highlight-nix notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; self&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; utils &lt;span class=&#34;p&#34;&gt;}:&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;eachPythonVersion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; f&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;listToAttrs &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;builtins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;version&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; f version&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt; versions&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

  &lt;span class=&#34;ss&#34;&gt;devShells&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; utils&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;lib&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;eachDefaultSystemMap &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;system&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;pkgs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;inherit&lt;/span&gt; system&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;
      eachPythonVersion &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;37&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;38&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;39&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;310&amp;quot;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;311&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;pyVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;let&lt;/span&gt;
          &lt;span class=&#34;ss&#34;&gt;pytest-lsp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/pytest-lsp.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;pythonPackages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
          &lt;span class=&#34;ss&#34;&gt;esbonio&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;callPackage &lt;span class=&#34;l&#34;&gt;./nix/esbonio.nix&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;pythonPackages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;

        &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; pkgs&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; mkShell &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
          &lt;span class=&#34;ss&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;py&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

          &lt;span class=&#34;ss&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
            pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;

            esbonio

            &lt;span class=&#34;c1&#34;&gt;# test suite dependencies&lt;/span&gt;
            pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;mock
            pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest
            pytest-lsp
            pkgs&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;python&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;pyVersion&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Packages&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;pytest-timeout
          &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With any luck, we should now see a per-python version devShell appear in the output of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;flake&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;show&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;flake&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;show
&lt;span class=&#34;gp&#34;&gt;git+file:///var/home/alex/Projects/esbonio?dir=lib%2fesbonio&amp;amp;ref=refs%2fheads%&lt;/span&gt;2fnix&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;rev&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4a548327974dff1750099df4d793638a64b663e6
&lt;span class=&#34;go&#34;&gt;└───devShells&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    ├───aarch64-darwin&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py310: development environment &amp;#39;py310&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py311: development environment &amp;#39;py311&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py37: development environment &amp;#39;py37&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py38: development environment &amp;#39;py38&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   └───py39: development environment &amp;#39;py39&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    ├───aarch64-linux&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py310: development environment &amp;#39;py310&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py311: development environment &amp;#39;py311&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py37: development environment &amp;#39;py37&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py38: development environment &amp;#39;py38&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   └───py39: development environment &amp;#39;py39&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    ├───x86_64-darwin&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py310: development environment &amp;#39;py310&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py311: development environment &amp;#39;py311&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py37: development environment &amp;#39;py37&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   ├───py38: development environment &amp;#39;py38&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    │   └───py39: development environment &amp;#39;py39&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    └───x86_64-linux&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;        ├───py310: development environment &amp;#39;py310&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;        ├───py311: development environment &amp;#39;py311&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;        ├───py37: development environment &amp;#39;py37&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;        ├───py38: development environment &amp;#39;py38&amp;#39;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;        └───py39: development environment &amp;#39;py39&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To reference a given environment we’d use the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;.#&amp;lt;envname&amp;gt;&lt;/span&gt;&lt;/code&gt; syntax when calling &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;nix&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;develop&lt;/span&gt;&lt;/code&gt;.
The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;--command&lt;/span&gt;&lt;/code&gt; flag also allows us to run a command within the named environment without having to activate it first!&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py310&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--command&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;pytest
&lt;span class=&#34;go&#34;&gt;=========================== test session starts ================================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;platform linux -- Python 3.10.8, pytest-7.1.3, pluggy-1.0.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;rootdir: /var/home/alex/Projects/esbonio/lib/esbonio, configfile: pyproject.toml&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;plugins: typeguard-2.13.3, lsp-0.1.3, asyncio-0.19.0, timeout-2.1.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;asyncio: mode=auto&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;collected 2508 items&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;...&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;======== 2496 passed, 4 skipped, 8 xfailed in 344.10s (0:05:27) ================&lt;/span&gt;

&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;nix&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;develop&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.#py39&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--command&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;pytest
&lt;span class=&#34;go&#34;&gt;=========================== test session starts ================================&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;platform linux -- Python 3.9.15, pytest-7.1.3, pluggy-1.0.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;rootdir: /var/home/alex/Projects/esbonio/lib/esbonio, configfile: pyproject.toml&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;plugins: typeguard-2.13.3, lsp-0.1.3, asyncio-0.19.0, timeout-2.1.0&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;asyncio: mode=auto&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;collected 2508 items&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;...&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;======== 2496 passed, 4 skipped, 8 xfailed in 344.10s (0:05:44) ================&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Achievement unlocked! 🏆&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;next-steps&#34;&gt;
&lt;h2&gt;Next Steps&lt;a class=&#34;headerlink&#34; href=&#34;#next-steps&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was mainly a “Hello, World” type exercise looking to see if I could get Nix up and running in a real project, but so far I haven’t achieved anything you can’t already do with traditional Python tools like &lt;a class=&#34;reference external&#34; href=&#34;https://tox.wiki/en/latest/index.html&#34;&gt;tox&lt;/a&gt;.
However, this should hopefully serve as a good foundation on which I can explore&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Changing the source where dependent libraries are fetched from (e.g. local vs git vs PyPi)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using overlays (these might help with the previous point?)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Defining environments that contain particular text editor configurations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are interested, you can find the final Nix definitions
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/esbonio/commit/f62e1d486bb7899d802bfd668f98f21b71702317&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2021/bringing-esbonio-to-the-browser/</id>
    <link href="https://www.alcarney.me/blog/2021/bringing-esbonio-to-the-browser" rel="alternate" />
    <published>2021-10-25T00:00:00+00:00</published>
    <updated>2021-10-25T00:00:00+00:00</updated>
    <title>Bringing Esbonio to the Browser</title>
    <content type="html">
      &lt;section id=&#34;bringing-esbonio-to-the-browser&#34;&gt;
&lt;h1&gt;Bringing Esbonio to the Browser&lt;a class=&#34;headerlink&#34; href=&#34;#bringing-esbonio-to-the-browser&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;For the past year or so I’ve been working on a language server called &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/esbonio&#34;&gt;Esbonio&lt;/a&gt;.
It’s a language server designed to streamline the process of working with your
&lt;a class=&#34;reference external&#34; href=&#34;https://www.sphinx-doc.org/en/master/&#34;&gt;Sphinx&lt;/a&gt; documentation projects. Currently its feature set is quite limited, but I
think it does a good job of providing you with completion suggestions for all your
roles, directives and cross-references.&lt;/p&gt;
&lt;figure class=&#34;align-center&#34;&gt;
&lt;img alt=&#34;https://github.com/swyddfa/esbonio/raw/develop/resources/images/completion-demo.gif&#34; src=&#34;https://github.com/swyddfa/esbonio/raw/develop/resources/images/completion-demo.gif&#34; /&gt;
&lt;/figure&gt;
&lt;p&gt;Anyway with the recent releases of &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/github/dev&#34;&gt;github.dev&lt;/a&gt; and &lt;a class=&#34;reference external&#34; href=&#34;https://code.visualstudio.com/blogs/2021/10/20/vscode-dev&#34;&gt;vscode.dev&lt;/a&gt; I really want to
see if I can bring Esbonio into the browser version of VSCode. There’s only one
problem… Esbonio is written in Python! 😬&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;the-approach&#34;&gt;
&lt;h2&gt;The Approach&lt;a class=&#34;headerlink&#34; href=&#34;#the-approach&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m sure there will be plenty of problems that need to be solved in order to
make this work, but my gut instinct is that it &lt;em&gt;is&lt;/em&gt; possible. First of all there is
&lt;a class=&#34;reference external&#34; href=&#34;https://pyodide.org/en/stable/index.html&#34;&gt;Pyodide&lt;/a&gt; which, if you’ve not come across it before, is the Python interpreter,
(&lt;a class=&#34;reference external&#34; href=&#34;https://pyodide.org/en/stable/usage/wasm-constraints.html&#34;&gt;most of&lt;/a&gt;) the standard library and the “scientific stack” compiled down to
WebAssembly which can then be executed in a browser.&lt;/p&gt;
&lt;p&gt;Also, as part of the vscode.dev &lt;a class=&#34;reference external&#34; href=&#34;https://www.youtube.com/watch?v=sy3TUb_iVJM&amp;amp;t=1447&#34;&gt;announcement stream&lt;/a&gt; they demo’d the &lt;a class=&#34;reference external&#34; href=&#34;https://marketplace.visualstudio.com/items?itemName=joyceerhl.vscode-pyodide&#34;&gt;vscode-pyodide&lt;/a&gt;
extension which builds on Pyodide and &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/jupyterlite/jupyterlite&#34;&gt;JupyterLite&lt;/a&gt; to allow for executable Python
notebooks from a web browser! This proves that it’s possible to run Python code via
Pyodide from within VSCode running in a web browser.&lt;/p&gt;
&lt;p&gt;All that’s left to do is “just” to connect the dots! 😃&lt;/p&gt;
&lt;p&gt;Of course, the devil is in the details and there’s going to be all sorts of gotchas on
the way to making this work. But I think a rough plan of attack would be to tackle the
following steps.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Setup a basic VSCode extension that runs in a browser composed of placeholder language
client and server components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Expand on the language server to include a server implemented with &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls&#34;&gt;pygls&lt;/a&gt;
(the library that Esbonio is built on).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensure Sphinx works in a browser context. I’m fairly sure Sphinx is a pure Python
project so in theory should “just work” but file I/O could prove a challenge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bring all of the above together and get the Esbonio language server running.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ship it!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;the-setup&#34;&gt;
&lt;h2&gt;The Setup&lt;a class=&#34;headerlink&#34; href=&#34;#the-setup&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/microsoft/vscode-extension-samples/tree/main/lsp-web-extension-sample&#34;&gt;lsp-web-extension-sample&lt;/a&gt; as a guide, the remainder of this blog post is
going to be dedicated to setting up the rough structure of a web-enabled lsp VSCode
extension. You can browse the completed extension &lt;a class=&#34;reference internal&#34; href=&#34;../code/hello-lsp-web/&#34;&gt;&lt;span class=&#34;doc&#34;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But before we get too far into it, it’s probably worth zooming out a bit and roughly
sketch out all the pieces and how they fit together.&lt;/p&gt;
&lt;section id=&#34;architecture&#34;&gt;
&lt;h3&gt;Architecture&lt;a class=&#34;headerlink&#34; href=&#34;#architecture&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At the core we have two components, a language client (e.g. our VSCode extension) and
a language server (e.g. the &lt;a class=&#34;extlink-pypi reference external&#34; href=&#34;https://pypi.org/project/esbonio&#34;&gt;esbonio&lt;/a&gt; Python package) which communicate by sending
messages between each other.&lt;/p&gt;
&lt;svg
  width=&#34;100%&#34;
  viewBox=&#34;0 0 350 100&#34;
  fill=&#34;currentColor&#34;
  xmlns=&#34;http://www.w3.org/2000/svg&#34;
  xmlns:svg=&#34;http://www.w3.org/2000/svg&#34;&gt;

  &lt;defs&gt;
    &lt;marker id=&#34;arrowhead&#34; markerWidth=&#34;10&#34; markerHeight=&#34;10&#34; refX=&#34;0&#34; refY=&#34;3&#34; orient=&#34;auto&#34; markerUnits=&#34;strokeWidth&#34;&gt;
      &lt;path d=&#34;M0,0 L0,6 L9,3 z&#34;&gt;&lt;/path&gt;
    &lt;/marker&gt;
  &lt;/defs&gt;

  &lt;rect fill=&#34;var(--fg-accent)&#34; x=&#34;30&#34; y=&#34;25&#34; width=&#34;100&#34; height=&#34;50&#34;/&gt;
  &lt;rect fill=&#34;var(--fg-accent)&#34; x=&#34;220&#34; y=&#34;25&#34; width=&#34;100&#34; height=&#34;50&#34;/&gt;

  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;55&#34; x=&#34;47&#34;&gt;LSP Client&lt;/text&gt;
  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;55&#34; x=&#34;237&#34;&gt;LSP Server&lt;/text&gt;

  &lt;path marker-end=&#34;url(#arrowhead)&#34; stroke=&#34;currentColor&#34; d=&#34;M135 40 L205 40&#34;&gt;&lt;/path&gt;
  &lt;path marker-end=&#34;url(#arrowhead)&#34; stroke=&#34;currentColor&#34; d=&#34;M215 60 L145 60&#34;&gt;&lt;/path&gt;
&lt;/svg&gt;&lt;p&gt;In a web browser context, the client runs as a &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API&#34;&gt;Web Worker&lt;/a&gt; that it managed by VSCode’s
Extension Host. The client in turn manages its own Web Worker which hosts the language
server. Hopefully, this server web worker will eventually contain an instance of Pyodide
running Esbonio managed by a bit of JavaScript glue code.&lt;/p&gt;
&lt;svg
  width=&#34;100%&#34;
  viewBox=&#34;0 0 700 200&#34;
  fill=&#34;currentColor&#34;
  xmlns=&#34;http://www.w3.org/2000/svg&#34;
  xmlns:svg=&#34;http://www.w3.org/2000/svg&#34;&gt;

  &lt;defs&gt;
    &lt;marker id=&#34;arrowright&#34; markerWidth=&#34;10&#34; markerHeight=&#34;10&#34; refX=&#34;0&#34; refY=&#34;3&#34; orient=&#34;0deg&#34; markerUnits=&#34;strokeWidth&#34;&gt;
      &lt;path d=&#34;M0,0 L0,6 L9,3 z&#34;&gt;&lt;/path&gt;
    &lt;/marker&gt;
    &lt;marker id=&#34;arrowleft&#34; markerWidth=&#34;10&#34; markerHeight=&#34;10&#34; refX=&#34;0&#34; refY=&#34;3&#34; orient=&#34;180deg&#34; markerUnits=&#34;strokeWidth&#34;&gt;
      &lt;path d=&#34;M0,0 L0,6 L9,3 z&#34;&gt;&lt;/path&gt;
  &lt;/defs&gt;

  &lt;rect fill=&#34;none&#34; stroke=&#34;currentColor&#34; x=&#34;30&#34; y=&#34;50&#34; width=&#34;150&#34; height=&#34;100&#34;/&gt;
  &lt;rect fill=&#34;none&#34; stroke=&#34;currentColor&#34; x=&#34;225&#34; y=&#34;50&#34; width=&#34;150&#34; height=&#34;100&#34;/&gt;
  &lt;rect fill=&#34;none&#34; stroke=&#34;currentColor&#34; x=&#34;420&#34; y=&#34;50&#34; width=&#34;250&#34; height=&#34;100&#34;/&gt;

  &lt;rect fill=&#34;var(--fg-accent)&#34; x=&#34;50&#34; y=&#34;75&#34; width=&#34;110&#34; height=&#34;50&#34;/&gt;
  &lt;rect fill=&#34;var(--fg-accent)&#34; x=&#34;250&#34; y=&#34;75&#34; width=&#34;100&#34; height=&#34;50&#34;/&gt;
  &lt;rect fill=&#34;var(--fg-accent)&#34; x=&#34;435&#34; y=&#34;75&#34; width=&#34;100&#34; height=&#34;50&#34;/&gt;
  &lt;rect fill=&#34;var(--fg-accent)&#34; x=&#34;565&#34; y=&#34;75&#34; width=&#34;80&#34; height=&#34;50&#34;/&gt;

  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;45&#34; x=&#34;70&#34;&gt;vscode.dev&lt;/text&gt;
  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;45&#34; x=&#34;260&#34;&gt;Web Worker&lt;/text&gt;
  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;45&#34; x=&#34;465&#34;&gt;LSP Server (Web Worker)&lt;/text&gt;
  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;95&#34; x=&#34;185&#34;&gt;Starts&lt;/text&gt;

  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;105&#34; x=&#34;57&#34;&gt;Extension Host&lt;/text&gt;
  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;105&#34; x=&#34;267&#34;&gt;LSP Client&lt;/text&gt;
  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;105&#34; x=&#34;450&#34;&gt;JS Wrapper&lt;/text&gt;
  &lt;text style=&#34;font-size: 0.8rem&#34; y=&#34;105&#34; x=&#34;580&#34;&gt;Pyodide&lt;/text&gt;

  &lt;path marker-end=&#34;url(#arrowright)&#34; stroke=&#34;currentColor&#34; d=&#34;M162 100 L240 100&#34;&gt;&lt;/path&gt;
  &lt;path marker-start=&#34;url(#arrowleft)&#34; marker-end=&#34;url(#arrowright)&#34; stroke=&#34;currentColor&#34; d=&#34;M360 100 L425 100&#34;&gt;&lt;/path&gt;
  &lt;path marker-start=&#34;url(#arrowleft)&#34; marker-end=&#34;url(#arrowright)&#34; stroke=&#34;currentColor&#34; d=&#34;M545 100 L555 100&#34;&gt;&lt;/path&gt;
&lt;/svg&gt;&lt;/section&gt;
&lt;section id=&#34;writing-the-language-client&#34;&gt;
&lt;h3&gt;Writing the Language Client&lt;a class=&#34;headerlink&#34; href=&#34;#writing-the-language-client&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The language client code is pretty straightforward as all the heavy lifting is done
by the &lt;a class=&#34;reference external&#34; href=&#34;https://www.npmjs.com/package/vscode-languageclient&#34;&gt;vscode-languageclient&lt;/a&gt; library.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;npm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;install&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--save&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;vscode-languageclient
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The client code is pretty much identical to code found in the &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/microsoft/vscode-extension-samples/blob/355d5851a8e87301cf814a3d20f3918cb162ff73/lsp-web-extension-sample/client/src/browserClientMain.ts&#34;&gt;sample extension&lt;/a&gt;
I used as reference. All that we have to do it tell the language client which documents
we’re interested in&lt;/p&gt;
&lt;div class=&#34;highlight-typescript notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientOptions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;LanguageClientOptions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;documentSelector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;scheme&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;plaintext&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;outputChannelName&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Hello Language Server&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and since we’re building this for the web, we need to start a web worker that hosts the
language server and pass that to the client also.&lt;/p&gt;
&lt;div class=&#34;highlight-typescript notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Uri&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;joinPath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;extensionUri&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;dist/server.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;worker&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Worker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;toString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;LanguageClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;hello-lsp-web&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Hello LSP&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientOptions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;worker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;subscriptions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onReady&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;then&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;hello-lsp-web server is ready&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;writing-the-language-server&#34;&gt;
&lt;h3&gt;Writing the Language Server&lt;a class=&#34;headerlink&#34; href=&#34;#writing-the-language-server&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The goal of this post is just to get the simplest end-to-end concept working so the
“language server” in this case does barely anything except prove that&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;We can communicate with the client&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can load Pyodide and execute some Python code&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Communication with web workers is achieved through &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#sending_messages_to_and_from_a_dedicated_worker&#34;&gt;sending messages&lt;/a&gt;, so to handle
incoming messages from the client we create an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;onmessage&lt;/span&gt;&lt;/code&gt; event handler and use the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;postMessage&lt;/span&gt;&lt;/code&gt; to send our responses.&lt;/p&gt;
&lt;p&gt;To prove that the communication works, our “language server” handles the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;initialize&lt;/span&gt;&lt;/code&gt;
request to establish the session, but ignores everything else.&lt;/p&gt;
&lt;div class=&#34;highlight-typescript notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onmessage&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;async&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`Client message:`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;method&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;===&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;initialize&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;postMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;jsonrpc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;event.data.id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;serverInfo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Hello, LSP&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;capabilities&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With the communication taken care of, we can focus on setting up Pyodide. Adapting one
of the &lt;a class=&#34;reference external&#34; href=&#34;https://pyodide.org/en/stable/usage/quickstart.html#complete-example&#34;&gt;getting started examples&lt;/a&gt; from the Pyodide documentation and using the
&lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#importing_scripts_and_libraries&#34;&gt;importScripts&lt;/a&gt; function that’s available to web workers it’s relatively
straightforward to load Pyodide from a CDN and initialize it.&lt;/p&gt;
&lt;div class=&#34;highlight-typescript notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;importScripts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyodide.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;async&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;initPyodide&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Initing pyodide.&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* @ts-ignore */&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pyodide&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;await&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;loadPyodide&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;indexURL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;https://cdn.jsdelivr.net/pyodide/v0.18.1/full/&amp;quot;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pyodide&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pyodideReady&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;initPyodide&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Pyodide isn’t exactly a small component to download and especially when we start
pulling in packages, will take some time to initialize. Using a global &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pyodideReady&lt;/span&gt;&lt;/code&gt;
promise we can make any code that depends on pyodide wait until it’s ready to use.&lt;/p&gt;
&lt;div class=&#34;highlight-typescript notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pyodide&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;await&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pyodideReady&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pyodide&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runPython&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;import sys;sys.version&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;packaging-for-the-web&#34;&gt;
&lt;h3&gt;Packaging for the Web&lt;a class=&#34;headerlink&#34; href=&#34;#packaging-for-the-web&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You may have noticed that the code above was written in TypeScript which needs to be
compiled into JavaScript in order to run in the browser. Additionally, due
to the way VSCode &lt;a class=&#34;reference external&#34; href=&#34;https://code.visualstudio.com/api/extension-guides/web-extensions#web-extension-main-file&#34;&gt;handles web extensions&lt;/a&gt; all the code that comprises the language
client (including the dependencies!) needs to be bundled into a single JavaScript file.&lt;/p&gt;
&lt;p&gt;To do this we’ll use &lt;a class=&#34;reference external&#34; href=&#34;https://webpack.js.org/&#34;&gt;webpack&lt;/a&gt; along with a few other tools.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;npm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;install&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--save-dev&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;webpack&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;webpack-cli&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;typescript&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ts-loader&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;@types/vscode&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;path-browserify
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Like most of this setup, the webpack configuration was based on the
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/microsoft/vscode-extension-samples/tree/main/lsp-web-extension-sample&#34;&gt;lsp-web-extension-sample&lt;/a&gt;  where we export 2 configurations, one for the client and
one for the server.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientConfig&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;webworker&amp;#39;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;./src/client&amp;#39;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resolve&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fallback&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resolve&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;path-browserify&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;externals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;vscode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;commonjs vscode&amp;#39;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;serverConfig&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;webworker&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;./src/server&amp;#39;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientConfig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;serverConfig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’ve omitted most of the more standard configuration fields for brevity but you can
look at the &lt;a class=&#34;reference internal&#34; href=&#34;../code/hello-lsp-web/&#34;&gt;&lt;span class=&#34;doc&#34;&gt;code&lt;/span&gt;&lt;/a&gt; for full details though there are a few
things worth mentioning&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Both client and server will be running in web workers so we need to make sure we tell
webpack to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;target:&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;webworker&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The client depends on the VSCode API but it’s not available at build time, so we use
the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;externals&lt;/span&gt;&lt;/code&gt; field to tell webpack to translate any &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;{}&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;&#39;vscode&#39;&lt;/span&gt;&lt;/code&gt;
statements into a CommonJS import.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Node libraries like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;path&lt;/span&gt;&lt;/code&gt;  are not available in the browser, so we use the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;fallback&lt;/span&gt;&lt;/code&gt; field to replace calls to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;path&lt;/span&gt;&lt;/code&gt; library, will calls to the
&lt;a class=&#34;reference external&#34; href=&#34;https://www.npmjs.com/package/path-browserify&#34;&gt;path-browserify&lt;/a&gt; library which implements the same API, but works within the browser.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally to invoke webpack we can add a couple of scripts to our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;package.json&lt;/span&gt;&lt;/code&gt; for
convenience.&lt;/p&gt;
&lt;div class=&#34;highlight-json notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;compile&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;webpack&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;watch&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;webpack --watch&amp;quot;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;trying-it-out&#34;&gt;
&lt;h3&gt;Trying it out&lt;a class=&#34;headerlink&#34; href=&#34;#trying-it-out&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;I don’t fully understand how this section works, thankfully the VSCode devs figured
out these steps and &lt;a class=&#34;reference external&#34; href=&#34;https://code.visualstudio.com/api/extension-guides/web-extensions#test-your-web-extension-in-on-vscode.dev&#34;&gt;wrote them up&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The last step is to actually try to run this extension in the web version of VSCode and
see if it works. Unfortunately testing a web extension is not as straightforward as a
desktop one, but with a few &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;npm&lt;/span&gt;&lt;/code&gt; commands  &lt;em&gt;✨magic happens✨&lt;/em&gt; and the web version
of VSCode is able to install our extension from a simple web server running on
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;localhost&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;First we start by adding a few more scripts to our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;package.json&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-json notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;serve&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;npx serve --cors -l 5000&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;quot;tunnel&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;npx localtunnel -p 5000&amp;quot;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now assuming that we’ve already run &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;npm&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;watch&lt;/span&gt;&lt;/code&gt; or &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;npm&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;compile&lt;/span&gt;&lt;/code&gt; from the
previous section, we run both the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;serve&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;tunnel&lt;/span&gt;&lt;/code&gt; scripts from &lt;strong&gt;two separate
terminals&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;flex flex-col lg-flex-row justify-around docutils container&#34;&gt;
&lt;div class=&#34;overflow-auto highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;npm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;run&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;serve

&lt;span class=&#34;go&#34;&gt;&amp;gt; hello-lsp-web@ serve blog/code/hello-lsp-web&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;&amp;gt; npx serve --cors -l 5000&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;npx: installed 88 in 6.613s&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;┌──────────────────────────────────────────────────┐&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│                                                  │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│   Serving!                                       │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│                                                  │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│   - Local:            http://localhost:5000      │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│   - On Your Network:  http://192.168.0.31:5000   │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│                                                  │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│   Copied local address to clipboard!             │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│                                                  │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;└──────────────────────────────────────────────────┘&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;overflow-auto lg-ml-2 highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;npm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;run&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;tunnel

&lt;span class=&#34;go&#34;&gt;&amp;gt; hello-lsp-web@ tunnel blog/code/hello-lsp-web&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;&amp;gt; npx localtunnel -p 5000&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;npx: installed 22 in 3.043s&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;your url is: https://xxxx-yyyy-zzzz.loca.lt&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then to enable the tunnel we have to visit the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;https://xxxx-yyyy-zzz.loca.lt&lt;/span&gt;&lt;/code&gt;
URL printed by the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;tunnel&lt;/span&gt;&lt;/code&gt; script, which takes us to a “Friendly Reminder” screen
and we click the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Click&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;Continue&lt;/span&gt;&lt;/code&gt; button.&lt;/p&gt;
&lt;figure class=&#34;align-center&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/tunnel_warning.png&#34; src=&#34;https://www.alcarney.me/_images/tunnel_warning.png&#34; /&gt;
&lt;/figure&gt;
&lt;p&gt;Now we can finally open the &lt;a class=&#34;reference external&#34; href=&#34;https://vscode.dev/github/alcarney/blog&#34;&gt;web version&lt;/a&gt; of VSCode itself, open the command palette
with &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;F1&lt;/kbd&gt; and pick the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Developer:&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;Install&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;Web&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;Extension...&lt;/span&gt;&lt;/code&gt; command. When asked
for the URL to install from, we paste the URL given to us from the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;tunnel&lt;/span&gt;&lt;/code&gt;  script
above.&lt;/p&gt;
&lt;figure class=&#34;align-center&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/install_extension.png&#34; src=&#34;https://www.alcarney.me/_images/install_extension.png&#34; /&gt;
&lt;/figure&gt;
&lt;p&gt;With any luck, VSCode should install the extension show it in the installed extensions
list in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Extensions&lt;/span&gt;&lt;/code&gt; tab. All that’s left us to do is actually test the extension!&lt;/p&gt;
&lt;p&gt;As you can probably guess from the code we wrote above, there’s actually not much for
us to test. However, we can open the dev tools as you would on any other website and
create a file &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;test.txt&lt;/span&gt;&lt;/code&gt; if everything works as expected, we should see the following
messages printed to console.&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id1&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/hello-lsp-web.png&#34; src=&#34;https://www.alcarney.me/_images/hello-lsp-web.png&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;Success!&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id1&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;next-steps&#34;&gt;
&lt;h2&gt;Next Steps&lt;a class=&#34;headerlink&#34; href=&#34;#next-steps&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That’s it! We have a very simple proof of concept web extension setup where the language
server component is able to run Python code and communicate with the client. In the next
post I hope to be able to stand up a simple &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/openlawlibrary/pygls&#34;&gt;pygls&lt;/a&gt; language server and have it work
with the online version of VSCode 🤞&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2021/ast-python-frontend/</id>
    <link href="https://www.alcarney.me/blog/2021/ast-python-frontend" rel="alternate" />
    <published>2021-01-13T00:00:00+00:00</published>
    <updated>2021-01-13T00:00:00+00:00</updated>
    <title>Creating a CPython Extension</title>
    <content type="html">
      &lt;section id=&#34;creating-a-cpython-extension&#34;&gt;
&lt;h1&gt;Creating a CPython Extension&lt;a class=&#34;headerlink&#34; href=&#34;#creating-a-cpython-extension&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2020/ast-simple-eval/&#34; title=&#34;Evaluating a Simple Abstract Syntax Tree&#34;&gt;Previously&lt;/a&gt;, as part of my exploration
into how programming languages are implemented, I wrote a very simple AST
evaluator that knew how to add and multiply floats together. Since constructing
these ASTs by hand is quite painful I thought it would be fun to come up with a
frontend to my “programming language” which could do it for me.&lt;/p&gt;
&lt;p&gt;Now your typical frontend would be some kind of parser built into the
compiler/interpreter. However, while I’m definitely interested in parsing I
don’t quite feel like tackling that just yet. Instead I’m going to have Python
be the frontend and embed my toy language into it via a &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/extending/extending.html&#34;&gt;CPython Extension&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;overview&#34;&gt;
&lt;h2&gt;Overview&lt;a class=&#34;headerlink&#34; href=&#34;#overview&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving into the detail I think it would be worth keeping in mind what we
want the end result to be. By the end of this post, we want to have a CPython
extension that allows us to write normal-ish Python code to construct a
representation of some expression&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;ccalc&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expression&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expression&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Multiply&amp;lt;Plus&amp;lt;Literal&amp;lt;1.0&amp;gt;, Literal&amp;lt;2.0&amp;gt;&amp;gt;, Literal&amp;lt;3.0&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and then be able to pass this expression to the AST evaluator we wrote in the
previous post and have it compute the result&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;eval_ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expression&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;9.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you’d rather skip all the exposition you can find the final codebase&lt;/p&gt;
&lt;p&gt;We can break the implementation down into 3 main steps&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2021/ast-python-frontend/#ast-python-frontend-ast-repr&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Constructing an AST Representation&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We need an equivalent Python representation to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode&lt;/span&gt;&lt;/code&gt; structure,
allowing the user to express the expression they want computed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2021/ast-python-frontend/#ast-python-frontend-ext-setup&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Setting up the C Extension&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Before we can get to the fun part, there’s some setup required to get a
CPython extension up and running.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2021/ast-python-frontend/#ast-python-frontend-conversions&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Converting Between Python and C&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally we need to write the code that converts the Python representation into
the C representation, passing it off to the evaluator before converting the
result back into Python.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;constructing-an-ast-representation&#34;&gt;
&lt;span id=&#34;ast-python-frontend-ast-repr&#34;&gt;&lt;/span&gt;&lt;h2&gt;Constructing an AST Representation&lt;a class=&#34;headerlink&#34; href=&#34;#constructing-an-ast-representation&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To represent the AST in Python code we can create a class that captures the same
information as our &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2020/ast-simple-eval/#ast-simple-eval-ast-repr&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;AstNode&lt;/span&gt;&lt;/a&gt; struct from the C code&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;

   &lt;span class=&#34;n&#34;&gt;LITERAL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;PLUS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;MULTIPLY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;From there it’s simple enough to create some subclasses that help us fill out
the correct fields.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;nb&#34;&gt;super&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Plus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;nb&#34;&gt;super&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PLUS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Multiply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;nb&#34;&gt;super&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MULTIPLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Technically that’s all we need but we haven’t really gained anything in terms of
usability, constructing an AST from the classes we have defined so far would be
just as painful as it was in C.&lt;/p&gt;
&lt;p&gt;Thankfully though, we don’t have to stop here, by taking advantage of being able
to define implementations for arithmetic operations on our custom types we can
introduce a much nicer method of constructing expressions.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;

      &lt;span class=&#34;c1&#34;&gt;# Automatically convert python numbers to Literal(x) AST nodes&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;isinstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;isinstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__add__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Plus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__radd__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Plus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__mul__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Multiply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__rmul__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Multiply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now if we wanted to construct an expression we can do so with fairly
straightforward Python code.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;ccalc&lt;/span&gt;

&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Multiply&amp;lt;Plus&amp;lt;Literal&amp;lt;1.0&amp;gt;, Literal&amp;lt;2.0&amp;gt;&amp;gt;, Literal&amp;lt;3.0&amp;gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Plus&amp;lt;Literal&amp;lt;1.0&amp;gt;, Literal&amp;lt;6.0&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, as shown with the second example above we need to be careful when
choosing the number to wrap in our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ccalc.Literal&lt;/span&gt;&lt;/code&gt; class if we want to “catch”
the expression and construct our AST rather than have Python compute the value
directly&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Plus&amp;lt;Literal&amp;lt;1.0&amp;gt;, Multiply&amp;lt;Literal&amp;lt;2.0&amp;gt;, Literal&amp;lt;3.0&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;setting-up-the-c-extension&#34;&gt;
&lt;span id=&#34;ast-python-frontend-ext-setup&#34;&gt;&lt;/span&gt;&lt;h2&gt;Setting up the C Extension&lt;a class=&#34;headerlink&#34; href=&#34;#setting-up-the-c-extension&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using &lt;a class=&#34;reference external&#34; href=&#34;https://realpython.com/build-python-c-extension-module/&#34;&gt;this tutorial&lt;/a&gt; from Real Python as a guide I was able
to get a C Extension up and running surprisingly easily. Be sure to check out
the article for details but in short I ended up creating the following directory
structure&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;.
├── ccalc
│   └── __init__.py
├── ccalcmodule.c
└── setup.py
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;__init__.py&lt;/span&gt;&lt;/code&gt; file contains the Python code we wrote in the previous
section and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ccalcmodule.c&lt;/span&gt;&lt;/code&gt; contains the boilerplate needed to define a Python
module&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define PY_SSIZE_T_CLEAN&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cpf&#34;&gt;&amp;lt;Python.h&amp;gt;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;PyModuleDef&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalcmodule&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyModuleDef_HEAD_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;_ccalc&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Simple calculator implemented in C&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;-1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc_methods&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;PyMODINIT_FUNC&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;PyInit__ccalc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyModule_Create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalcmodule&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyModuleDef&lt;/span&gt;&lt;/code&gt; struct as the name implies, defines some basic information
about the module&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;It’s name &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;_ccalc&lt;/span&gt;&lt;/code&gt;, specifies what our module is called when we &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;import&lt;/span&gt;&lt;/code&gt;
it in regular Python code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The next argument is the module’s docstring&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;-1&lt;/span&gt;&lt;/code&gt; is something to do with sub-interpreters?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ccalc_methods&lt;/span&gt;&lt;/code&gt; is an array of structs delcaring all the functions this module
exposes to the interpreter.️&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Something that caught me out is that the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyInit_&amp;lt;module&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;name&amp;gt;&lt;/span&gt;&lt;/code&gt; function &lt;em&gt;must&lt;/em&gt;
match the name we gave the module in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyModuleDef&lt;/span&gt;&lt;/code&gt;,  since the module name is
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;_ccalc&lt;/span&gt;&lt;/code&gt; I needed an additional &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;_&lt;/span&gt;&lt;/code&gt; character in the name so that the module can
be registered correctly.&lt;/p&gt;
&lt;p&gt;The methods declared in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ccalc_methods&lt;/span&gt;&lt;/code&gt; array follow a similar pattern&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyMethodDef&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc_methods&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;hello_world&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method_hello_world&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;METH_VARARGS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Print &amp;#39;Hello, World!&amp;#39;.&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// I think this is required so that Python knows when&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;                         &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// it&amp;#39;s reached the end of the array&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;hello_world&lt;/span&gt;&lt;/code&gt; is the name we want regular Python code to use when calling this
method&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;method_hello_world&lt;/span&gt;&lt;/code&gt; is the name of the function in our C code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;METH_VARARGS&lt;/span&gt;&lt;/code&gt; tells Python the kinds of arguments our function should be
called with. Check out the &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/extending/extending.html#the-module-s-method-table-and-initialization-function&#34;&gt;documentation&lt;/a&gt; for more details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The final parameter sets the docstring for the function&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally we need the the actual method definition itself.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;method_hello_world&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Hello, World!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Py_RETURN_NONE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;section id=&#34;building-the-extension&#34;&gt;
&lt;h3&gt;Building the Extension&lt;a class=&#34;headerlink&#34; href=&#34;#building-the-extension&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To my surprise, this was the easiest step of them all. Rather than worrying
about writing a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Makefile&lt;/span&gt;&lt;/code&gt; or providing the right flags to link against my
version of Python, it turns out that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;setuptools&lt;/span&gt;&lt;/code&gt; takes care of all those
details.&lt;/p&gt;
&lt;p&gt;All I had to do was write a standard &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;setup.py&lt;/span&gt;&lt;/code&gt; file, just with some additional
information about the extension itself&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;setuptools&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Extension&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;ccalcmod&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Extension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;_ccalc&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sources&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;ccalcmodule.c&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;ccalc&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;A simple calculator implemented in C&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;packages&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;ccalc&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;ext_modules&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalcmod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With the packaging defined a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;setup.py&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;install&lt;/span&gt;&lt;/code&gt; was all that was needed
to build and install the extension into my virtual environment.&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;(.env) $ python setup.py install&lt;/summary&gt;&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;running install
running bdist_egg
running egg_info
creating ccalc.egg-info
writing ccalc.egg-info/PKG-INFO
writing dependency_links to ccalc.egg-info/dependency_links.txt
writing top-level names to ccalc.egg-info/top_level.txt
writing manifest file &amp;#39;ccalc.egg-info/SOURCES.txt&amp;#39;
reading manifest file &amp;#39;ccalc.egg-info/SOURCES.txt&amp;#39;
writing manifest file &amp;#39;ccalc.egg-info/SOURCES.txt&amp;#39;
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_py
creating build
creating build/lib.linux-x86_64-3.8
creating build/lib.linux-x86_64-3.8/ccalc
copying ccalc/__init__.py -&amp;gt; build/lib.linux-x86_64-3.8/ccalc
running build_ext
building &amp;#39;_ccalc&amp;#39; extension
creating build/temp.linux-x86_64-3.8
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/home/alex/Projects/scratch/.env/include -I/usr/include/python3.8 -c ccalcmodule.c -o build/temp.linux-x86_64-3.8/ccalcmodule.o
x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.8/ccalcmodule.o -o build/lib.linux-x86_64-3.8/_ccalc.cpython-38-x86_64-linux-gnu.so
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/egg
creating build/bdist.linux-x86_64/egg/ccalc
copying build/lib.linux-x86_64-3.8/ccalc/__init__.py -&amp;gt; build/bdist.linux-x86_64/egg/ccalc
copying build/lib.linux-x86_64-3.8/_ccalc.cpython-38-x86_64-linux-gnu.so -&amp;gt; build/bdist.linux-x86_64/egg
byte-compiling build/bdist.linux-x86_64/egg/ccalc/__init__.py to __init__.cpython-38.pyc
creating stub loader for _ccalc.cpython-38-x86_64-linux-gnu.so
byte-compiling build/bdist.linux-x86_64/egg/_ccalc.py to _ccalc.cpython-38.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying ccalc.egg-info/PKG-INFO -&amp;gt; build/bdist.linux-x86_64/egg/EGG-INFO
copying ccalc.egg-info/SOURCES.txt -&amp;gt; build/bdist.linux-x86_64/egg/EGG-INFO
copying ccalc.egg-info/dependency_links.txt -&amp;gt; build/bdist.linux-x86_64/egg/EGG-INFO
copying ccalc.egg-info/top_level.txt -&amp;gt; build/bdist.linux-x86_64/egg/EGG-INFO
writing build/bdist.linux-x86_64/egg/EGG-INFO/native_libs.txt
zip_safe flag not set; analyzing archive contents...
__pycache__._ccalc.cpython-38: module references __file__
creating dist
creating &amp;#39;dist/ccalc-1.0.0-py3.8-linux-x86_64.egg&amp;#39; and adding &amp;#39;build/bdist.linux-x86_64/egg&amp;#39; to it
removing &amp;#39;build/bdist.linux-x86_64/egg&amp;#39; (and everything under it)
Processing ccalc-1.0.0-py3.8-linux-x86_64.egg
removing &amp;#39;/home/alex/Projects/scratch/.env/lib/python3.8/site-packages/ccalc-1.0.0-py3.8-linux-x86_64.egg&amp;#39; (and everything under it)
creating /home/alex/Projects/scratch/.env/lib/python3.8/site-packages/ccalc-1.0.0-py3.8-linux-x86_64.egg
Extracting ccalc-1.0.0-py3.8-linux-x86_64.egg to /home/alex/Projects/scratch/.env/lib/python3.8/site-packages
ccalc 1.0.0 is already the active version in easy-install.pth

Installed /home/alex/Projects/scratch/.env/lib/python3.8/site-packages/ccalc-1.0.0-py3.8-linux-x86_64.egg
Processing dependencies for ccalc==1.0.0
Finished processing dependencies for ccalc==1.0.0
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;&lt;p&gt;With the C code sorted and building, we can import it in Python code and call
functions from it just as we would with any other module.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;_ccalc&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hello_world&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Hello, World!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;converting-between-python-and-c&#34;&gt;
&lt;span id=&#34;ast-python-frontend-conversions&#34;&gt;&lt;/span&gt;&lt;h2&gt;Converting Between Python and C&lt;a class=&#34;headerlink&#34; href=&#34;#converting-between-python-and-c&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now for the fun part! It’s time to write a method for our extension module
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;method_eval_ast&lt;/span&gt;&lt;/code&gt; that takes a Python representation of the AST and converts it
into our C representation before executing it and passing the result back up to
Python.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;method_eval_ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Be sure to expose the new method to the module&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyMethodDef&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc_methods&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;eval_ast&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method_eval_ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;METH_VARARGS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Evaluate the given ast.&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This can be broken down into a three step process&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2021/ast-python-frontend/#ast-python-frontend-function-args&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Parsing Function Arguments&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2021/ast-python-frontend/#ast-python-frontend-c-ast&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Constructing the C AST&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2021/ast-python-frontend/#ast-python-frontend-return&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;Returning the Result&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&#34;parsing-function-arguments&#34;&gt;
&lt;span id=&#34;ast-python-frontend-function-args&#34;&gt;&lt;/span&gt;&lt;h3&gt;Parsing Function Arguments&lt;a class=&#34;headerlink&#34; href=&#34;#parsing-function-arguments&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When writing a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;METH_VARARGS&lt;/span&gt;&lt;/code&gt; style function, it gets called with 2 parameters
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;self&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;args&lt;/span&gt;&lt;/code&gt;. &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;self&lt;/span&gt;&lt;/code&gt; in this case is a reference to our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;_ccalc&lt;/span&gt;&lt;/code&gt; module and
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;args&lt;/span&gt;&lt;/code&gt; is a reference to a tuple containing the arguments that were passed to
our function.&lt;/p&gt;
&lt;p&gt;As the contents of this tuple can be arbitrary it’s up to our code to correctly
interpret the values that have been given to it. Thankfully Python provides a
handy function &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyArg_ParseTuple&lt;/span&gt;&lt;/code&gt; that can take care of this for us.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyArg_ParseTuple&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;O&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This function takes a &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/c-api/arg.html#parsing-arguments&#34;&gt;format string&lt;/a&gt; that specifies the
number and type of arguments we expect to be given. In this case &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;quot;O&amp;quot;&lt;/span&gt;&lt;/code&gt; says that
we want to take a single object - our AST. We also need to pass the correct
number of pointers into this function so that it can “return” the parsed values
to us.&lt;/p&gt;
&lt;p&gt;In the case of invalid arguments being given, this function will set the global
error indicator for us with the correct error message. So all that would be left
for us to do is to return &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;NULL&lt;/span&gt;&lt;/code&gt; which indicates to the code calling us that
there was an error. See the documentation on &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/c-api/exceptions.html&#34;&gt;error handling&lt;/a&gt; for more details&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;constructing-the-c-ast&#34;&gt;
&lt;span id=&#34;ast-python-frontend-c-ast&#34;&gt;&lt;/span&gt;&lt;h3&gt;Constructing the C AST&lt;a class=&#34;headerlink&#34; href=&#34;#constructing-the-c-ast&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With a reference to the Python object that (hopefully!) represents a valid AST
it’s time to do the conversion into our C representation. To do this we’ll write
a function dedicated to handling the conversion and call it from
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;method_eval_ast&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstTree_FromPyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The first step is to dynamically allocate enough memory to store the C
representation. Easy enough to do, assuming that you know the size of the
tree…&lt;/p&gt;
&lt;section id=&#34;allocating-memory&#34;&gt;
&lt;h4&gt;Allocating Memory&lt;a class=&#34;headerlink&#34; href=&#34;#allocating-memory&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;It took me a while to realise it, but even though we’re writing C code we are
still within the Python interpreter. This means we still have access to all the standard
Python functions - we just need to look up their C equivalents. Why not just ask the
tree itself how big it is by calling &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;len()&lt;/span&gt;&lt;/code&gt; on it?&lt;/p&gt;
&lt;p&gt;After a quick trip to the documentation I discover that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;len&lt;/span&gt;&lt;/code&gt; is “spelt”
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyObject_Length&lt;/span&gt;&lt;/code&gt; in the C API, add some of the required book keeping and we
should be able to allocate enough space&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;AstTree_FromPyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Py_ssize_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num_nodes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject_Length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num_nodes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;-1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num_nodes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Something important to note here, up until now we’ve been calling into the
Python C API which has been taking care of reporting any errors it encounters.
However, the call to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;malloc&lt;/span&gt;&lt;/code&gt; is now our code and it’s our responsibility to
correctly report any errors we counter.&lt;/p&gt;
&lt;p&gt;If we were to leave the code as is and this call to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;malloc&lt;/span&gt;&lt;/code&gt; fails, Python would
know that an error had occured but not be able to tell the user what was wrong.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;ccalc&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;_ccalc&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;eval_ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;gt&#34;&gt;Traceback (most recent call last):&lt;/span&gt;
&lt;span class=&#34;gr&#34;&gt;   File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;&lt;/span&gt;
&lt;span class=&#34;gr&#34;&gt;SystemError&lt;/span&gt;: &lt;span class=&#34;n&#34;&gt;&amp;lt;built-in function eval_ast&amp;gt; returned NULL without setting an error&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Instead we also need to call &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyErr_SetString&lt;/span&gt;&lt;/code&gt; to raise the appropriate
exception that describes our error.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num_nodes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyErr_SetString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyExc_MemoryError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Unable to allocate memory for the AST.&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With the information set, Python is able to report a much better error
message to the user&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;ccalc&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;_ccalc&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;eval_ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;gt&#34;&gt;Traceback (most recent call last):&lt;/span&gt;
&lt;span class=&#34;gr&#34;&gt;   File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;&lt;/span&gt;
&lt;span class=&#34;gr&#34;&gt;MemoryError&lt;/span&gt;: &lt;span class=&#34;n&#34;&gt;Unable to allocate memory&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally let’s not forget to jump back to the Python code and implement &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;__len__&lt;/span&gt;&lt;/code&gt;
on our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode&lt;/span&gt;&lt;/code&gt; class.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__len__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;inspecting-nodes&#34;&gt;
&lt;h4&gt;Inspecting Nodes&lt;a class=&#34;headerlink&#34; href=&#34;#inspecting-nodes&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;With the memory to hold the tree allocated it’s time to start on the actual
conversion. To handle this we’ll write another function &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode_FromPyObject&lt;/span&gt;&lt;/code&gt;
that we can recursively call whenever we need to descend down a branch. This
function will take a reference &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;obj&lt;/span&gt;&lt;/code&gt; to the Python representation of the node
we’re currently converting, another reference &lt;cite&gt;ast&lt;/cite&gt; to the memory we allocated
and finally an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;index&lt;/span&gt;&lt;/code&gt; into the array that we should write the node to.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;AstNode_FromPyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Py_ssize_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;astindex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The first step in the process is to determine the type of node we are
converting, which we can do by inspecting the value of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;type&lt;/span&gt;&lt;/code&gt; field.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject_GetAttrString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node_type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyLong_AsLong&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Py_DECREF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The call to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyObject_GetAttrString&lt;/span&gt;&lt;/code&gt; is equivalent to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;obj.type&lt;/span&gt;&lt;/code&gt; in Python and
returns a &lt;strong&gt;new reference&lt;/strong&gt; to a generic Python object. In order to get an
actual number we need to use &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyLong_AsLong&lt;/span&gt;&lt;/code&gt; to convert it.&lt;/p&gt;
&lt;p&gt;In theory &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;type&lt;/span&gt;&lt;/code&gt; could be a reference to anything, so there’s always the chance
that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyLong_AsLong&lt;/span&gt;&lt;/code&gt; could fail in which case it would return &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;-1&lt;/span&gt;&lt;/code&gt;. As stated in
&lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/c-api/long.html?highlight=aslong#c.PyLong_AsLong&#34;&gt;the documentation&lt;/a&gt; we should really be performing extra checks here to determine
if the value is actually &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;-1&lt;/span&gt;&lt;/code&gt; or if there was an error but I’ve decided to omit
those for now.&lt;/p&gt;
&lt;p&gt;Something else to note is that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;type&lt;/span&gt;&lt;/code&gt; was a &lt;strong&gt;new reference&lt;/strong&gt; and since Python
uses &lt;a class=&#34;reference external&#34; href=&#34;https://en.wikipedia.org/wiki/Reference_counting&#34;&gt;Reference Counting&lt;/a&gt; internally it’s our responsibility to decrement the
count (using &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Py_DECREF&lt;/span&gt;&lt;/code&gt;) when we are finished with it - at least that’s what I
think should be done based on what I found in the documentation on &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/extending/extending.html#ownership-rules&#34;&gt;ownership&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;converting-the-node&#34;&gt;
&lt;h3&gt;Converting the Node&lt;a class=&#34;headerlink&#34; href=&#34;#converting-the-node&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we have an integer &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;node_type&lt;/span&gt;&lt;/code&gt; that corresponds with one of the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNodeType&lt;/span&gt;&lt;/code&gt; enum entries we can use a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;switch&lt;/span&gt;&lt;/code&gt; statement and start writing the
conversion code for each type in turn.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject_GetAttrString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyFloat_AsDouble&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Py_DECREF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Considering the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Literal&lt;/span&gt;&lt;/code&gt; node types first, we can follow a very similar process
to the previous section to extract the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;value&lt;/span&gt;&lt;/code&gt; field from the node giving us
enough information to fill out our first &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode&lt;/span&gt;&lt;/code&gt; instance!&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As this node type has no children there’s no further work to do and we can
return successfully. However, in the case of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_PLUS&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;/code&gt;
things aren’t as straightforward…&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;traversing-the-tree&#34;&gt;
&lt;h3&gt;Traversing the Tree&lt;a class=&#34;headerlink&#34; href=&#34;#traversing-the-tree&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Handling the other node types starts off easy enough, since  they are almost
identical we can handle their differences in the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;switch&lt;/span&gt;&lt;/code&gt; statement and then use
the remainder of the function to handle recursing down both the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;left&lt;/span&gt;&lt;/code&gt; and
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;right&lt;/span&gt;&lt;/code&gt; branches.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_PLUS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_PLUS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We can then get references to the child nodes in the same way we’ve been
referencing all the other fields so far&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject_GetAttrString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;PyObject&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyObject_GetAttrString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;right&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then “all” that is left to do is set the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;left&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;right&lt;/span&gt;&lt;/code&gt; pointers on the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode&lt;/span&gt;&lt;/code&gt; struct and call &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode_FromPyObject&lt;/span&gt;&lt;/code&gt; on each branch - remembering to
adjust the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;index&lt;/span&gt;&lt;/code&gt; value accordingly.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode_FromPyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode_FromPyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;At least… that’s what I wanted to do initially, unfortunately this solution
wouldn’t work in practice,. If &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;left&lt;/span&gt;&lt;/code&gt; is a reference to anything other than an
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;/code&gt; then it’s children would be overwritten when we start processing
nodes on the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;right&lt;/span&gt;&lt;/code&gt; branch!&lt;/p&gt;
&lt;p&gt;This had me scratching my head for quite a while, trying to come up with a way
to compute the correct offset for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;right&lt;/span&gt;&lt;/code&gt; branch - without success.&lt;/p&gt;
&lt;p&gt;Instead, since this is C I ended up changing the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;index&lt;/span&gt;&lt;/code&gt; argument from an actual
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Py_ssize_t&lt;/span&gt;&lt;/code&gt; to a pointer to one. This allows recursive calls to increment the
index as needed and by the time execution returns to the top level function, the
value referenced by the pointer is automatically the correct value.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode_FromPyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode_FromPyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I have no idea if this is a terrible idea for real world scenarios, but it seems
to work well enough for this at least.&lt;/p&gt;
&lt;p&gt;To complete the conversion code, all that remains is to make the initial call to
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode_FromPyObject&lt;/span&gt;&lt;/code&gt; from our main &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstTree_FromPyObject&lt;/span&gt;&lt;/code&gt;  function&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Py_ssize_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstTree_FromPyObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;returning-the-result&#34;&gt;
&lt;span id=&#34;ast-python-frontend-return&#34;&gt;&lt;/span&gt;&lt;h3&gt;Returning the Result&lt;a class=&#34;headerlink&#34; href=&#34;#returning-the-result&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Phew! That was a lot of work but we’re almost there. We just need to add a few
more lines to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;method_eval_ast&lt;/span&gt;&lt;/code&gt; that takes the newly constructed AST and
evaluates it, before converting the result into a Python float and returning it.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_evaluate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PyFloat_FromDouble&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That’s the C Extension finished, the only thing we could do is import the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;_ccalc&lt;/span&gt;&lt;/code&gt; module from &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ccalc&lt;/span&gt;&lt;/code&gt; and expose the methods we want to present a unified
interface to users of the module.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# In ccalc/__init__.py&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;_ccalc&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;eval_ast&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;eval_ast&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And that way we can now make the example code from the start of this post
actually work!&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;ccalc&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expression&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Literal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expression&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Multiply&amp;lt;Plus&amp;lt;Literal&amp;lt;1.0&amp;gt;, Literal&amp;lt;2.0&amp;gt;&amp;gt;, Literal&amp;lt;3.0&amp;gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;gp&#34;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ccalc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;eval_ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expression&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;9.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;final-thoughts&#34;&gt;
&lt;h2&gt;Final Thoughts&lt;a class=&#34;headerlink&#34; href=&#34;#final-thoughts&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There was a lot of code flying around in this post, if you want to see the final
result in its entirety you can find it&lt;/p&gt;
&lt;section id=&#34;best-practice&#34;&gt;
&lt;h3&gt;Best Practice?&lt;a class=&#34;headerlink&#34; href=&#34;#best-practice&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was my first CPython extension so I might be missing out on some best
practices, for example a question I had was around my use of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;malloc&lt;/span&gt;&lt;/code&gt; and
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;free&lt;/span&gt;&lt;/code&gt;. While writing this section I found the documentation on &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/c-api/memory.html&#34;&gt;memory management&lt;/a&gt;
and it appears that the recommendation is to use the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyMem_*&lt;/span&gt;&lt;/code&gt; family of
functions, even for allocations that are not &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;PyObjects&lt;/span&gt;&lt;/code&gt;. However it looks
like there is a learning curve to these as some functions require holding
the &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/glossary.html#term-global-interpreter-lock&#34;&gt;GIL&lt;/a&gt; and some don’t.&lt;/p&gt;
&lt;p&gt;Hmm… speaking of the GIL, should this extension be acquiring it at any point?
🤔&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;another-approach&#34;&gt;
&lt;h3&gt;Another approach&lt;a class=&#34;headerlink&#34; href=&#34;#another-approach&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another note worth mentioning is that it looks like it’s possible to
&lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/extending/newtypes_tutorial.html&#34;&gt;define custom types&lt;/a&gt; directly in C. This means it should be possible to extend
the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode&lt;/span&gt;&lt;/code&gt; C struct to be an object than can be manipulated directly from
Python code - bypassing the need for all the conversion code we had to write.&lt;/p&gt;
&lt;p&gt;However, I decided against this approach mainly because the “convert between the
representations” approach means we get to evolve the Python and C
representations semi independently. Assuming that the Python representation
exposes the correct fields then any method of generating the AST from Python is
perfectly valid.&lt;/p&gt;
&lt;p&gt;Anyway, I think this post has gone on long enough I hope you found it useful and
I’ll see you in the next one!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2020/ast-simple-eval/</id>
    <link href="https://www.alcarney.me/blog/2020/ast-simple-eval" rel="alternate" />
    <published>2020-12-17T00:00:00+00:00</published>
    <updated>2020-12-17T00:00:00+00:00</updated>
    <title>Evaluating a Simple Abstract Syntax Tree</title>
    <content type="html">
      &lt;section id=&#34;evaluating-a-simple-abstract-syntax-tree&#34;&gt;
&lt;h1&gt;Evaluating a Simple Abstract Syntax Tree&lt;a class=&#34;headerlink&#34; href=&#34;#evaluating-a-simple-abstract-syntax-tree&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;Programming languages and their implementation is a topic I’ve been interested
in for a long time and I thought it would be worth trying to get a bit more
hands on and play with some of the ideas in this space. Choosing a topic
somewhat at random I’ve chosen to take a look at implementing an Abstract Syntax
Tree (AST).&lt;/p&gt;
&lt;/div&gt;
&lt;dl class=&#34;simple&#34;&gt;
&lt;dt&gt;30/12/2025&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;Edited this post to&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;Reorganise code snippets so that we can use the current snapshot version of &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/swyddfa/awdur&#34;&gt;awdur&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add section on printing the AST&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Convert mermaid diagrams to SVG&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;section id=&#34;what-is-an-abstract-syntax-tree&#34;&gt;
&lt;h2&gt;What is an Abstract Syntax Tree?&lt;a class=&#34;headerlink&#34; href=&#34;#what-is-an-abstract-syntax-tree&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An &lt;a class=&#34;reference external&#34; href=&#34;https://en.wikipedia.org/wiki/Abstract_syntax_tree&#34;&gt;Abstract Syntax Tree&lt;/a&gt; is a way to represent a program’s source
code within an interpreter/compiler. Consider an expression like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;2&lt;/span&gt;&lt;/code&gt;, it
could be represented by the following tree.&lt;/p&gt;
&lt;style&gt;
  .diagram rect,
  .diagram line,
  .diagram path { stroke: var(--fg-main); stroke-width: 0.5px; fill: none; }
  .diagram text { fill: var(--fg-main); }
&lt;/style&gt;

&lt;svg class=&#34;diagram&#34; width=&#34;100%&#34; viewBox=&#34;-80 -45 160 90&#34; style=&#34;aspect-ratio: 16/9;&#34;  &gt;
  &lt;rect x=&#34;-10&#34; y=&#34;-40&#34; width=&#34;20&#34; height=&#34;25&#34;&gt;&lt;/rect&gt;
  &lt;rect x=&#34;-50&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34;&gt;&lt;/rect&gt;
  &lt;rect x=&#34;30&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34;&gt;&lt;/rect&gt;

  &lt;text x=&#34;-5&#34; y=&#34;-22&#34;&gt;+&lt;/text&gt;
  &lt;text x=&#34;-44&#34; y=&#34;28&#34;&gt;1&lt;/text&gt;
  &lt;text x=&#34;35.5&#34; y=&#34;28&#34;&gt;2&lt;/text&gt;

  &lt;path d=&#34;M -10 -28 Q -30 -20 -40 10&#34; /&gt;
  &lt;path d=&#34;M 10 -28 Q 30 -20  40 10&#34; /&gt;
&lt;/svg&gt;&lt;p&gt;One of the nice things about ASTs is that they remove some of the ambiguity that
can exist in plain text. Consider the expression &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;3&lt;/span&gt;&lt;/code&gt;, there are two ways
to interpret it and depending on which you choose you will get a different
result - either &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;(1&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;2)&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;9&lt;/span&gt;&lt;/code&gt; or &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;(2&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;3)&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;7&lt;/span&gt;&lt;/code&gt; (rules like &lt;a class=&#34;reference external&#34; href=&#34;https://en.wikipedia.org/wiki/Order_of_operations#Mnemonics&#34;&gt;BODMAS&lt;/a&gt;
dictate that we should choose the second version but there’s still a choice).
This choice gets encoded into the structure of tree itself&lt;/p&gt;
&lt;svg class=&#34;diagram&#34; width=&#34;100%&#34; viewBox=&#34;-160 -90 340 180&#34; style=&#34;aspect-ratio: 16/9;&#34;  &gt;
  &lt;g transform=&#34;translate(-60, -20)&#34;&gt;
    &lt;text x=&#34;-60&#34; y=&#34;-50&#34; style=&#34;font-family: monospace; font-size: 8pt&#34;&gt;(1 + 2) * 3&lt;/text&gt;
    &lt;rect x=&#34;-100&#34; y=&#34;-60&#34; width=&#34;160&#34; height=&#34;160&#34; /&gt;
    &lt;rect x=&#34;-10&#34; y=&#34;-40&#34; width=&#34;20&#34; height=&#34;25&#34;&gt;&lt;/rect&gt;
    &lt;text x=&#34;-4&#34; y=&#34;-20&#34;&gt;*&lt;/text&gt;
    &lt;g&gt;
      &lt;rect x=&#34;-50&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34; /&gt;
      &lt;rect x=&#34;30&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34; /&gt;

      &lt;text x=&#34;-45&#34; y=&#34;28&#34;&gt;+&lt;/text&gt;
      &lt;text x=&#34;35.5&#34; y=&#34;28&#34;&gt;3&lt;/text&gt;

      &lt;path d=&#34;M -10 -28 Q -30 -20 -40 10&#34; /&gt;
      &lt;path d=&#34;M 10 -28 Q 30 -20  40 10&#34; /&gt;
    &lt;/g&gt;
    &lt;g transform=&#34;translate(-40,50)&#34;&gt;
      &lt;rect x=&#34;-50&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34; /&gt;
      &lt;rect x=&#34;30&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34; /&gt;

      &lt;text x=&#34;-44&#34; y=&#34;28&#34;&gt;1&lt;/text&gt;
      &lt;text x=&#34;35.5&#34; y=&#34;28&#34;&gt;2&lt;/text&gt;

      &lt;path d=&#34;M -10 -28 Q -30 -20 -40 10&#34; /&gt;
      &lt;path d=&#34;M 10 -28 Q 30 -20  40 10&#34; /&gt;
    &lt;/g&gt;
  &lt;/g&gt;

  &lt;g transform=&#34;translate(70, -20) scale(-1,1)&#34;&gt;
    &lt;text x=&#34;-10&#34; y=&#34;-50&#34; transform=&#34;scale(-1, 1)&#34; style=&#34;font-family: monospace; font-size: 8pt&#34;&gt;1 + (2 * 3)&lt;/text&gt;
    &lt;rect x=&#34;-100&#34; y=&#34;-60&#34; width=&#34;160&#34; height=&#34;160&#34; /&gt;
    &lt;rect x=&#34;-10&#34; y=&#34;-40&#34; width=&#34;20&#34; height=&#34;25&#34;&gt;&lt;/rect&gt;
    &lt;text x=&#34;-5&#34; y=&#34;-22&#34;&gt;+&lt;/text&gt;
    &lt;g&gt;
      &lt;rect x=&#34;-50&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34; /&gt;
      &lt;rect x=&#34;30&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34; /&gt;

      &lt;text x=&#34;-44&#34; y=&#34;28&#34; transform=&#34;scale(-1,1)&#34;&gt;1&lt;/text&gt;
      &lt;text x=&#34;36&#34; y=&#34;29&#34; transform=&#34;scale(-1,1)&#34;&gt;*&lt;/text&gt;

      &lt;path d=&#34;M -10 -28 Q -30 -20 -40 10&#34; /&gt;
      &lt;path d=&#34;M 10 -28 Q 30 -20  40 10&#34; /&gt;
    &lt;/g&gt;
    &lt;g transform=&#34;translate(-40,50)&#34;&gt;
      &lt;rect x=&#34;-50&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34; /&gt;
      &lt;rect x=&#34;30&#34; y=&#34;10&#34; width=&#34;20&#34; height=&#34;25&#34; /&gt;

      &lt;text x=&#34;-44&#34; y=&#34;28&#34; transform=&#34;scale(-1,1)&#34;&gt;2&lt;/text&gt;
      &lt;text x=&#34;35.5&#34; y=&#34;28&#34; transform=&#34;scale(-1,1)&#34;&gt;3&lt;/text&gt;

      &lt;path d=&#34;M -10 -28 Q -30 -20 -40 10&#34; /&gt;
      &lt;path d=&#34;M 10 -28 Q 30 -20  40 10&#34; /&gt;
    &lt;/g&gt;
  &lt;/g&gt;

&lt;/svg&gt;&lt;p&gt;Encoding a program in this way allows the interpreter/compiler to focus on the
semantic meaning of the program without having to worry about the finer details
of how that program happens to be written down.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;representing-the-ast&#34;&gt;
&lt;span id=&#34;ast-simple-eval-ast-repr&#34;&gt;&lt;/span&gt;&lt;h2&gt;Representing the AST&lt;a class=&#34;headerlink&#34; href=&#34;#representing-the-ast&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For no particular reason other than I fancied trying it, I decided to use C to represent my AST.
In order to encode the example trees above, we’ll need three node types&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_PLUS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNodeType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Where each node is represented by the following struct.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;_ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* The type of node this represents e.g.&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;       a literal, an operator etc. */&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNodeType&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* In the case of a literal value, this field&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;       holds the actual value */&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* In the case of an operator, this pointer&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;       refers to the left child node */&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;_ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* In the case of an operator, this pointer&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;       refers to the right child node */&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;_ast&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Although the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;typedef&lt;/span&gt;&lt;/code&gt; will let us refer to this struct using the name &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AstNode&lt;/span&gt;&lt;/code&gt;
from here on out, this name does not exist within the body of the struct
definition itself. In order to have the struct hold pointers to other instances
of the same type it’s necessary to also name the struct definition &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;_ast&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;printing-the-ast&#34;&gt;
&lt;h2&gt;Printing the AST&lt;a class=&#34;headerlink&#34; href=&#34;#printing-the-ast&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Keeping things simple, we can recurse over all the nodes and print a single line representation of each node.
By indenting each line according to its depth in the tree, it should be possible to visually parse the structure.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;ast_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;  &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When printing an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;/code&gt; node, it’s enough to just print the contained value&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;%.2f&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_PLUS&lt;/span&gt;&lt;/code&gt; nodes, we need to print a representation of the operation and then recurse down both branches of the tree.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_PLUS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;+&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Similarly for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;/code&gt; nodes.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;*&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;evaluating-the-ast&#34;&gt;
&lt;h2&gt;Evaluating the AST&lt;a class=&#34;headerlink&#34; href=&#34;#evaluating-the-ast&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To evaluate an instance of the AST we have defined we can take a similiar approach to printing it.&lt;/p&gt;
&lt;p&gt;If the node we are evaluating is an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;/code&gt; then all we have to do is return the value stored in that node&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;ast_evaluate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In the case of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_PLUS&lt;/span&gt;&lt;/code&gt;, we recursively call &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ast_evaluate&lt;/span&gt;&lt;/code&gt; on both the left and right branches of the tree and then add the resulting values together&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_PLUS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_evaluate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_evaluate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Simiarly for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;/code&gt;, but returing &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;b&lt;/span&gt;&lt;/code&gt; in this case.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;no&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_evaluate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_evaluate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;bringing-it-together&#34;&gt;
&lt;h2&gt;Bringing it together&lt;a class=&#34;headerlink&#34; href=&#34;#bringing-it-together&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We have enough of a toy example together to be able to define, print and evaluate a tree for the two examples in the introduction.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;simple-ast.c&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;one&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.0f&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;two&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2.0f&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;three&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_LITERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;3.0f&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;plus1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_PLUS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;one&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;two&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;example1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;plus1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;three&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mul1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_MULTIPLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;two&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;three&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AstNode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;example2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AST_PLUS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;one&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mul1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_evaluate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;example1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_evaluate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;example2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;example1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Example 1: %.2f&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ast_print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;example2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Example 2: %.2f&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which we can execute with the help of a compiler.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;gcc&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;simple-ast.c&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-o&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;simple-ast
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;./simple-ast
&lt;span class=&#34;go&#34;&gt;*&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  +&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    1.00&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    2.00&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  3.00&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Example 1: 9.00&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;+&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  1.00&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;  *&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    2.00&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;    3.00&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;Example 2: 7.00&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And there you have it, a calculator that only knows how to add and multiply floats!
If you want to see the entire source file you can find it &lt;a class=&#34;reference internal&#34; href=&#34;../code/#code-simple-ast&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2020/passing-strings-between-tinygo-wasm/</id>
    <link href="https://www.alcarney.me/blog/2020/passing-strings-between-tinygo-wasm" rel="alternate" />
    <published>2020-05-06T00:00:00+00:00</published>
    <updated>2020-05-06T00:00:00+00:00</updated>
    <title>Passing strings between TinyGo and JavaScript</title>
    <content type="html">
      &lt;section id=&#34;passing-strings-between-tinygo-and-javascript&#34;&gt;
&lt;h1&gt;Passing strings between TinyGo and JavaScript&lt;a class=&#34;headerlink&#34; href=&#34;#passing-strings-between-tinygo-and-javascript&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;After getting a &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2020/hello-world-tinygo-wasm/&#34; title=&#34;Saying ‘Hello, World!’ with TinyGo and WebAssembly&#34;&gt;&amp;quot;Hello, World!&amp;quot;&lt;/a&gt; WebAssembly
application working I thought it would be fun to try and implement a toy programming
language in the browser. However before I could even start thinking about parsers,
abstract syntax trees and the like I had to be able to pass strings between my
WebAssembly module and the surrounding JavaScript.&lt;/p&gt;
&lt;p&gt;Turns out that is much trickier than I expected.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition-disclaimer admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Disclaimer&lt;/p&gt;
&lt;p&gt;I definitely don’t know what I’m doing, if there’s a better way of doing this I’d love
to know about it! 🙂&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;the-interface&#34;&gt;
&lt;h2&gt;The Interface&lt;a class=&#34;headerlink&#34; href=&#34;#the-interface&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id1&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/wasm-input-output.png&#34; src=&#34;https://www.alcarney.me/_images/wasm-input-output.png&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;The Interface to our ‘interpreter’&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id1&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Our WebAssembly module needs a way to interact with the user in order both collect input
and show the output. So to start with I updated the webpage from the previous post to
include a number of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;textarea&lt;/span&gt;&lt;/code&gt; elements and a “Run” button.&lt;/p&gt;
&lt;div class=&#34;highlight-html notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Input&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;textarea&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;input&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;textarea&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;button&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;disabled&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;run-button&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Run&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;button&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Output&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;textarea&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;disabled&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;output&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;textarea&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;log-area&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;textarea&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;disabled&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;log&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;textarea&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now we could just use the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;println&lt;/span&gt;&lt;/code&gt; function to do the equivalent of a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;console.log&lt;/span&gt;&lt;/code&gt;
from our TinyGo code but it could be useful to have a log on screen to provide feedback
to the user.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;passing-strings-from-tinygo-to-javascript&#34;&gt;
&lt;h2&gt;Passing strings from TinyGo to JavaScript&lt;a class=&#34;headerlink&#34; href=&#34;#passing-strings-from-tinygo-to-javascript&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To achieve this we first need a JavaScript function which takes some text and appends it
to the “log” &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;textarea&lt;/span&gt;&lt;/code&gt; element on screen.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getElementById&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;log&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;logText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next we need some way to reference such a function from our go code. If we define a
function but not implement it TinyGo will recognise it as an external function whose
implementation should be provided by the surrounding JavaScript.&lt;/p&gt;
&lt;div class=&#34;highlight-go notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Hello, World!&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;The Go tools inside of VSCode will complain about the missing implementation for the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;log&lt;/span&gt;&lt;/code&gt; function but TinyGo itself will compile this happily.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Lastly all we have to do is adjust our wrapping JavaScript code to pass in the
implementation for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;log&lt;/span&gt;&lt;/code&gt; function to the module’s environment. While we’re at we
might as well wire up that “Run” button.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onRun&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;importObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;main.go.log&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;logText&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;WebAssembly&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;instantiateStreaming&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fetch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;/js/wisp.wasm&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;importObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;then&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;instance&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runButton&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;disabled&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runButton&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onRun&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That should be everything connected up, time to give it a whirl!&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id2&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/wasm-addr.png&#34; src=&#34;https://www.alcarney.me/_images/wasm-addr.png&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;Not exactly what I had in mind…&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id2&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Hmm… 🤔&lt;/p&gt;
&lt;p&gt;This result quickly prompted an extended session of searching around for the “right”
way to pass values back and forth between my WebAssembly module and the surrounding
JavaScript code. Unfortunately I didn’t really come across anything that seemed to work
for me.&lt;/p&gt;
&lt;p&gt;I did find that Go has a &lt;a class=&#34;reference external&#34; href=&#34;https://golang.org/pkg/syscall/js/&#34;&gt;syscall/js&lt;/a&gt; module which seems to handle exactly this kind of
thing along with a &lt;a class=&#34;reference external&#34; href=&#34;https://www.aaron-powell.com/posts/2019-02-06-golang-wasm-3-interacting-with-js-from-go/&#34;&gt;tutorial series&lt;/a&gt; that makes use of it. The problem is that it seems
to fly in the face of the &lt;a class=&#34;reference external&#34; href=&#34;https://tinygo.org/webassembly/webassembly/&#34;&gt;examples&lt;/a&gt; (which I did manage to reproduce) on the TinyGo
website where it appears the compiler is handling most of these details.&lt;/p&gt;
&lt;p&gt;Unable to find an example to copy I decided it was time for a peek behind the curtain…&lt;/p&gt;
&lt;section id=&#34;digging-deeper&#34;&gt;
&lt;h3&gt;Digging Deeper&lt;a class=&#34;headerlink&#34; href=&#34;#digging-deeper&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On my travels I did manage to find out some more information about WebAssembly itself&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;WebAssembly only has basic integer and float &lt;a class=&#34;reference external&#34; href=&#34;https://webassembly.github.io/spec/core/syntax/types.html&#34;&gt;types&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A module has its own &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory&#34;&gt;memory&lt;/a&gt; and is represented by an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ArrayBuffer&lt;/span&gt;&lt;/code&gt; in
JavaScript code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before long I had a hunch that the random number that was being displayed in the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;textarea&lt;/span&gt;&lt;/code&gt; element was in fact the memory address of the string to be logged. If that
was the case, how should the memory in that location be interpreted so that we’re
able to extract a string from it?&lt;/p&gt;
&lt;p&gt;After some more research I discovered that TinyGo is using the &lt;a class=&#34;reference external&#34; href=&#34;https://llvm.org/&#34;&gt;LLVM&lt;/a&gt; compiler
toolchain and that you can ask it for the &lt;a class=&#34;reference external&#34; href=&#34;https://llvm.org/docs/LangRef.html#abstract&#34;&gt;intermediate representation&lt;/a&gt; which it
passes to LLVM in order to generate the WebAssembly code.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;tinygo&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;build&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-no-debug&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-target&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;wasm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-printir&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-o&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;public/js/wisp.wasm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;main.go&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&amp;gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;debug.txt
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now, there is a &lt;em&gt;lot&lt;/em&gt; going on (20,000+ lines) in this file as it includes not just our
simple program but the Go runtime required to execute it. Thankfully with &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;Ctrl&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;F&lt;/kbd&gt; to
the rescue, it’s easy enough to track down where our “Hello, World!” string is defined&lt;/p&gt;
&lt;div class=&#34;highlight-llvm notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;vg&#34;&gt;@&amp;quot;main.go.main$string&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;internal&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unnamed_addr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;constant&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Hello, World!&amp;quot;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I don’t know the first thing when it comes to LLVM’s IR representation of code but after
looking into how it thinks about &lt;a class=&#34;reference external&#34; href=&#34;https://llvm.org/docs/LangRef.html#array-type&#34;&gt;arrays&lt;/a&gt; we see that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;[13&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;i8]&lt;/span&gt;&lt;/code&gt; indicates
that our string is represented by an array of 13, 8-bit integers.&lt;/p&gt;
&lt;p&gt;Awesome, we now know how to interpret the values we see in the WebAssembly module’s
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ArrayBuffer&lt;/span&gt;&lt;/code&gt;, but how will we know how many values to look for?&lt;/p&gt;
&lt;p&gt;Let’s try and find our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;log&lt;/span&gt;&lt;/code&gt; function…&lt;/p&gt;
&lt;div class=&#34;highlight-llvm notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;declare&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;vg&#34;&gt;@main.go.log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ah, just like the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;log&lt;/span&gt;&lt;/code&gt; function in our go code it has no implementation since this is
to be provided by the JavaScript wrapper. However instead of a single argument it now
takes 4! Interesting… let’s track down our main function and see how it is used.&lt;/p&gt;
&lt;div class=&#34;highlight-llvm notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;define&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;dso_local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;vg&#34;&gt;@main.go.main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;%context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;%parentHandle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unnamed_addr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;nl&#34;&gt;entry:&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;vg&#34;&gt;@main.go.log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;getelementptr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;inbounds&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;vg&#34;&gt;@&amp;quot;main.go.main$string&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i32&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i32&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i32&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;void&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Wow. Umm… there’s a lot going on here… what if we try “squinting” at this code a bit&lt;/p&gt;
&lt;div class=&#34;highlight-llvm notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;define&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;vg&#34;&gt;@main.go.main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(...)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;vg&#34;&gt;@main.go.log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;getelementptr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(...&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;vg&#34;&gt;@&amp;quot;main.go.main$string&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,...),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;i32&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;...)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;void&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ok, so it looks like there’s a call being made to our log function and
&lt;a class=&#34;reference external&#34; href=&#34;https://llvm.org/docs/LangRef.html#i-getelementptr&#34;&gt;getelementptr&lt;/a&gt; appears to be returning the memory address of our
“Hello, World!” string and look! The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;i32&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;13&lt;/span&gt;&lt;/code&gt; argument appears to be passing in its
length! I have no idea what the other arguments are supposed to represent so let’s just
ignore those for now! 😃&lt;/p&gt;
&lt;p&gt;Instead why don’t we tweak our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;logText&lt;/span&gt;&lt;/code&gt; implementation of this function to take a
second argument and see what happens&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;logText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id3&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/wasm-addr-length.png&#34; src=&#34;https://www.alcarney.me/_images/wasm-addr-length.png&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;That looks promising!&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id3&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&#34;extracting-the-string&#34;&gt;
&lt;h3&gt;Extracting the String&lt;a class=&#34;headerlink&#34; href=&#34;#extracting-the-string&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Assuming our assumptions are correct we should now have all the information we need in
order to extract the string from the WebAssembly module’s memory. &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;ArrayBuffer&lt;/span&gt;&lt;/code&gt; objects
in JavaScript don’t seem to be the most intuitive to work with but I was eventually able
to come up with this.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;logText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;memory&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;memory&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bytes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;slice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fromCharCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;apply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;Int8Array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After getting the reference to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;memory&lt;/span&gt;&lt;/code&gt; object we use the &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/slice&#34;&gt;slice&lt;/a&gt; method to obtain
a copy of only the bytes that represent our string. Unfortunately bytes on their own are
meaningless unless you know how to interpret them. To enable this there is a whole collection
of &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray&#34;&gt;views&lt;/a&gt; that can be wrapped around a given array of bytes to attach meaning to them.
From our explorations above we know that we should use an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Int8Array&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From there we map the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;String.fromCharCode&lt;/span&gt;&lt;/code&gt; function over the array of ints to convert
them to a string. Finally, we should be able to see our “Hello, World!” string output to
the log area&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id4&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/wasm-log-hello.png&#34; src=&#34;https://www.alcarney.me/_images/wasm-log-hello.png&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;Success!&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id4&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This did require a slight tweak to the way we load the module so that we have a global
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wasm&lt;/span&gt;&lt;/code&gt; reference that our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;logText&lt;/span&gt;&lt;/code&gt; function is able to use to access the module
instance directly.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;WebAssembly&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;instantiateStreaming&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fetch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;/js/wisp.wasm&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;importObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;then&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;instance&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runButton&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;disabled&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runButton&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onRun&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;passing-strings-from-javascript-to-tinygo&#34;&gt;
&lt;h2&gt;Passing strings from JavaScript to TinyGo&lt;a class=&#34;headerlink&#34; href=&#34;#passing-strings-from-javascript-to-tinygo&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Phew, at least we’re halfway there! Now that we’ve figured out how things actually hang
together it’s “just” a matter of doing the inverse process to pass a string from our
JavaScript code into our WebAssembly module. As a proof of concept let’s create an
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;echo&lt;/span&gt;&lt;/code&gt; function in TinyGo that will simply log whatever text it receives.&lt;/p&gt;
&lt;div class=&#34;highlight-go notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//go:export echo&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;echo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In order to actually pass a string to this function, we need to insert the string into
the memory of the WebAssembly module before calling &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;echo&lt;/span&gt;&lt;/code&gt; with its address and length.&lt;/p&gt;
&lt;section id=&#34;manipulating-memory&#34;&gt;
&lt;h3&gt;Manipulating Memory&lt;a class=&#34;headerlink&#34; href=&#34;#manipulating-memory&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The problem is, where exactly in the module’s memory should we place the string? We
can’t shove it anywhere as we could corrupt memory required for some other part of the
program. It is possible to &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/grow&#34;&gt;grow&lt;/a&gt; the memory assigned to a module instance
which technically would be free for us to use(?) But it doesn’t exactly &lt;em&gt;feel&lt;/em&gt; right,
having two competing codebases manipulate the same memory layout seems to be asking
for trouble…&lt;/p&gt;
&lt;p&gt;Thankfully I came across &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/tinygo-org/tinygo/issues/411#issuecomment-503066868&#34;&gt;this comment&lt;/a&gt; on an issue in the TinyGo project
which provides a way we can work around this.&lt;/p&gt;
&lt;div class=&#34;highlight-go notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;//go:export getBuffer&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getBuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If we declare an array of bytes in the module, the TinyGo compiler will allocate space
and manage it for us. Then by exporting the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;getBuffer&lt;/span&gt;&lt;/code&gt; function we provide a way for
our wrapping JavaScript to ask for the address to the region of memory we have reserved
for it. This region of memory should then be safe for us to write to from JavaScript
&lt;strong&gt;provided our go code only reads from this array&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now with some reserved memory to use we can write a function that takes a string and
inserts it into the module’s memory.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;insertText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Get the address of the writable memory.&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getBuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;Int8Array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;subarray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;charCodeAt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Return the address we started at.&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As with the earlier case, we need to create an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Int8Array&lt;/span&gt;&lt;/code&gt; in order to attach meaning to
the bytes and so that the numbers representing the characters in the string are encoded
correctly. Also note that we’re using the &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray&#34;&gt;subarray&lt;/a&gt; method this time so that we’re
modifying the original array and not a copy.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;calling-the-echo-function&#34;&gt;
&lt;h3&gt;Calling the Echo Function&lt;a class=&#34;headerlink&#34; href=&#34;#calling-the-echo-function&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With a way for us to insert the string we want into the module’s memory we should now
be in a position to call the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;echo&lt;/span&gt;&lt;/code&gt; function passing the starting address and length
of the string we want it to echo. However instead of hardcoding the string this time why
don’t we take it from the input &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;textarea&lt;/span&gt;&lt;/code&gt; we have on the page.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getElementById&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;input&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onRun&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// First, we need to run the module in order to define everything.&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;inputText&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;insertText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;inputText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Now just pass the memory location to the relevant function.&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;echo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;inputText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;figure class=&#34;align-center&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/wasm-echo.gif&#34; src=&#34;https://www.alcarney.me/_images/wasm-echo.gif&#34; /&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;wrapping-up&#34;&gt;
&lt;h2&gt;Wrapping Up&lt;a class=&#34;headerlink&#34; href=&#34;#wrapping-up&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That’s about it, if you want to have a look at the final codebase then you can find it
&lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/wisp/tree/passing-strings&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This apparently simple task was certainly a lot more work than I expected it to be,
but if nothing else it’s forced me to learn a bit more about some of the lower-level
details of working with WebAssembly modules.&lt;/p&gt;
&lt;p&gt;I don’t think this is necessarily the right approach though.. ok we’re able to pass a
(simple!) string back and forth between our TinyGo code and JavaScript. But there are
more details that still need to be considered&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;This solution does not handle Unicode. There is however a
&lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder&#34;&gt;TextEncoder&lt;/a&gt; API available in the browser that looks like it might
go some way towards fixing this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I thought the fixed buffer size in the go module would be an issue - how would you
handle inputs larger than 1024 bytes? However after a quick test with about 5K of text
it seemed to not matter? 🤷 Though I’m sure there’s ways to break it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, what about more complex data structures? Sure we’d probably be able to encode
them as JSON and pass them around that way but I’m sure that would introduce
unnecessary overhead.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And with all that said isn’t this a problem that the toolchain should be solving?
Perhaps I’m just using it wrong 🤔&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2020/hello-world-tinygo-wasm/</id>
    <link href="https://www.alcarney.me/blog/2020/hello-world-tinygo-wasm" rel="alternate" />
    <published>2020-04-28T00:00:00+00:00</published>
    <updated>2020-04-28T00:00:00+00:00</updated>
    <title>Saying ‘Hello, World!’ with TinyGo and WebAssembly</title>
    <content type="html">
      &lt;section id=&#34;saying-hello-world-with-tinygo-and-webassembly&#34;&gt;
&lt;h1&gt;Saying ‘Hello, World!’ with TinyGo and WebAssembly&lt;a class=&#34;headerlink&#34; href=&#34;#saying-hello-world-with-tinygo-and-webassembly&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;WebAssembly is something I’ve wanted to play with for quite a while now and
I’ve finally got around to taking a look at it. In this post I describe how I
managed to use &lt;a class=&#34;reference external&#34; href=&#34;https://tinygo.org/&#34;&gt;TinyGo&lt;/a&gt; to compile a “Hello, World!” Go program into
WebAssembly and execute it in the browser. So that I have something to refer
back to I also describe setting up my development environment as a container
using &lt;a class=&#34;reference external&#34; href=&#34;https://linuxcontainers.org/&#34;&gt;LXD&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;setting-up&#34;&gt;
&lt;h2&gt;Setting Up&lt;a class=&#34;headerlink&#34; href=&#34;#setting-up&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;What I describe here is definitely &lt;em&gt;not&lt;/em&gt; a requirement in order to use TinyGo,
but me wanting to play with yet more technologies so feel free to
&lt;a class=&#34;reference internal&#34; href=&#34;../blog/2020/hello-world-tinygo-wasm/#hello-world-tinygo-wasm-tinygo&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;skip&lt;/span&gt;&lt;/a&gt; this section if you want! 🙂&lt;/p&gt;
&lt;p&gt;If you’re looking for details on getting started with TinyGo I suggest taking a
look at their &lt;a class=&#34;reference external&#34; href=&#34;https://tinygo.org/getting-started/&#34;&gt;documentation&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The recent release of Ubuntu 20.04 (and my desire to have a computer that works
properly! 😂) has convinced me to switch away from using Arch Linux as my distro of
choice. That said I have been spoiled by how easy it is to grab the latest version
of some programming language and start playing with it…&lt;/p&gt;
&lt;p&gt;Turns out I can have the best of both worlds! Thanks to &lt;a class=&#34;reference external&#34; href=&#34;https://linuxcontainers.org/&#34;&gt;LXD&lt;/a&gt; and the
interface it provides around the native container technology built into Linux I was
able to spin up an Arch Linux container with all the tools I needed to edit and run
my code.&lt;/p&gt;
&lt;section id=&#34;spinning-up-arch-linux&#34;&gt;
&lt;h3&gt;Spinning up Arch Linux&lt;a class=&#34;headerlink&#34; href=&#34;#spinning-up-arch-linux&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Following this`_ article it was easy enough to pull down and
launch an Arch Linux image from the community &lt;a class=&#34;reference external&#34; href=&#34;https://uk.images.linuxcontainers.org/&#34;&gt;repository&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;snap&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;install&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;lxd
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;lxd&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;init&lt;span class=&#34;w&#34;&gt;                                 &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# ... and picking all the defaults&lt;/span&gt;
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;lxd&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;launch&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;image:archlinux/amd64&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;tinygo&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;#39;tinygo&amp;#39; is the name I&amp;#39;ve given my container&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once the container has started it’s easy enough to open a bash shell and start
installing what we need&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;lxc&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;tinygo&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/bin/bash
&lt;span class=&#34;gp&#34;&gt;[root@tinygo] $ &lt;/span&gt;pacman&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-S&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;tinygo&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;llvm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;lld
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;users-and-project-data&#34;&gt;
&lt;h3&gt;Users and Project Data&lt;a class=&#34;headerlink&#34; href=&#34;#users-and-project-data&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Even in an unprivileged container (which is what I think LXD uses by default?) its
probably not the best idea to run programs as root so we should create a normal user
account and set a password&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;[root@tinygo] $ &lt;/span&gt;useradd&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-m&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;alex
&lt;span class=&#34;gp&#34;&gt;[root@tinygo] $ &lt;/span&gt;passwd&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;alex
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then its time to share the project folder with the container so that the tools inside
are able to work with it.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;mkdir&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;hello-world
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;lxc&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;config&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;device&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;add&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;tinygo&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;workdir&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;disk&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/host/path/to/hello-world/&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/home/alex/hello-world/

&lt;span class=&#34;gp&#34;&gt;[root@tinygo] $ &lt;/span&gt;ls&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/home/alex
&lt;span class=&#34;go&#34;&gt;hello-world&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;vscode&#34;&gt;
&lt;h3&gt;VSCode&lt;a class=&#34;headerlink&#34; href=&#34;#vscode&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id2&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/vscode-remote.gif&#34; src=&#34;https://www.alcarney.me/_images/vscode-remote.gif&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;Attaching VSCode to ‘tinygo’ container.&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id2&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Just because the development tools we’re using are isolated in their own container
doesn’t mean we have to give up on all the features of our editor. With VSCode’s
&lt;a class=&#34;reference external&#34; href=&#34;https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack&#34;&gt;Remote Development Extensions&lt;/a&gt; we can connect to a remote environment where VSCode
will install its server component along with any other extensions we require - all
of which will remain isolated in the container.&lt;/p&gt;
&lt;p&gt;The remote capabilities of VSCode come in a few flavours and while VSCode has an
extension dedicated to containers it appears that it’s hard wired to work with Docker
which isn’t much use in this case… but since each LXC container is assigned a local
IP address I decided to try the SSH method.&lt;/p&gt;
&lt;p&gt;This means we need to enable ssh access from within the container itself.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;[root@tinygo] $ &lt;/span&gt;pacman&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-S&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;openssh
&lt;span class=&#34;gp&#34;&gt;[root@tinygo] $ &lt;/span&gt;systemctl&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;enable&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--now&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;sshd.service
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then for all the Go related tooling in VSCode to function I also had to install the main
Go implementation.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;[root@tinygo] $ &lt;/span&gt;pacman&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-S&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;go
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally we can discover the IP address of the container using the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;lxc&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;list&lt;/span&gt;&lt;/code&gt; command and
try to connect VSCode to the container logging in as the &lt;cite&gt;alex&lt;/cite&gt; user we created earlier.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;lxc&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;list
&lt;span class=&#34;go&#34;&gt;+--------+---------+---------------------+-----------------------------------------------+-----------+-----------+&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;|  NAME  |  STATE  |        IPV4         |                     IPV6                      |   TYPE    | SNAPSHOTS |&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;+--------+---------+---------------------+-----------------------------------------------+-----------+-----------+&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;| tinygo | RUNNING | 10.68.193.81 (eth0) | fd42:56e0:e39c:b4c1:216:3eff:feaa:3b91 (eth0) | CONTAINER | 0         |&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;+--------+---------+---------------------+-----------------------------------------------+-----------+-----------+&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;access-denied&#34;&gt;
&lt;h3&gt;Access Denied!!&lt;a class=&#34;headerlink&#34; href=&#34;#access-denied&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once I started to create the files necessary for the project I very quickly realised that
the project folder we passed into the container was mounted as read-only! It turns
out there is some extra wizardry required to give the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;alex&amp;#64;tinygo&lt;/span&gt;&lt;/code&gt; user permission to
write files back to the host…&lt;/p&gt;
&lt;p&gt;I really don’t quite understand the details of how users and permissions work with these
containers but from what I can gather LXD needs to reuse the ID of my user account on the
host as the ID of the user within the container?..&lt;/p&gt;
&lt;p&gt;Anyway according to &lt;a class=&#34;reference external&#34; href=&#34;https://tribaal.io/nicer-mounting-home-in-lxd.html&#34;&gt;this post&lt;/a&gt; the incantations needed are&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;root:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$UID&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;:1&amp;quot;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;sudo&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;tee&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-a&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/etc/subuid&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/etc/subgid
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;which is a one time setup allowing my user ID on the host to be reused. Then on a
per-container basis we also need to tell LXD to reuse my ID within a given container&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;lxc&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;config&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;tinygo&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;raw.idmap&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;both &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$UID&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 1000&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Phew! I think, finally, we’re in a position to crack on with the program itself. Was all
of that necessary?.. probably not. Was it interesting? I certainly think so! Is it worth
the effort? Well, I guess only time will tell…&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;tinygo&#34;&gt;
&lt;span id=&#34;hello-world-tinygo-wasm-tinygo&#34;&gt;&lt;/span&gt;&lt;h2&gt;TinyGo&lt;a class=&#34;headerlink&#34; href=&#34;#tinygo&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the setup out of the way time to write our “Hello, World!” program in Go&lt;/p&gt;
&lt;div class=&#34;highlight-go notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;//go:export main&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Hello, World!&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Notice the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;//go:export&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;main&lt;/span&gt;&lt;/code&gt; comment. Using comments like these is how we tell TinyGo
which functions we want to be callable from the JavaScript code that will wrap our
WebAssembly module. This is then compiled with the following TinyGo command.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;mkdir&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;public/
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;tinygo&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;build&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-o&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;public/hello.wasm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-target&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;wasm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;main.go
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition-why-tinygo admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Why TinyGo?&lt;/p&gt;
&lt;p&gt;While the standard Go compiler &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/golang/go/wiki/WebAssembly&#34;&gt;has support&lt;/a&gt; for WebAssembly the binaries it
produces are typically &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/golang/go/wiki/WebAssembly#reducing-the-size-of-wasm-files&#34;&gt;quite large&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Whereas &lt;a class=&#34;reference external&#34; href=&#34;https://tinygo.org/&#34;&gt;TinyGo&lt;/a&gt; is an alternate compiler for the Go language that
specifically targets constrained environments such as embedded devices and
microcontrollers. This means the binaries it produces are typically much smaller - at
the expense of &lt;a class=&#34;reference external&#34; href=&#34;https://tinygo.org/lang-support/&#34;&gt;missing&lt;/a&gt; some features of the language.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;webassembly&#34;&gt;
&lt;h2&gt;WebAssembly&lt;a class=&#34;headerlink&#34; href=&#34;#webassembly&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With our WebAssembly binary ready to go it’s time to load it into the browser and
execute it.&lt;/p&gt;
&lt;div class=&#34;highlight-html notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;lang&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;en&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;meta&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;charset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;meta&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;viewport&amp;quot;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;WASM Test&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;wasm_exec.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;WebAssembly&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;instantiateStreaming&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fetch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;hello.wasm&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;importObject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;then&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;               &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;instance&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;               &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;wasm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There’s not too much to go into here - I’m surprised at how straightforward this was! 😀
The &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming&#34;&gt;WebAssembly.instantiateStreaming&lt;/a&gt; function is provided by the browser to fetch a
wasm executable over the network and compile it. It also takes an object that describes
details such as how much memory to allocate to the module and which JavaScript functions
should be passed into it.&lt;/p&gt;
&lt;p&gt;Thankfully in our case most of these details are handled by the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Go()&lt;/span&gt;&lt;/code&gt; object provided
by the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;wasm_exec.js&lt;/span&gt;&lt;/code&gt; file from the TinyGo project. All we have to do is make sure that
this file is also accessible by the browser. The file itself should be included as part
of your TinyGo install, mine was located in &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;/usr/lib/tinygo/targets/wasm_exec.js&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;More details on using the compiled WebAssembly module can be found in the
&lt;a class=&#34;reference external&#34; href=&#34;https://tinygo.org/webassembly/webassembly/&#34;&gt;TinyGo documentation&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id3&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/wasm-hello-world.png&#34; src=&#34;https://www.alcarney.me/_images/wasm-hello-world.png&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;This is probably my most convoluted ‘Hello, World!’ program to date!&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id3&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;All being well, you should be able to open your browser to the webpage we created above
and see the message “Hello, World!” written to the console!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2020/learning-vulkan-p1/</id>
    <link href="https://www.alcarney.me/blog/2020/learning-vulkan-p1" rel="alternate" />
    <published>2020-01-08T00:00:00+00:00</published>
    <updated>2020-01-08T00:00:00+00:00</updated>
    <title>Learning Vulkan: Enumerating Physical Devices</title>
    <content type="html">
      &lt;section id=&#34;learning-vulkan-enumerating-physical-devices&#34;&gt;
&lt;h1&gt;Learning Vulkan: Enumerating Physical Devices&lt;a class=&#34;headerlink&#34; href=&#34;#learning-vulkan-enumerating-physical-devices&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;Being an API for talking to GPUs and other compute devices every Vulkan
program starts off by looking for an appropriate &lt;a class=&#34;reference external&#34; href=&#34;https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkPhysicalDevice.html&#34;&gt;physical device&lt;/a&gt;
to use. In this post I write a little C program that initialises the Vulkan
API and lists out the available devices in the system.&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ vkdevice
Device Name:            Intel(R) HD Graphics 520 (Skylake GT2)
  Type:                 Integrated GPU
  Vendor ID:            32902
  Device ID:            6422
  API Version:          v1.1.102
  Driver Version:       v19.3.1
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;This is part of my “Learning Vulkan” series where I try to figure how to use
Vulkan to explore various concepts in graphics programming. As mentioned in
the &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2020/learning-vulkan-p0/&#34; title=&#34;Learning Vulkan: Overview&#34;&gt;Overview&lt;/a&gt; I don’t necessarily
know what I’m doing!&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;setup&#34;&gt;
&lt;h2&gt;Setup&lt;a class=&#34;headerlink&#34; href=&#34;#setup&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Unlike Python which has tools like &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;pip&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;venv&lt;/span&gt;&lt;/code&gt; to manage
dependencies and development environments, C projects (as far as I know)
require the environment of your development machine to be “just right”. This means
details such as the host operating system and its libraries are more important
than normal.&lt;/p&gt;
&lt;p&gt;Since this series is a learning exercise, being able to compile and run code
across multiple systems is not a huge concern of mine right now. But here is a rough
overview of what is required to build this project…&lt;/p&gt;
&lt;p&gt;I’m running Arch Linux with &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;gcc&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;make&lt;/span&gt;&lt;/code&gt; installed along with the following
Vulkan related packages&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;pacman&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-Q&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;grep&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;vulkan
&lt;span class=&#34;go&#34;&gt;vulkan-extra-layers 1.1.130+10614+a70d5d17e-1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;vulkan-headers 1:1.1.130-1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;vulkan-html-docs 1:1.1.130-1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;vulkan-icd-loader 1.1.130-1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;vulkan-intel 19.3.1-1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;vulkan-man-pages 1:1.0.38-1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;vulkan-trace 1.1.130+10614+a70d5d17e-1&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;vulkan-validation-layers 1.1.130-1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’m not sure however which of these are essential for the code contained in this
post.&lt;/p&gt;
&lt;section id=&#34;project-structure&#34;&gt;
&lt;h3&gt;Project Structure&lt;a class=&#34;headerlink&#34; href=&#34;#project-structure&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’m intending over the course of this series to build up a repository of Vulkan
examples/utilities and since the API  has a reputation of being verbose I’ll be looking
to reuse as much code as I can! So with that in mind I have opted for the following
project structure&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;tree&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-a&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--dirsfirst
&lt;span class=&#34;go&#34;&gt;.&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;├── bin&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│   └── vkdevice&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;├── src&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│   ├── vkdevice.c&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│   └── vkdevice.o&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;├── .gitignore&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;└── Makefile&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Nothing ground breaking, a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;src/&lt;/span&gt;&lt;/code&gt; folder to hold the source and intermediate build files,
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;bin/&lt;/span&gt;&lt;/code&gt; to hold all the compiled programs and a plain &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Makefile&lt;/span&gt;&lt;/code&gt; to orchestrate the whole
thing.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;the-makefile&#34;&gt;
&lt;h3&gt;The Makefile&lt;a class=&#34;headerlink&#34; href=&#34;#the-makefile&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I know that there are tools such as &lt;a class=&#34;reference external&#34; href=&#34;https://cmake.org/&#34;&gt;CMake&lt;/a&gt; and &lt;a class=&#34;reference external&#34; href=&#34;https://www.gnu.org/software/autoconf/&#34;&gt;Autoconf&lt;/a&gt; that are
probably preferable to a plain Makefile since they can be used to abstract over some
differences between platforms. However since I’m not familiar with them and want to
focus on learning Vulkan I’m opting for a simpler approach to start out with.&lt;/p&gt;
&lt;div class=&#34;highlight-make notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;CC&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;gcc
&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-Wall&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-Wextra
&lt;span class=&#34;nv&#34;&gt;LDFLAGS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-lvulkan
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here I’m declaring that I’m using the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;gcc&lt;/span&gt;&lt;/code&gt; compiler, the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;CFLAGS&lt;/span&gt;&lt;/code&gt; variable contains any
flags that should passed to compile steps (at the moment this just enables some compiler
warnings). Finally &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;LDFLAGS&lt;/span&gt;&lt;/code&gt; contains any flags related to linking, &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;-lvulkan&lt;/span&gt;&lt;/code&gt; tells the
linker to link our program against the Vulkan SDK.&lt;/p&gt;
&lt;div class=&#34;highlight-make notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;.PHONY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clean&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkdevice&lt;/span&gt;
&lt;span class=&#34;nf&#34;&gt;clean&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;rm&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;src/*.o&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;bin/*
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next I define the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;default&lt;/span&gt;&lt;/code&gt; target to be &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;vkdevice&lt;/span&gt;&lt;/code&gt; so that I can just run &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;make&lt;/span&gt;&lt;/code&gt; and
have it build the project. Then there’s a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;clean&lt;/span&gt;&lt;/code&gt; target so that it’s easy to recompile
everything from scratch. Declaring both &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;default&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;clean&lt;/span&gt;&lt;/code&gt; to be &lt;a class=&#34;reference external&#34; href=&#34;https://www.gnu.org/software/make/manual/make.html#Phony-Targets&#34;&gt;phony targets&lt;/a&gt; I
think means we’re telling &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;make&lt;/span&gt;&lt;/code&gt; not to look for matching files on the filesystem.&lt;/p&gt;
&lt;div class=&#34;highlight-make notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;%.o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;%.&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-c&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;$&amp;lt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;

&lt;span class=&#34;nv&#34;&gt;VKDEVICE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;src/vkdevice.o
&lt;span class=&#34;nf&#34;&gt;vkdevice&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;LDFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;VKDEVICE&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-o&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;bin/vkdevice
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Last but not least we get to the main part of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Makefile&lt;/span&gt;&lt;/code&gt;. First there is a generic
&lt;a class=&#34;reference external&#34; href=&#34;https://www.gnu.org/software/make/manual/make.html#Pattern-Rules&#34;&gt;pattern rule&lt;/a&gt; that instructs &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;make&lt;/span&gt;&lt;/code&gt; on how to convert any &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;.c&lt;/span&gt;&lt;/code&gt; file into
an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;.o&lt;/span&gt;&lt;/code&gt; file making use of any of the compiler flags defined earlier. This allows the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Makefile&lt;/span&gt;&lt;/code&gt; to be extended to compile each program we write by declaring a target that
links the relevant object files (as defined by &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;VKDEVICE&lt;/span&gt;&lt;/code&gt;) into an executable.&lt;/p&gt;
&lt;p&gt;Then we can compile the project by calling &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;make&lt;/span&gt;&lt;/code&gt; from the same directory as the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Makefile&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;make
&lt;span class=&#34;go&#34;&gt;gcc -c -Wall -Wextra src/vkdevice.c -o src/vkdevice.o&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;gcc -lvulkan src/vkdevice.o -o bin/vkdevice&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;creating-an-instance&#34;&gt;
&lt;h2&gt;Creating an instance&lt;a class=&#34;headerlink&#34; href=&#34;#creating-an-instance&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With all the housekeeping out of the way, time to dive into the code which starts in
a fairly standard way with us including all the header files we need.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cpf&#34;&gt;&amp;lt;vulkan/vulkan.h&amp;gt;&lt;/span&gt;

&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Insert code...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then we start by filling out the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;VkApplicationInfo&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;VkInstanceCreateInfo&lt;/span&gt;&lt;/code&gt; structs.
Unsurprisingly the first is used to provide information about our application such as
the version of the API we wish to use. The application name and version fields are
arbitrary and can be set to whatever we like.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VkApplicationInfo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sType&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_STRUCTURE_TYPE_APPLICATION_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pApplicationName&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;vkDevice Info&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;applicationVersion&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_MAKE_VERSION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_API_VERSION_1_1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;VkInstanceCreateInfo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sType&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pApplicationInfo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;vk_info&lt;/span&gt;&lt;/code&gt; struct is then be used to create the instance.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VkInstance&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;VkResult&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkCreateInstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Unable to create VkInstance!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We also have to be sure to destroy the instance once we have finished with it&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Code omitted...&lt;/span&gt;

&lt;span class=&#34;nl&#34;&gt;cleanup_instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkDestroyInstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is me attempting to apply &lt;a class=&#34;reference external&#34; href=&#34;https://www.kernel.org/doc/html/v4.10/process/coding-style.html#centralized-exiting-of-functions&#34;&gt;this&lt;/a&gt; rule from the Linux kernel style
guide to help manage resources through the lifetime of the program.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;listing-devices&#34;&gt;
&lt;h2&gt;Listing Devices&lt;a class=&#34;headerlink&#34; href=&#34;#listing-devices&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we have an instance we can start querying the API for the physical devices that
are in the system. The issue is however - we don’t know how many devices the system has!
To get around this we first have to call &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;vkEnumeratePhysicalDevices&lt;/span&gt;&lt;/code&gt; with a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;NULL&lt;/span&gt;&lt;/code&gt;
pointer, it will then mutate the &lt;cite&gt;count&lt;/cite&gt; variable that we give to be equal to the number
of available devices.&lt;/p&gt;
&lt;p&gt;Note that we skip straight to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;cleanup_instance&lt;/span&gt;&lt;/code&gt; label we defined earlier if this
step fails.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkEnumeratePhysicalDevices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Unable to enumerate physical devices&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cleanup_instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next we attempt to allocate enough memory to store each of the devices in an array.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VkPhysicalDevice&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physical_devices&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VkPhysicalDevice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physical_devices&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Unable to enumerate physical devices&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cleanup_instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally with the array allocated we can call &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;vkEnumeratePhysicalDevices&lt;/span&gt;&lt;/code&gt; a second time
to populate it. Notice how this time the error path has to jump to the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;cleanup_devices&lt;/span&gt;&lt;/code&gt;
label so that we can be sure to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;free&lt;/span&gt;&lt;/code&gt; the newly allocated memory.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkEnumeratePhysicalDevices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physical_devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Unable to enumerate physical devices&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cleanup_devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;// Code omitted...&lt;/span&gt;

&lt;span class=&#34;nl&#34;&gt;cleanup_devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physical_devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physical_devices&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

&lt;span class=&#34;nl&#34;&gt;cleanup_instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkDestroyInstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition-editor-s-note admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Editor’s Note&lt;/p&gt;
&lt;p&gt;As I was writing this post I looked up the &lt;a class=&#34;reference external&#34; href=&#34;https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumeratePhysicalDevices.html&#34;&gt;documentation&lt;/a&gt;
for &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;vkEnumeratePhysicalDevices&lt;/span&gt;&lt;/code&gt; and noticed that there is a different way to
approach this section. We could’ve instead decided on a fixed size array&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_DEVICES&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;VkPhysicalDevice&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physical_devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_DEVICES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkEnumeratePhysicalDevices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_DEVICES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physical_devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this situation the function will return up to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;MAX_DEVICES&lt;/span&gt;&lt;/code&gt; and if there more
devices than can fit in the array then &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;res&lt;/span&gt;&lt;/code&gt; will be set to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;VK_INCOMPLETE&lt;/span&gt;&lt;/code&gt; giving
us the option to try again with a larger array.&lt;/p&gt;
&lt;p&gt;This creates a dilemma - which approach is better? 🤔&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;device-properties&#34;&gt;
&lt;h2&gt;Device Properties&lt;a class=&#34;headerlink&#34; href=&#34;#device-properties&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It turns out that a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;VkPhysicalDevice&lt;/span&gt;&lt;/code&gt; on its own is rather useless since it doesn’t
carry any information about itself. In order to find out more about what the device is
and what features of the API it supports you need to call additional functions such as&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetPhysicalDeviceProperties.html&#34;&gt;vkGetPhysicalDeviceProperties&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetPhysicalDeviceImageFormatProperties.html&#34;&gt;vkGetPhysicalDeviceImageFormatProperties&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetPhysicalDeviceQueueFamilyProperties.html&#34;&gt;vkGetPhysicalDeviceQueueFamilyProperties&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and many more!!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Typically as part of your program’s setup you would call a number of these to gather
information about support for features that matter to you to help decide which device
is best suited to your use case. However for this toy program we’re only going to call
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;vkGetPhysicalDeviceProperties&lt;/span&gt;&lt;/code&gt; for each device which will give us information such as
its name.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VkPhysicalDeviceProperties&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{};&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkGetPhysicalDeviceProperties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physical_devices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Version numbers (&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;MAJOR.MINOR.PATCH&lt;/span&gt;&lt;/code&gt;) in the Vulkan API are encoded into a single 32bit
integer as defined in the &lt;a class=&#34;reference external&#34; href=&#34;https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#extendingvulkan-coreversions-versionnumbers&#34;&gt;specification&lt;/a&gt;. Thankfully the spec also defines a number of
macros that make decoding them nice and easy for us.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk_major&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_VERSION_MAJOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk_minor&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_VERSION_MINOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk_patch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_VERSION_PATCH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;

&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driver_major&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_VERSION_MAJOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driverVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driver_minor&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_VERSION_MINOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driverVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driver_patch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;VK_VERSION_PATCH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driverVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;All that’s left to do is to print out the information we have gathered.&lt;/p&gt;
&lt;div class=&#34;highlight-c notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Device Name:     &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deviceName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;  Type:          &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vkPhysicalDeviceType_as_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deviceType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;  Vendor ID:     &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vendorID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;  Device ID:     &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deviceID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;  API Version:   &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;v%d.%d.%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk_major&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk_minor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk_patch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;  Driver Version:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;v%d.%d.%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driver_major&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driver_minor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;driver_patch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I should also note that &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;vkPhysicalDeviceType_as_string&lt;/span&gt;&lt;/code&gt; is a helper function I
defined that converts a member of the &lt;a class=&#34;reference external&#34; href=&#34;https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkPhysicalDeviceType.html&#34;&gt;VkPhysicalDeviceType&lt;/a&gt; enum
into a string representation with a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;switch&lt;/span&gt;&lt;/code&gt; statement.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;conclusion&#34;&gt;
&lt;h2&gt;Conclusion&lt;a class=&#34;headerlink&#34; href=&#34;#conclusion&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;And that’s that! I’ve taken my first few baby steps with the Vulkan API and I hope that
if you’ve read this far then this post was as useful to you as it was to me! If you are
interested then you can see the full code listing &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/vk/blob/2e7daaa68d79c6467e91bbd9d5ebfcf34729f6a5/src/vkdevice.c&#34;&gt;here&lt;/a&gt; and I’ll see you in the
next one.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2020/learning-vulkan-p0/</id>
    <link href="https://www.alcarney.me/blog/2020/learning-vulkan-p0" rel="alternate" />
    <published>2020-01-01T00:00:00+00:00</published>
    <updated>2020-01-01T00:00:00+00:00</updated>
    <title>Learning Vulkan: Overview</title>
    <content type="html">
      &lt;section id=&#34;learning-vulkan-overview&#34;&gt;
&lt;h1&gt;Learning Vulkan: Overview&lt;a class=&#34;headerlink&#34; href=&#34;#learning-vulkan-overview&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;I have always been interested in graphics and have on numerous occasions tried
to dip my toe into the world of OpenGL and more recently Vulkan. However I have
never been able to get past the “Hello, World” of these technologies - drawing a
triangle on screen, I think mostly becuase I never really had a goal in mind
once I got that far…&lt;/p&gt;
&lt;p&gt;But that’s (hopefully) about to change! What better excuse than a new decade to
jump back into this world for the 100th time and try to get to all those
interesting ideas I see people playing with all the time!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I should say that I don’t really know what I’m doing and will totally be making
it up as I go along. With Python being my favourite language, programming in C
(C++ is just too intimidating) will take some getting used to let alone all the
concepts specific to graphics programming! However that said I’m not a complete
n00b as I have at least played with C on and off over the years - I’m sure I
already know enough to be able to shoot myself in the foot! 😁&lt;/p&gt;
&lt;p&gt;So the only thing left to do is set some goals so I don’t get lost after getting
to the “drawing a triangle on screen” stage again. I imagine this will evolve
into some kind of living document that I’ll use to keep track of my progress - if I
remember to update it that is!&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;[ ] Draw a triangle on screen&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;[x] &lt;a class=&#34;reference internal&#34; href=&#34;../blog/2020/learning-vulkan-p1/&#34; title=&#34;Learning Vulkan: Enumerating Physical Devices&#34;&gt;Enumerating available VkPhysicalDevices&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[ ] OBJ object viewer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[ ] Ray Marching&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[ ] Ray Tracing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[ ] Python integrations?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2019/click-drag-vanilla-js/</id>
    <link href="https://www.alcarney.me/blog/2019/click-drag-vanilla-js" rel="alternate" />
    <published>2019-07-07T00:00:00+00:00</published>
    <updated>2019-07-07T00:00:00+00:00</updated>
    <title>Implementing Click &amp; Drag with Vanilla JS</title>
    <content type="html">
      &lt;section id=&#34;implementing-click-drag-with-vanilla-js&#34;&gt;
&lt;h1&gt;Implementing Click &amp;amp; Drag with Vanilla JS&lt;a class=&#34;headerlink&#34; href=&#34;#implementing-click-drag-with-vanilla-js&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;figure&gt;
  &lt;div id=&#34;main-el&#34;&gt;&lt;/div&gt;
  &lt;figcaption&gt;
    &lt;p&gt;Try clicking and dragging on this circle.&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;script type=&#34;text/javascript&#34; src=&#34;/_static/js/click-drag.js&#34;&gt;&lt;/script&gt;&lt;div class=&#34;admonition-disclaimer admonition&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Disclaimer&lt;/p&gt;
&lt;p&gt;This post makes use of a number of interactive elements to help illustrate a few
concepts. Unfortunately these do not yet work on mobile devices - sorry mobile
users!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I have for quite some time now wanted to play around with web development some
more, particularly using web technologies to build user interfaces of some
kind. However there is just &lt;strong&gt;so much&lt;/strong&gt; out there it’s been impossible for me to
really get anywhere past a “Hello, World!” tutorial before I find myself trying
out the next new shiny.&lt;/p&gt;
&lt;p&gt;So I’ve decided to abandon everything and try a bottom up approach where I see
how far I can push the core web technologies - HTML, CSS and
JavaScript. Hopefully then by the time I start using one of the gazillion
libraries out there I will have a better understanding of why I
needed it in the first place.&lt;/p&gt;
&lt;p&gt;In this post I will be looking at implementing clicking and dragging
functionality using only vanilla JavaScript. Clicking and dragging as a concept
can apply to many kinds of interactions so in this instance I’m specifically
referring to clicking on an SVG element moving it around on the page as
illustrated by the demo above.&lt;/p&gt;
&lt;/div&gt;
&lt;section id=&#34;setup&#34;&gt;
&lt;h2&gt;Setup&lt;a class=&#34;headerlink&#34; href=&#34;#setup&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All we need to get started is a HTML document that contains some markup which
provides someplace we can reference and attach our image element to, as well as
loading the code we write.&lt;/p&gt;
&lt;div class=&#34;highlight-html notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;/js/click-drag.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then the first step is to create our SVG image element to act as our “canvas”
that we can draw on.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;svgns&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;http://www.w3.org/2000/svg&amp;quot;&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getElementById&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createElementNS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;svgns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;svg&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;width&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;height&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;style&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;border&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;solid 2px #242930&amp;quot;&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;appendChild&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A few things to note:&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;By adding our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;svg&amp;gt;&lt;/span&gt;&lt;/code&gt; element as a child of some &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;/code&gt; element and setting
both the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;width&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;height&lt;/span&gt;&lt;/code&gt; to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;100%&lt;/span&gt;&lt;/code&gt; our canvas will be able to
scale responsively based on the styles applied to the parent &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You might already be familiar with the &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement&#34;&gt;document.createElement()&lt;/a&gt; function for
creating HTML elements using JavaScript. However in order to work with SVG
elements we need to use the &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS&#34;&gt;document.createElementNS()&lt;/a&gt; function which allows
us to use the SVG namespace instead of the HTML default.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;the-view-box&#34;&gt;
&lt;h2&gt;The View Box&lt;a class=&#34;headerlink&#34; href=&#34;#the-view-box&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next step is to construct an appropriate &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; definition for our
canvas. For more information on the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; you can refer to the &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox&#34;&gt;documentation&lt;/a&gt;
but to briefly summarise. An SVG image exists on an infinite plane and the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; is the window we use to view a portion of that space, changing the
definition of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; allows you to zoom in and out on particular regions.&lt;/p&gt;
&lt;p&gt;For our purposes what’s important is that we construct a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; that matches
the proportions of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;svg&amp;gt;&lt;/span&gt;&lt;/code&gt; element as it is displayed in the browser. If
these proportions do not match then the element being dragged around will not
accurately track the cursor, either racing away from or lagging behind it.&lt;/p&gt;
&lt;p&gt;One minor issue is that in our setup we didn’t explicitly set the dimensions of
our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;svg&amp;gt;&lt;/span&gt;&lt;/code&gt; element - so how can we know its proportions? Thankfully once the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;svg&amp;gt;&lt;/span&gt;&lt;/code&gt; as been added to the page we can ask the browser for the bounding box
around the element.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Among other properties that are outlined on &lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect&#34;&gt;this&lt;/a&gt; page we can get the width and
height of the rendered image in pixels from which its easy to calculate the
aspect ratio.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;aspectRatio&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We’re free to choose whichever scale we want for the vertical height of the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; into the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;svg&amp;gt;&lt;/span&gt;&lt;/code&gt; element. I have chosen &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;100&lt;/span&gt;&lt;/code&gt; simply because it feels
like a nice round number. Once we’ve decided on a scale for the height, it’s
easy enough to calculate the corresponding width from our aspect ratio.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;100&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;aspectRatio&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With the dimensions of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; taken care of all that is left to do is
decide on the coordinates to assign to the top left corner of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;svg&amp;gt;&lt;/span&gt;&lt;/code&gt;
element and assign the view box to our canvas.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minX&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBoxStr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;viewBox&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBoxStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;something-to-click-on&#34;&gt;
&lt;h2&gt;Something to Click on&lt;a class=&#34;headerlink&#34; href=&#34;#something-to-click-on&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By this point we have finished preparing our canvas and it’s time to add
something for us to interact with. To keep things simple I will stick to a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;circle&amp;gt;&lt;/span&gt;&lt;/code&gt;
element, though the method we use here should apply to any SVG element (or any
collection of elements under a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;g&amp;gt;&lt;/span&gt;&lt;/code&gt; tag).&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createElementNS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;svgns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;circle&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cx&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cy&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;fill&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;#57cc8a&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;appendChild&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;admonition note&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Note&lt;/p&gt;
&lt;p&gt;Of course the way in which you define the position of your interactive element
will depend on the element you have chosen.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;implementing-the-drag&#34;&gt;
&lt;h2&gt;Implementing the Drag&lt;a class=&#34;headerlink&#34; href=&#34;#implementing-the-drag&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We will create an event handler for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mousemove&lt;/span&gt;&lt;/code&gt; event and attach it to
our canvas.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;mousemove&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Do something clever here...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The function we write will be called every time the cursor moves regardless of
whether the user has clicked or not. This means our event handler has to be able
to cope with two situations, the cursor moving when the user has clicked and the
cursor moving when the user has not clicked.&lt;/p&gt;
&lt;p&gt;To do this we will declare a variable called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;clicked&lt;/span&gt;&lt;/code&gt; outside the scope of our
function.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clicked&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For the moment we will ignore the details around how this variable is updated
(it is covered in the next section), instead let’s focus on what we do while the
cursor is moving about the page&lt;/p&gt;
&lt;p&gt;Let’s get the simpler case out of the way first&lt;/p&gt;
&lt;section id=&#34;not-clicked&#34;&gt;
&lt;h3&gt;Not Clicked&lt;a class=&#34;headerlink&#34; href=&#34;#not-clicked&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When the mouse is moving but the user has not clicked, then there is nothing for
us to do! We can simply check the value of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;clicked&lt;/span&gt;&lt;/code&gt; variable and stop the
function if it meets the criteria.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clicked&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;clicked&#34;&gt;
&lt;h3&gt;Clicked&lt;a class=&#34;headerlink&#34; href=&#34;#clicked&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now for the interesting part! The mouse is moving and the user has clicked on
the circle, all we have to do now is update its position to match
the cursor’s current position. The only problem is… where is it?&lt;/p&gt;
&lt;p&gt;Like all mouse related events the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;event&lt;/span&gt;&lt;/code&gt; object passed into the event handler
will contain a number of position related properties.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;e.client&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt;: Coordinates of the cursor with respect to the current portion
of the document visible on the page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;e.offset&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt;: Coordinates of the cursor with respect to the edge of the
target element&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;e.page&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt;: Coordinates of the cursor with respect to the entire HTML page,
including any portions of the page not currently visible&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;e.screen&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt;: Coordinates of the cursor with respect to the user’s display&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reading through those descriptions you would imagine that the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;e.offset&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt;
properties would be the best fit for our use case. However it’s not quite as
simple as that.&lt;/p&gt;
&lt;p&gt;Below you should see 2 boxes, the bigger one on the left is our canvas. The
smaller box on the right contains a smaller circle that represents the
calculated position of the cursor based on the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;offset&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt; properties like so.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;offsetX&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;offsetY&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Try moving the mouse across the canvas and keep an eye on the calculated
position.&lt;/p&gt;
&lt;figure&gt;
  &lt;div id=&#34;offset-demo&#34;
       style=&#34;display:grid;grid-template-columns:50% auto;grid-gap:10px&#34;&gt;
  &lt;h3 id=&#34;offset-title&#34; style=&#34;margin: 0; padding: 15px; padding-top: 0&#34;&gt;
    Cursor Position: Offset
  &lt;/h3&gt;
    &lt;div&gt;
      &lt;p style=&#34;margin:0;padding-left:20px&#34;&gt;Target: &lt;span id=&#34;offset-target&#34;&gt;&lt;/span&gt;&lt;/p&gt;
      &lt;p style=&#34;margin:0;padding-left:20px&#34;&gt;Position: &lt;span id=&#34;offset-position&#34;&gt;&lt;/span&gt;&lt;/p&gt;
    &lt;/div&gt;
    &lt;svg width=&#34;100%&#34;
         id=&#34;offset-demo-canvas&#34;
         style=&#34;border: solid 2px var(--border-color)&#34;&gt;
    &lt;/svg&gt;
    &lt;svg width=&#34;50%&#34;
         id=&#34;offset-posbox&#34;
         style=&#34;border: solid 2px var(--border-color);margin:auto&#34;&gt;&lt;svg&gt;
  &lt;/div&gt;
  &lt;figcaption&gt;
    &lt;p&gt;
      Determining the cursor&#39;s position using the &lt;code&gt;event.offsetX&lt;/code&gt; and
      &lt;code&gt;event.offsetY&lt;/code&gt; properties
    &lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;script type=&#34;text/javascript&#34; src=&#34;/_static/js/click-drag-offset.js&#34;&gt;&lt;/script&gt;&lt;p&gt;Notice the issue when we move across the circle? Why does the calculated
position of the cursor suddenly jump whenever we touch it? The answer lies in
the description of the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;offset&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt; property “with respect to the edge of the
&lt;strong&gt;target&lt;/strong&gt; element”&lt;/p&gt;
&lt;p&gt;When initially trying to implement this I incorrectly assumed that the target
element meant the element that we attached the event listener to - the canvas. In
fact the target element is whichever element is currently under the cursor&lt;/p&gt;
&lt;p&gt;To work around this we can calculate the offset values we need ourselves. In
order to do this we will make use of both the bounding box returned from the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;canvas.getBoundingClientRect()&lt;/span&gt;&lt;/code&gt; method as well as the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;client&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt; properties
found on the mouse event.&lt;/p&gt;
&lt;p&gt;It turns out that the bounding box also returns the coordinates of the top left
corner of the canvas relative to the user’s current view of the document -
exactly the same coordinate system used by the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;client&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt; properties! From
those two pieces of information it’s easy enough to recover the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;offset&amp;lt;XY&amp;gt;&lt;/span&gt;&lt;/code&gt;
values ourselves.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientX&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;left&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;top&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;By calculating the coordinates using values that are independent of the element
currently underneath the cursor we sidestep any issues that arise from a
changing target. Try the same thing again on the canvas below.&lt;/p&gt;
&lt;figure&gt;
&lt;div id=&#34;client-demo&#34;
      style=&#34;display:grid;grid-template-columns:50% auto;grid-gap:10px&#34;&gt;
   &lt;h3 id=&#34;offset-title&#34; style=&#34;margin: 0; padding: 15px; padding-top: 0&#34;&gt;
      Cursor Position: Client
   &lt;/h3&gt;
   &lt;div&gt;
      &lt;p style=&#34;margin:0;padding-left:20px&#34;&gt;Target: &lt;span id=&#34;client-target&#34;&gt;&lt;/span&gt;&lt;/p&gt;
      &lt;p style=&#34;margin:0;padding-left:20px&#34;&gt;Position: &lt;span id=&#34;client-position&#34;&gt;&lt;/span&gt;&lt;/p&gt;
   &lt;/div&gt;
   &lt;svg width=&#34;100%&#34;
         id=&#34;client-demo-canvas&#34;
         style=&#34;border: solid 2px var(--border-color)&#34;&gt;
   &lt;/svg&gt;
      &lt;svg width=&#34;50%&#34;
         id=&#34;client-posbox&#34;
         style=&#34;border: solid 2px var(--border-color);margin:auto&#34;&gt;&lt;svg&gt;
&lt;/div&gt;
&lt;figcaption&gt;
   &lt;p&gt;
      Determining the cursor&#39;s position using the &lt;code&gt;event.clientX&lt;/code&gt; and
      &lt;code&gt;event.clientY&lt;/code&gt; properties
   &lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;script type=&#34;text/javascript&#34; src=&#34;/_static/js/click-drag-client.js&#34;&gt;&lt;/script&gt;&lt;div class=&#34;admonition important&#34;&gt;
&lt;p class=&#34;admonition-title&#34;&gt;Important&lt;/p&gt;
&lt;p&gt;Since the values &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;bbox.top&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;bbox.left&lt;/span&gt;&lt;/code&gt; are defined relative to the user’s
current view on the document these values are &lt;strong&gt;not&lt;/strong&gt; constant. They will change
whenever the user alters their view of the page, i.e. performing actions like
resizing the window or scrolling. This is why we ask for an updated bounding box
every time our event handler is called.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now that we can reliably know the position of the cursor, we can focus on the
final piece of this puzzle - updating the position of our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;circle&amp;gt;&lt;/span&gt;&lt;/code&gt;
element. There is however one further issue to work through. The position of the
cursor that we’ve just calculated is using a different coordinate system to the
one used to draw our circle!&lt;/p&gt;
&lt;p&gt;Although we have managed to correctly calculate the cursor’s position relative
to our canvas, that position is measured using pixels which makes it highly
dependent on the resolution of the user’s screen. A user who uses a 4K monitor
and positions their cursor at the bottom right of the canvas will have a
calculated position much larger than a user on a smartphone…&lt;/p&gt;
&lt;p&gt;What this means is that if we map this calculated position directly onto the
circle it won’t accurately follow the cursor. The only time the circle would
follow the cursor correctly is when the pixel based coordinates line up with the
coordinate system used in the SVG image. I.e. when the dimensions of the canvas
match up &lt;strong&gt;exactly&lt;/strong&gt; with the scale used to define our &lt;cite&gt;viewBox&lt;/cite&gt; which in this
case would be &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;100px&lt;/span&gt;&lt;/code&gt; tall&lt;/p&gt;
&lt;p&gt;Since the mouse circle and the circle use different coordinate systems, we don’t
actually care about the exact position we have just calculated. What’s more
important is the position of the cursor relative to bounds of the canvas - a
percentage. For example, let’s say that the cursor was halfway down the canvas
(&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;50%&lt;/span&gt;&lt;/code&gt;) then we could calculate the corresponding coordinate value in the SVG
coordinate system by multiplying the total height by &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;50%&lt;/span&gt;&lt;/code&gt;. In our particular
case this would mean setting &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;0.5&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;50&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can adopt this approach by using the &lt;cite&gt;width&lt;/cite&gt; and &lt;cite&gt;height&lt;/cite&gt; information
returned as part of the bounding box to modify our calculation to produce a
percentage rather than an absolute value.&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientX&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;
&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;top&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To then convert this percentage into its corresponding value in the SVG
coordinate system all we have to do is multiply it by the width and height of
that system and assign the result to our circle’s position!&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttriubte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cx&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cy&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Bringing all that together we end up with the following implementation of our
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mousemove&lt;/span&gt;&lt;/code&gt; event handler.&lt;/p&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;mousemove&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clicked&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientX&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clientY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;top&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;

&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cx&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cy&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Nearly there! The only thing left to do is decide on how we want to update the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;clicked&lt;/span&gt;&lt;/code&gt; variable.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;click-detection&#34;&gt;
&lt;h2&gt;Click Detection&lt;a class=&#34;headerlink&#34; href=&#34;#click-detection&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finally all that’s left is to do is decide how we want to toggle the dragging
behaviour. This mostly comes down to how you want the user to interact with the
draggable object and will change depending on your use case. To keep things
simple I will go with a fairly simple interaction model&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;If the mouse is over the circle and the user clicks then start dragging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the user releases the mouse button then stop dragging&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;mousedown&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clicked&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;mouseup&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clicked&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Additionally I will impose one final condition&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;If the mouse leaves the bounds of the canvas then stop dragging.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;awdur-codeblock docutils container&#34;&gt;
&lt;div class=&#34;awdur-codeblock-header docutils container&#34;&gt;
&lt;code class=&#34;awdur-codeblock-filename docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;click-drag.js&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;canvas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;mouseleave&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clicked&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This last point is to work around an issue that arises when the user moves the
cursor out of the bounds of the canvas and releases the mouse button. Since the
cursor is no longer over the circle the handler for the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mouseup&lt;/span&gt;&lt;/code&gt; event on the
circle is never fired so when the user brings their cursor back over the canvas
our code still believes the user never released the mouse button and so the
circle will appear “stuck” to their cursor until they click again.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;conclusion&#34;&gt;
&lt;h2&gt;Conclusion&lt;a class=&#34;headerlink&#34; href=&#34;#conclusion&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There you have it, those were some of the basics required to get a working proof
of concept of clicking and dragging functionality using only the JavaScript APIs
that come with your web browser. However in writing this blog post I realised
as with anything that the rabbit hole goes deep and there are many
considerations to keep in mind if you wanted to “productionise” this code for
any real usage.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Touchscreen Support&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you were reading this post on a mobile device you will already have noticed
that none of the interactive demos have worked. This is because touchscreens
have their own family of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;touchXXXX&lt;/span&gt;&lt;/code&gt; events that are triggered when a user
interacts with a webpage. While there is some mouse emulation done by the
browsers (e.g. a &lt;cite&gt;touchstart&lt;/cite&gt; event will trigger a &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mousedown&lt;/span&gt;&lt;/code&gt; event if not
handled), some key events such as &lt;cite&gt;mousemove&lt;/cite&gt; are not emulated and require
dedicated support in your code. See &lt;a class=&#34;reference external&#34; href=&#34;https://www.html5rocks.com/en/mobile/touch/&#34;&gt;these&lt;/a&gt; &lt;a class=&#34;reference external&#34; href=&#34;https://www.html5rocks.com/en/mobile/touchandmouse/&#34;&gt;articles&lt;/a&gt; for more details&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Snap to Center&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is only a minor issue and depending on your use case may not be a problem
at all. Currently whenever you pick up the circle its center snaps to the
cursor’s position. There may be situations where you would prefer the keep the
object’s relative position to the cursor e.g. fine adjustments, the last thing
you would want is for the object to jump to the cursor just because the user
happened to click on it off center.&lt;/p&gt;
&lt;p&gt;A way around this would be to record the original positions of both the mouse
cursor and the object on a click, then on each &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;mousemove&lt;/span&gt;&lt;/code&gt; event calculate the
distance moved by the cursor and apply it to the original recorded position of
the object.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple Objects&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Chances are when using this functionality in a real application you would want
the ability to click and drag on multiple objects. Adding support for this
would require reworking at least some of the code, having the canvas object
handle all mouse movements is probably a good idea but of course updating the
circle’s position directly would have to change. It would probably make sense
to move the click detection logic onto the canvas also, making use of the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;event.target&lt;/span&gt;&lt;/code&gt; property to determine which object would need updating.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Canvas Resizing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While the existing code makes some effort to ensure this works in a responsive
manner it is currently only “statically responsive”. What I mean is that on
page load all the necessary calculations are performed to ensure that the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; has the correct proportions for example. However if the user were to
resize the webpage, or rotate their device chances are the proportions of the
canvas would change meaning that the circle would no longer follow the cursor
correctly.&lt;/p&gt;
&lt;p&gt;In order to be truly responsive, we would need to listen for events such as
&lt;a class=&#34;reference external&#34; href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Window/resize%5Fevent&#34;&gt;resize&lt;/a&gt; and perform all the calculations again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pan and Zoom&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Something I realised when writing up the part where we map the cursor’s
position onto the position of the circle is that I had by chance chosen a
special case where the maths is a little easier. The calculations
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;viewBox.width&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;viewBox.height&lt;/span&gt;&lt;/code&gt; only work because our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; starts
at &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;(0,&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;0)&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Say we had an application that also allowed for panning and zooming of the
canvas itself then the chances are our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;viewBox&lt;/span&gt;&lt;/code&gt; would not be starting at
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;(0,&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;0)&lt;/span&gt;&lt;/code&gt; and we would have to include an offset in our calculations to reflect
this. This means for the general case our code should probably look something
like this&lt;/p&gt;
&lt;div class=&#34;highlight-js notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cx&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nx&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;cy&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;viewBox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;minY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m sure there are more edge cases and considerations to think of but this post
is long enough already! - Perhaps this is why people use libraries for this kind
of thing 🤔…&lt;/p&gt;
&lt;p&gt;If you are interested you can find the final version of the code &lt;a class=&#34;reference internal&#34; href=&#34;../code/#code-click-drag&#34;&gt;&lt;span class=&#34;std std-ref&#34;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2019/til-python-cmd/</id>
    <link href="https://www.alcarney.me/blog/2019/til-python-cmd" rel="alternate" />
    <published>2019-01-05T00:00:00+00:00</published>
    <updated>2019-01-05T00:00:00+00:00</updated>
    <title>TIL: Python has a cmd module</title>
    <content type="html">
      &lt;section id=&#34;til-python-has-a-cmd-module&#34;&gt;
&lt;h1&gt;TIL: Python has a cmd module&lt;a class=&#34;headerlink&#34; href=&#34;#til-python-has-a-cmd-module&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;Today I Learned that Python’s standard library has a &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/library/cmd.html&#34;&gt;cmd&lt;/a&gt; module and it is &lt;em&gt;awesome!&lt;/em&gt;&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id1&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/cmd_python.gif&#34; src=&#34;https://www.alcarney.me/_images/cmd_python.gif&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;Interactive program using the cmd module&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id1&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/library/cmd.html&#34;&gt;cmd&lt;/a&gt; module contains a single class called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Cmd&lt;/span&gt;&lt;/code&gt; which handles all the
details of creating an application similar to Python’s REPL. All you need to do
is to provide some command definitions and the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;Cmd&lt;/span&gt;&lt;/code&gt; class will handle the rest.&lt;/p&gt;
&lt;p&gt;In an attempt to demonstrate why I think this is so cool I’m going to walk
through the process of building the application you see in the screencast above.&lt;/p&gt;
&lt;p&gt;The example application we’re going to create is a very basic REPL for a passion
project of mine called &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/stylo&#34;&gt;stylo&lt;/a&gt;. Stylo is a Python library that allows you to draw
images and create animations using code and some mathematics. The application
will expose some of the basic shapes available and for the “Print” part of the
&lt;a class=&#34;reference external&#34; href=&#34;https://en.wikipedia.org/wiki/Read%25E2%2580%2593eval%25E2%2580%2593print%5Floop&#34;&gt;REPL&lt;/a&gt; it will show a preview of your image.&lt;/p&gt;
&lt;p&gt;My main focus for this post is the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;cmd&lt;/span&gt;&lt;/code&gt; module which means I’m not going to go
into any of the specifics of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;stylo&lt;/span&gt;&lt;/code&gt; or how to use it. If you want to know more
about it I will point you in the direction of the &lt;a class=&#34;reference external&#34; href=&#34;https://stylo.readthedocs.io/&#34;&gt;documentation&lt;/a&gt;
(under construction) and the &lt;a class=&#34;reference external&#34; href=&#34;https://alcarney.github.io/stylo-doodles&#34;&gt;example gallery&lt;/a&gt;&lt;/p&gt;
&lt;section id=&#34;setup&#34;&gt;
&lt;h2&gt;Setup&lt;a class=&#34;headerlink&#34; href=&#34;#setup&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To start with we’re going to create a virtual environment and install &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;stylo&lt;/span&gt;&lt;/code&gt;
into it. This will also install &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;matplotlib&lt;/span&gt;&lt;/code&gt; which we will be using later on.
I’m using Python 3.7 but this application should work on all versions of Python
≥ 3.5.&lt;/p&gt;
&lt;div class=&#34;highlight-console notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;python&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-m&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;venv&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;env
&lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;env/bin/activate
&lt;span class=&#34;gp gp-VirtualEnv&#34;&gt;(env)&lt;/span&gt; &lt;span class=&#34;gp&#34;&gt;$ &lt;/span&gt;pip&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;install&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;stylo
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;cmd&lt;/span&gt;&lt;/code&gt; module is available for &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/2.7/library/cmd.html&#34;&gt;even older&lt;/a&gt; versions of
Python. However we are limited by &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;stylo&lt;/span&gt;&lt;/code&gt; which only supports Python 3.5+&lt;/p&gt;
&lt;p&gt;With the dependencies out of the way we can create a file called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;stylo-cmd.py&lt;/span&gt;&lt;/code&gt;
and start writing some code!&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;cmd&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;StyloPrompt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;k&#34;&gt;pass&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;prompt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StyloPrompt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
 &lt;span class=&#34;n&#34;&gt;prompt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmdloop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is the bare minimum required to get something we can start playing with.
If you were to run &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;stylo-cmd.py&lt;/span&gt;&lt;/code&gt; you would see the following prompt
which comes with a single built-in command &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;help&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(Cmd) help

Documented commands (type help &amp;lt;topic&amp;gt;):
========================================
help
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;Ctrl&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt; will exit the application. Obviously this is pretty useless right now
so let’s look at adding in some commands of our own.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;adding-commands&#34;&gt;
&lt;h2&gt;Adding Commands&lt;a class=&#34;headerlink&#34; href=&#34;#adding-commands&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Any method on our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;StyloPrompt&lt;/span&gt;&lt;/code&gt; class with a name of the form &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;do_*&lt;/span&gt;&lt;/code&gt; is
considered a command, with the command name given by whatever is after the
underscore.  To get ourselves warmed up let’s add two commands &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;reset&lt;/span&gt;&lt;/code&gt; and
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;save&lt;/span&gt;&lt;/code&gt; which will allow us to create a fresh image and save it to a file.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;stylo.image&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LayeredImage&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;StyloPrompt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;nb&#34;&gt;super&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LayeredImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;do_reset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LayeredImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;do_save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As you can see each command receives its arguments as a single string and
it is up to the method to handle them - including conversions to appropriate
data types as is the case with the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;width&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;height&lt;/span&gt;&lt;/code&gt; arguments. For the sake
of being brief proper error handling has been omitted.&lt;/p&gt;
&lt;p&gt;Now if we were to fire up the application we would be able to produce an image!&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(Cmd) reset
(Cmd) save 1920 1080 image.png
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Of course this image is currently empty so next we should add the ability for
the user to place shapes on the image. We’ll create two more commands &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;circle&lt;/span&gt;&lt;/code&gt;
and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;square&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;stylo.color&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FillColor&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;stylo.shape&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Square&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;StyloPrompt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;do_circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;color&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;circle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fill&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_layer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FillColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;do_square&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;color&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;square&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Square&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_layer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;square&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FillColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now when we use the application we can create something a bit more
interesting than a snowman in a blizzard!&lt;/p&gt;
&lt;figure class=&#34;align-center&#34; id=&#34;id2&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/dice.png&#34; src=&#34;https://www.alcarney.me/_images/dice.png&#34; /&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class=&#34;caption-text&#34;&gt;Number 3 on a dice&lt;/span&gt;&lt;a class=&#34;headerlink&#34; href=&#34;#id2&#34; title=&#34;Link to this image&#34;&gt;¶&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(Cmd) square 0 0 1.75 000000
(Cmd) circle 0 0 0.3 ffffff
(Cmd) circle -0.5 0.5 0.3 ffffff
(Cmd) circle 0.5 -0.5 0.3 ffffff
(Cmd) save 1920 1080 image.png
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;getting-help&#34;&gt;
&lt;h2&gt;Getting Help&lt;a class=&#34;headerlink&#34; href=&#34;#getting-help&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we have a few commands available we need to tell users how they can be
used. If we were to use the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;help&lt;/span&gt;&lt;/code&gt; command we would see something like the
following.&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(Cmd) help

Documented commands (type help &amp;lt;topic&amp;gt;):
========================================
help

Undocumented commands:
======================
circle reset save square
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Not very helpful.&lt;/p&gt;
&lt;p&gt;Thankfully the default help system doesn’t require much to get started, all we
have to do is add docstrings to our &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;do_*&lt;/span&gt;&lt;/code&gt; methods!&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;do_circle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;usage: circle &amp;lt;x&amp;gt; &amp;lt;y&amp;gt; &amp;lt;r&amp;gt; &amp;lt;color&amp;gt;&lt;/span&gt;

&lt;span class=&#34;sd&#34;&gt;   This command will draw a circle centered at the coordinates (&amp;lt;x&amp;gt;, &amp;lt;y&amp;gt;)&lt;/span&gt;
&lt;span class=&#34;sd&#34;&gt;   with radius given by &amp;lt;r&amp;gt;. The &amp;lt;color&amp;gt; argument is a 6 digit hex&lt;/span&gt;
&lt;span class=&#34;sd&#34;&gt;   representing a color in RGB format.&lt;/span&gt;
&lt;span class=&#34;sd&#34;&gt;   &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now if we were to run &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;help&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;circle&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(Cmd) help circle
circle &amp;lt;x&amp;gt; &amp;lt;y&amp;gt; &amp;lt;r&amp;gt; &amp;lt;color&amp;gt;

      This command will draw a circle centered at the coordinates (&amp;lt;x&amp;gt;, &amp;lt;y&amp;gt;)
      with radius given by &amp;lt;r&amp;gt;. The &amp;lt;color&amp;gt; argument is a 6 digit hex
      representing a color in RGB format.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Much better&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;giving-feedback&#34;&gt;
&lt;h2&gt;Giving Feedback&lt;a class=&#34;headerlink&#34; href=&#34;#giving-feedback&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Right now our program is… ok. The user can type in a few commands and they
can create some images, but it’s not much of a step up from using the library
as they still have to wait until they have saved their image before
they can view it. Add in the fact that our program isn’t that flexible they may
as well be using the library directly.&lt;/p&gt;
&lt;p&gt;If only there was some way we could show the user their image as they build it
up a command at a time…&lt;/p&gt;
&lt;p&gt;Enter &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;postcmd&lt;/span&gt;&lt;/code&gt;! This handy method is called each time our program has
processed a command - we can use this to redraw the image each time.
Then “all” we have to do if find a way to display the current image to the user.&lt;/p&gt;
&lt;p&gt;After some searching and head scratching I was able to come up with the
following &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;matplotlib&lt;/span&gt;&lt;/code&gt; incantation to add our image to a figure and display it.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;matplotlib.pyplot&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;plt&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;StyloPrompt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;

      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;plt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subplots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ax&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_xaxis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_visible&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;False&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ax&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_yaxis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_visible&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;False&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update_image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;postcmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;

      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;

      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update_image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;update_image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;

      &lt;span class=&#34;c1&#34;&gt;# Re-render the image&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1920&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1080&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;c1&#34;&gt;# Update the preview&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ax&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;imshow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fig&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I won’t go into too much detail here but I will point out a few things.&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;stop&lt;/span&gt;&lt;/code&gt; argument to &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;postcmd&lt;/span&gt;&lt;/code&gt; indicates whether the previous command
wanted to exit the program (by returning &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;True&lt;/span&gt;&lt;/code&gt;). We have the option of
overriding that by not returning &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;True&lt;/span&gt;&lt;/code&gt;. But in our case we will just pass
the message on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Matplotlib is smart enough to use an existing window when calling &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;show()&lt;/span&gt;&lt;/code&gt; on
a figure so all we have to do is update the plot in the axis object&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;__init__&lt;/span&gt;&lt;/code&gt; method we are disabling the scale on the axis so that the
user doesn’t see something that looks like a graph.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;finishing-touches&#34;&gt;
&lt;h2&gt;Finishing Touches&lt;a class=&#34;headerlink&#34; href=&#34;#finishing-touches&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With most of the functionality out of the way we can look at tweaking
some things to make the overall experience nicer.&lt;/p&gt;
&lt;section id=&#34;exiting-the-program&#34;&gt;
&lt;h3&gt;Exiting the Program&lt;a class=&#34;headerlink&#34; href=&#34;#exiting-the-program&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So far we don’t have a clean way to close the program, we can hit &lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;Ctrl&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;C&lt;/kbd&gt; to
terminate the script but it results in Python printing a traceback and it looks
like an error in our program more than anything.&lt;/p&gt;
&lt;p&gt;Instead we can override the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;default&lt;/span&gt;&lt;/code&gt; method on our class. This method is
called whenever the program doesn’t recogise the user’s input as a valid
command and we can use it to look at all of the user’s input (not just the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;args&lt;/span&gt;&lt;/code&gt;) and decide what to do with it.&lt;/p&gt;
&lt;p&gt;In this case we will say that the program will exit whenever the user types a
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;q&lt;/span&gt;&lt;/code&gt; or we receive an &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;EOF&lt;/span&gt;&lt;/code&gt; character (&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;Ctrl&lt;/kbd&gt;-&lt;kbd class=&#34;kbd docutils literal notranslate&#34;&gt;D&lt;/kbd&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;StyloPrompt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;

   &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;q&amp;quot;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;EOF&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;

      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;super&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;changing-the-prompt&#34;&gt;
&lt;h3&gt;Changing the Prompt&lt;a class=&#34;headerlink&#34; href=&#34;#changing-the-prompt&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We can change the default prompt &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;(Cmd)&lt;/span&gt;&lt;/code&gt; by setting the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;prompt&lt;/span&gt;&lt;/code&gt; attribute on
our class.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;StyloPromt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;prompt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;-&amp;gt; &amp;quot;&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&#34;greeting-the-user&#34;&gt;
&lt;h3&gt;Greeting the User&lt;a class=&#34;headerlink&#34; href=&#34;#greeting-the-user&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Currently when our program starts it simply shows them the prompt, which if
they are using it for the first time they probably won’t know where to start.
To help them get started we can set the &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;intro&lt;/span&gt;&lt;/code&gt; attribute to contain a welcome
message.&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;stylo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__version__&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;intro_text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;Interactive Shell for Stylo v&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;----------------------------------&lt;/span&gt;

&lt;span class=&#34;s2&#34;&gt;Type `q` or `Ctrl-D` to quit.&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;Type `help` or `?` for an overview `help &amp;lt;command&amp;gt;` for more details.&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;StyloPrompt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
   &lt;span class=&#34;n&#34;&gt;intro&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;intro_text&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__version__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
   &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now when the user starts the program they should have enough information to
continue from there.&lt;/p&gt;
&lt;div class=&#34;highlight-none notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Interactive Shell for Stylo v0.9.1
----------------------------------

Type `q` or `Ctrl-D` to quit.
Type `help` or `?` for an overview `help &amp;lt;command&amp;gt;` for more details.

-&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There are also &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;doc_header&lt;/span&gt;&lt;/code&gt;, &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;misc_header&lt;/span&gt;&lt;/code&gt; and &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;undoc_header&lt;/span&gt;&lt;/code&gt; that you can set
to include even more information at different points in your program. You can
refer to the &lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/library/cmd.html&#34;&gt;docs&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&#34;wrapping-up&#34;&gt;
&lt;h2&gt;Wrapping Up&lt;a class=&#34;headerlink&#34; href=&#34;#wrapping-up&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I can’t believe I only just found out about this module. I hope you found this
as useful as I did and I strongly encourage you to take a look at the
&lt;a class=&#34;reference external&#34; href=&#34;https://docs.python.org/3/library/cmd.html&#34;&gt;docs&lt;/a&gt; as there are features there that I didn’t get around to
mentioning - such as completion!&lt;/p&gt;
&lt;p&gt;For those interested the final version of this program (with a few minor
tweaks) is available as a &lt;a class=&#34;reference external&#34; href=&#34;https://gist.github.com/alcarney/2f58820dd7a7c999197a450cf2069954&#34;&gt;Gist&lt;/a&gt; on Github. I think what I like most
about this module is that it requires very little code before you start seeing
real results - Our entire application is only 155 lines of code!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2018/introducing-stylo-doodles/</id>
    <link href="https://www.alcarney.me/blog/2018/introducing-stylo-doodles" rel="alternate" />
    <published>2018-10-12T00:00:00+00:00</published>
    <updated>2018-10-12T00:00:00+00:00</updated>
    <title>Introducing Stylo Doodles!</title>
    <content type="html">
      &lt;section id=&#34;introducing-stylo-doodles&#34;&gt;
&lt;h1&gt;Introducing Stylo Doodles!&lt;a class=&#34;headerlink&#34; href=&#34;#introducing-stylo-doodles&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;A few weeks back at &lt;a class=&#34;reference external&#34; href=&#34;https://2018.pyconuk.org/&#34;&gt;PyConUK&lt;/a&gt; I gave my first &lt;a class=&#34;reference external&#34; href=&#34;https://youtu.be/F5jSUJVymXk?t=3480&#34;&gt;lighting talk&lt;/a&gt;
at a conference. During that talk I spoke publically about &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/stylo&#34;&gt;stylo&lt;/a&gt; for
the first time. Stylo is a Python library that I have been working on for just
over a year and a half and it aims to make the creation of images easier by
bringing together ideas from programming and mathematics.&lt;/p&gt;
&lt;p&gt;Version &lt;a class=&#34;reference external&#34; href=&#34;https://alcarney.github.io/stylo/changes.html&#34;&gt;0.6.0&lt;/a&gt; was recently released which included the first feature
that wasn’t written by me! It’s very exciting not only to see other people
starting to take an interest in the project but taking the time to make a
contribution!&lt;/p&gt;
&lt;p&gt;Now that stylo seems to be getting to the point that it might me useful to
other people wouldn’t it be great if there was a community driven example
gallery that people could get inspired by? - Well now there is! And it’s
called &lt;a class=&#34;reference external&#34; href=&#34;https://alcarney.github.io/stylo-doodles&#34;&gt;Stylo Doodles&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&#34;align-center&#34;&gt;
&lt;img alt=&#34;https://www.alcarney.me/_images/stylo-doodles.png&#34; src=&#34;https://www.alcarney.me/_images/stylo-doodles.png&#34; /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;All the examples are written as a &lt;a class=&#34;reference external&#34; href=&#34;https://jupyter.org&#34;&gt;Jupyter Notebook&lt;/a&gt; and can be submitted to the
gallery by opening a pull request against the stylo-doodles &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/stylo-doodles&#34;&gt;repository&lt;/a&gt;. A small
python application is then run that builds the website and pushes the update to
the live website.&lt;/p&gt;
&lt;section id=&#34;current-features&#34;&gt;
&lt;h2&gt;Current Features&lt;a class=&#34;headerlink&#34; href=&#34;#current-features&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The gallery website is very new but it currently has the following features&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;All images are displayed in a grid on the homepage with the order randomly
chosen each time the website is built.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each image has its own page (as shown above) which displays the full
resolution image along with information about the author, image and the
version of stylo used to generate it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The source code from the notebook is extracted and is also displayed
alongside the image.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can also play around with any example &lt;strong&gt;live in your browser&lt;/strong&gt; if you
follow the &lt;a class=&#34;reference external&#34; href=&#34;https://mybinder.org/v2/gh/alcarney/stylo-doodles/master&#34;&gt;binder&lt;/a&gt; link in the repository’s README.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&#34;adding-your-own-example&#34;&gt;
&lt;h2&gt;Adding Your Own Example&lt;a class=&#34;headerlink&#34; href=&#34;#adding-your-own-example&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have an image that you would like to share there are only a couple of
things you need to do:&lt;/p&gt;
&lt;ol class=&#34;arabic&#34;&gt;
&lt;li&gt;&lt;p&gt;Your image &lt;strong&gt;must&lt;/strong&gt; be stored in a variable called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;image&lt;/span&gt;&lt;/code&gt;. The build process
will &lt;a class=&#34;reference external&#34; href=&#34;https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Importing%2520Notebooks.html&#34;&gt;import your notebook&lt;/a&gt; as a Python module and look for a variable called
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;image&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You also need to provide some additional information to the build system
about your example in the form of a Python dictionary. This dictionary
&lt;strong&gt;must&lt;/strong&gt; be called &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;info&lt;/span&gt;&lt;/code&gt; and it must be in &lt;strong&gt;very first cell of the notebook&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight-python notranslate&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
     &lt;span class=&#34;s2&#34;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;Jack-O-Lantern&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
     &lt;span class=&#34;s2&#34;&gt;&amp;quot;author&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;Alex Carney&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
     &lt;span class=&#34;s2&#34;&gt;&amp;quot;github_username&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;alcarney&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
     &lt;span class=&#34;s2&#34;&gt;&amp;quot;stylo_version&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;0.6.0&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
     &lt;span class=&#34;s2&#34;&gt;&amp;quot;dimensions&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1920&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1080&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;stylo_version&lt;/span&gt;&lt;/code&gt; field should be set to the value of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;stylo.__version__&lt;/span&gt;&lt;/code&gt;
at the time you created your image. The &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;dimensions&lt;/span&gt;&lt;/code&gt; is tuple of the form
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;(width,&lt;/span&gt; &lt;span class=&#34;pre&#34;&gt;height)&lt;/span&gt;&lt;/code&gt; and will be used by the build system to determine the size
of the image (in pixels) when it renders the full size copy for its detail
page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once your example is ready open a pull request adding your notebook to the
&lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;notebooks/&lt;/span&gt;&lt;/code&gt; folder to the repository.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Be sure to check out the existing &lt;a class=&#34;reference external&#34; href=&#34;https://github.com/alcarney/stylo-doodles/tree/master/notebooks&#34;&gt;examples&lt;/a&gt; to use as a guide or drop by the
stylo &lt;a class=&#34;reference external&#34; href=&#34;https://gitter.im/stylo-py/Lobby&#34;&gt;Gitter&lt;/a&gt; room if you get stuck we’ll be more than happy to help!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&#34;future-developments&#34;&gt;
&lt;h2&gt;Future Developments&lt;a class=&#34;headerlink&#34; href=&#34;#future-developments&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Stylo Doodles is far from finished aside from adding examples there are many
more things that could be added to the website:&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User profiles:&lt;/strong&gt; A page for every author, which lists the examples they
have contributed to the gallery.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Search&lt;/strong&gt;: As the number of images grow users would probably want to be able
to tag their images and be able to narrow down the list of images on the
homepage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recently Added:&lt;/strong&gt; Since the order of the homepage is random, as the number
of images increases the chance of a new image being buried at the bottom will
also increase, it would be good to have a way of sorting the images by date
added.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Descriptions:&lt;/strong&gt; Jupyter Notebooks support more than just code. Cells
containing markdown can be placed in between code cells to provide extra
context and explanation. It would be great if we could include these on the
site as well.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are looking for a web based python project to get involved with this
would be a great one to get started with and I would be more than happy to have
a few contribuitors to work on this (or even stylo itself!) with me.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
  <entry>
    <id>https://www.alcarney.me/blog/2018/first-article/</id>
    <link href="https://www.alcarney.me/blog/2018/first-article" rel="alternate" />
    <published>2018-09-22T00:00:00+00:00</published>
    <updated>2018-09-22T00:00:00+00:00</updated>
    <title>I’ve Started a Blog… Again!</title>
    <content type="html">
      &lt;section id=&#34;i-ve-started-a-blog-again&#34;&gt;
&lt;h1&gt;I’ve Started a Blog… Again!&lt;a class=&#34;headerlink&#34; href=&#34;#i-ve-started-a-blog-again&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&#34;post-teaser docutils container&#34;&gt;
&lt;p&gt;Not that you would have known it, but I’ve had a blog since 2014.  Well 2015 if
you’re feeling generous, the first (and only) post went up in the last few
hours of New Year’s Eve. It was a look back on some of the projects I had
worked on that year and I announced my intentions to start blogging.&lt;/p&gt;
&lt;p&gt;Fast forward nearly 4 years and here I am announcing my intentions to start
blogging - &lt;strong&gt;again&lt;/strong&gt;. So I guess you are wondering what happened?&lt;/p&gt;
&lt;p&gt;I got lost.&lt;/p&gt;
&lt;p&gt;My first attempt at running a blog was using &lt;a class=&#34;reference external&#34; href=&#34;https://jekyllrb.com&#34;&gt;Jekyll&lt;/a&gt; and for some mystical reason
(It’s been so long I can’t actually remember why), I decided that it was not the
static site generator I was looking for. So I promptly set off on a voyage of
discovery in search of the ultimate static site generator.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Here is a list of some of the other static site generators I have played with
over the years in no particular order:&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;http://www.metalsmith.io/&#34;&gt;Metalsmith&lt;/a&gt;: Written in Javascript, this one appealed to me with
its “everything is a plugin” approach. In theory I should be able to add any
feature I wanted simply by finding/writing the right plugin.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://jaspervdj.be/hakyll/&#34;&gt;Hakyll&lt;/a&gt;: I was going through a Haskell phase and I thought it would
be a great idea to have my blog powered with it as well. &lt;strong&gt;Haskell all the
things!&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;http://www.sphinx-doc.org&#34;&gt;Sphinx&lt;/a&gt;: Sphinx is an awesome tool for writing
documentation. A big part of that is &lt;a class=&#34;reference external&#34; href=&#34;http://docutils.sourceforge.net/rst.html&#34;&gt;reStructuredText&lt;/a&gt;, add in the &lt;a class=&#34;reference external&#34; href=&#34;https://ablog.readthedocs.io/&#34;&gt;ABlog&lt;/a&gt;
extension and you should have a great setup for a blog.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://blog.getpelican.com/&#34;&gt;Pelican&lt;/a&gt; &amp;amp; &lt;a class=&#34;reference external&#34; href=&#34;https://getnikola.com/&#34;&gt;Nikola&lt;/a&gt;: However as Sphinx is primarily built
for documentation projects, I found that I was fighting it more
than anything. That led me to take a look at Pelican and Nikola, both written
in Python and have support for reStructuredText and
&lt;a class=&#34;reference external&#34; href=&#34;http://jupyter.org/&#34;&gt;Jupyter&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://vuepress.vuejs.org/&#34;&gt;Vuepress&lt;/a&gt;: Having played around a bit with &lt;a class=&#34;reference external&#34; href=&#34;https://vuejs.org/&#34;&gt;VueJS&lt;/a&gt;, the
thought of being able to take a dynamic site written in a powerful frontend
framework and make a static site out of it seemed appealing. The best of both
worlds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt;: Who &lt;strong&gt;doesn’t&lt;/strong&gt; want a static site generator written in Go? :)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class=&#34;reference external&#34; href=&#34;https://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt; &amp;amp; &lt;a class=&#34;reference external&#34; href=&#34;https://orgmode.org/&#34;&gt;org-mode&lt;/a&gt;: Yes, &lt;a class=&#34;reference external&#34; href=&#34;https://orgmode.org/worg/org-blog-wiki.html&#34;&gt;you can&lt;/a&gt; use emacs
as a static site generator.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point you might be wondering what was wrong with all of the above so
that after nearly 4 years of tinkering I still had nothing to show for it?&lt;/p&gt;
&lt;p&gt;Nothing. Absolutely nothing.&lt;/p&gt;
&lt;p&gt;The problem was with me. I wanted complete control over the output, from the
contents of &lt;code class=&#34;docutils literal notranslate&#34;&gt;&lt;span class=&#34;pre&#34;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/code&gt; to the CSS styling of links. There would always
be a point where I would start fighting against the very abstractions
designed to make my life easier! It got to the point where I even tried writing
my own static site generator…&lt;/p&gt;
&lt;section id=&#34;a-new-perspective&#34;&gt;
&lt;h2&gt;A New Perspective&lt;a class=&#34;headerlink&#34; href=&#34;#a-new-perspective&#34; title=&#34;Link to this heading&#34;&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After endless hours lost fiddling with scripts and stylesheets I stumbled
across a quote on the internet that would snap me out of my spiral of perpetual
procrastination.&lt;/p&gt;
&lt;blockquote class=&#34;pull-quote&#34;&gt;
&lt;div&gt;&lt;p&gt;The technology you use &lt;strong&gt;impresses no one&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The experience you create with it is &lt;strong&gt;everything&lt;/strong&gt;. – &lt;a class=&#34;reference external&#34; href=&#34;https://twitter.com/ideakitchn?lang=en&#34;&gt;Sean Gerety&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;I have found myself saying this again and again, so much so that I think it may
have fundamentally altered the way I think about programming. I fell into a
trap of getting caught up in the merits of the technology for the sake of the
technology itself and lost sight of the experience - the blog itself.&lt;/p&gt;
&lt;p&gt;Rejuvenated I’ve gone back to where it all started and have started using &lt;a class=&#34;reference external&#34; href=&#34;https://jekyllrb.com&#34;&gt;Jekyll&lt;/a&gt;
again. I’m using the &lt;a class=&#34;reference external&#34; href=&#34;https://fongandrew.github.io/hydeout/&#34;&gt;Hydeout&lt;/a&gt; theme as it’s built in a way that allows me to make
a few (minor!) tweaks of my own. Within a few hours I was already working on the
draft that became this blog post, a place I never even got to in most of my
previous attempts.&lt;/p&gt;
&lt;p&gt;It turns out that Markdown is a perfectly acceptable format for a blog. You
don’t have to engineer your blog’s theme from the ground up especially when a
prebuilt theme exists in the style you were going to build yourself anyway. It
doesn’t matter that your blog can seamlessly format a Jupyter Notebook as a
regular blog post when you don’t have any notebooks to publish in the first
place…&lt;/p&gt;
&lt;p&gt;What matters is the content itself, that you have something interesting to say
and you have some way of making that available to other people. Everything else
is just an implementation detail, which if done right is invisible to the
consumers of your content anyway.&lt;/p&gt;
&lt;p&gt;It’s strange that I had learn something that is probably obvious to most people
the hard way but I’m here now. If you are reading this then things are looking
up but I can’t quite declare victory as I’m no further forward than I was 4
years ago, first let’s see if I make it to blog post number #2…&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

    </content>
  </entry>
  
</feed>