sqrtminusone.github.io/index.xml
2024-03-25 18:42:47 +00:00

5769 lines
1.1 MiB
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Index on SqrtMinusOne</title>
<link>https://sqrtminusone.xyz/</link>
<description>Recent content in Index on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Fri, 08 Mar 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>eshell-atuin</title>
<link>https://sqrtminusone.xyz/packages/eshell-atuin/</link>
<pubDate>Fri, 08 Mar 2024 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/eshell-atuin/</guid>
<content type="html">
&lt;p&gt;Integrate &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_mono/eshell.html&#34;&gt;eshell&lt;/a&gt; with &lt;a href=&#34;https://github.com/atuinsh/atuin&#34;&gt;atuin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;atuin&lt;/code&gt; stores shell history in a database, which allows for having the same history across multiple shells, sessions, and optionally across different machines. See the project page for the complete list of features.&lt;/p&gt;
&lt;p&gt;This package provides functionality to store and browse eshell history in &lt;code&gt;atuin&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package isn&amp;rsquo;t yet available anywhere but in this repository. My preferred way for such cases is &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/radian-software/straight.el&#34;&gt;straight.el&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne/eshell-atuin&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, clone the repository, add it to the &lt;code&gt;load-path&lt;/code&gt;, and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;p&gt;If your version of &lt;code&gt;atuin&lt;/code&gt; is less than 18, turn off saving command durations:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-save-duration&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;
&lt;p&gt;If your &lt;code&gt;atuin&lt;/code&gt; binary is located in a place unknown to &lt;code&gt;executable-find&lt;/code&gt;, set the &lt;code&gt;atuin-executable&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;If you are using a vertical completion system such as &lt;a href=&#34;https://github.com/abo-abo/swiper&#34;&gt;Ivy&lt;/a&gt;, &lt;a href=&#34;https://github.com/radian-software/selectrum&#34;&gt;Selectrum&lt;/a&gt;, etc., you can configure the completion interface, e.g.:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-search-fields&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;time&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;duration&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-history-format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%-160c %t + %d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The available flags are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;atuin field (see &lt;code&gt;help atuin search&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;%t&lt;/td&gt;
&lt;td&gt;&lt;code&gt;time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%c&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%e&lt;/td&gt;
&lt;td&gt;&lt;code&gt;exit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%d&lt;/td&gt;
&lt;td&gt;&lt;code&gt;duration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%i&lt;/td&gt;
&lt;td&gt;&lt;code&gt;directory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%u&lt;/td&gt;
&lt;td&gt;&lt;code&gt;user&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%h&lt;/td&gt;
&lt;td&gt;&lt;code&gt;host&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%r&lt;/td&gt;
&lt;td&gt;&lt;code&gt;relativetime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;See &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Custom-Format-Strings.html&#34;&gt;(emacs) Custom Format Strings&lt;/a&gt; for information on the general &lt;code&gt;format-spec&lt;/code&gt; syntax.&lt;/p&gt;
&lt;p&gt;I suspect the package might be slow if your history has a lot of records (I haven&amp;rsquo;t checked yet). In this case, it might be worth setting a limit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-search-options&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--exit&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--limit&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;10000&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Enable &lt;code&gt;eshell-atuin-mode&lt;/code&gt; to turn on storing eshell commands in &lt;code&gt;atuin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;eshell-atuin-history&lt;/code&gt; inside an &lt;code&gt;eshell&lt;/code&gt; buffer to browse the saved history. Accepting the completion will insert the command.&lt;/p&gt;
&lt;h2 id=&#34;implementation-notes&#34;&gt;Implementation notes&lt;/h2&gt;
&lt;p&gt;I may have overengineered the package a bit to scale on lots of records.&lt;/p&gt;
&lt;p&gt;The package caches the results of &lt;code&gt;atuin search&lt;/code&gt; in &lt;code&gt;eshell-atuin--history-cache&lt;/code&gt; (which see on the algorithm), and updates the cache incrementally. A formatted string for each entry is created at the moment of addition; entries are additionally &amp;ldquo;indexed&amp;rdquo; by a hashmap to lookup &amp;ldquo;raw&amp;rdquo; commands by their formatted versions.&lt;/p&gt;
&lt;p&gt;So, the only places I see with the computational complexity of O(N), where N is the number of unique commands in &lt;code&gt;atuin&lt;/code&gt;, are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;populating the cache at the first run of &lt;code&gt;M-x eshell-atuin-history&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;feeding the entirety of the cache to &lt;code&gt;completing-read&lt;/code&gt; on each run of &lt;code&gt;M-x eshell-atuin-history&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content>
</item>
<item>
<title>org-clock-agg</title>
<link>https://sqrtminusone.xyz/packages/org-clock-agg/</link>
<pubDate>Sun, 17 Dec 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/org-clock-agg/</guid>
<content type="html">
&lt;p&gt;Aggregate &lt;a href=&#34;https://orgmode.org/manual/Clocking-Work-Time.html&#34;&gt;org-clock&lt;/a&gt; records and display the results in an interactive buffer. The records are grouped by predicates such as file name, their outline path in the file, etc. Each record is placed in a tree structure; each node of the tree shows the total time spent in that node and its children. The top-level node shows the total time spent in all records found by the query.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/org-clock-agg-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package isn&amp;rsquo;t yet available anywhere but in this repository. My preferred way for such cases is &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/radian-software/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne/org-clock-agg&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, clone the repository, add it to the &lt;code&gt;load-path&lt;/code&gt;, and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;M-x org-clock-agg&lt;/code&gt; to open the interactive buffer (as depicted in the screenshot above).&lt;/p&gt;
&lt;p&gt;The interactive buffer provides the following controls:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Files&lt;/strong&gt;: Specifies the org files from which to select (defaults to &lt;a href=&#34;https://orgmode.org/manual/Agenda-Files.html&#34;&gt;org-agenda&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Date from&lt;/strong&gt; and &lt;strong&gt;To&lt;/strong&gt;: Define the date range.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Group by&lt;/strong&gt;: Determines how &lt;code&gt;org-clock&lt;/code&gt; records are grouped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Show elements&lt;/strong&gt;: Whether to display raw &lt;code&gt;org-clock&lt;/code&gt; records in each node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add &amp;ldquo;Ungrouped&amp;rdquo;&lt;/strong&gt;: Option to include the &amp;ldquo;Ungrouped&amp;rdquo; node. This is particularly useful with &lt;a href=&#34;#custom-grouping-predicates&#34;&gt;custom grouping predicates&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Press &lt;code&gt;[Refresh]&lt;/code&gt; to update the buffer. The initial search might take some time, but subsequent searches are generally faster due to the caching mechanism employed by &lt;a href=&#34;https://github.com/alphapapa/org-ql&#34;&gt;org-ql&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The buffer uses &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Outline-Mode.html&#34;&gt;outline-mode&lt;/a&gt; to display the tree, so each node becomes an &lt;code&gt;outline-mode&lt;/code&gt; header. Refer to the linked manual for available commands/keybindings, or, if you use &lt;code&gt;evil-mode&lt;/code&gt;, check &lt;a href=&#34;https://github.com/emacs-evil/evil-collection/blob/master/modes/outline/evil-collection-outline.el&#34;&gt;the relevant evil-collection file&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;files&#34;&gt;Files&lt;/h3&gt;
&lt;p&gt;By default, the package selects &lt;code&gt;org-clock&lt;/code&gt; records from &lt;code&gt;(org-agenda-files)&lt;/code&gt;. Additional options can be included by customizing the &lt;code&gt;org-clock-agg-files-preset&lt;/code&gt; variable. For instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-files-preset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Org Agenda + Archive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-agenda-files&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-remove-if&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;directory-files&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/archive/&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that after updating any of these variables, you&amp;rsquo;ll need to reopen the &lt;code&gt;*org-clock-agg*&lt;/code&gt; buffer to view the changes.&lt;/p&gt;
&lt;p&gt;Alternatively, you can directly specify the list of files within the buffer by selecting &amp;ldquo;Custom list&amp;rdquo; in the &amp;ldquo;Files&amp;rdquo; control.&lt;/p&gt;
&lt;h3 id=&#34;date-range&#34;&gt;Date Range&lt;/h3&gt;
&lt;p&gt;Dates can take the following values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A number: Represents a relative number of days from the current date. E.g. the default value of &lt;code&gt;-7&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt; menas the previous week up to today.&lt;/li&gt;
&lt;li&gt;A date string in the format &lt;code&gt;YYYY-MM-DD HH:mm:ss&lt;/code&gt;, with or without the time part.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By default, the interval is inclusive. For instance, specifying an interval like 2023-12-12 .. 2023-12-13 includes all records from 2023-12-12 00:00:00 to 2023-12-13 23:59:59.&lt;/p&gt;
&lt;h3 id=&#34;group-by&#34;&gt;Group By&lt;/h3&gt;
&lt;p&gt;Records are grouped based on the sequence of grouping predicates.&lt;/p&gt;
&lt;p&gt;For example, with the following content in &lt;code&gt;tasks.org&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Tasks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** DONE Thing 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:LOGBOOK:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CLOCK: [2023-12-13 Wed 19:01]--[2023-12-13 Wed 19:29] =&amp;gt; 0:28
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CLOCK: [2023-12-13 Wed 19:30]--[2023-12-13 Wed 19:40] =&amp;gt; 0:10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:END:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And predicates &amp;ldquo;Org file&amp;rdquo;, &amp;ldquo;Day&amp;rdquo;, and &amp;ldquo;Outline path&amp;rdquo;, the records for &amp;ldquo;Thing 1&amp;rdquo; will be processed as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Day&amp;rdquo; -&amp;gt; &lt;code&gt;2023-12-13&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Org file&amp;rdquo; -&amp;gt; &lt;code&gt;tasks.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Outline path&amp;rdquo; -&amp;gt; &lt;code&gt;Tasks&lt;/code&gt;, &lt;code&gt;Thing 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consequently, the node will be placed at the path &lt;code&gt;2023-12-13&lt;/code&gt; / &lt;code&gt;tasks.org&lt;/code&gt; / &lt;code&gt;Tasks&lt;/code&gt; / &lt;code&gt;Thing 1&lt;/code&gt; in the resulting tree:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Results Root 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** 2023-12-13 Day 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** tasks.org Org File 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;**** Tasks Outline path 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;***** Thing 1 Outline path 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- [2023-12-13 Wed 19:01]--[2023-12-13 Wed 19:29] =&amp;gt; 0:28 : DONE Thing 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- [2023-12-13 Wed 19:30]--[2023-12-13 Wed 19:40] =&amp;gt; 0:10 : DONE Thing 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following built-in predicates are currently available:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Comment&lt;/th&gt;
&lt;th&gt;Customization variables&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Category&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Org file&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outline path&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tags&lt;/td&gt;
&lt;td&gt;Sorted alphabetically&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headline&lt;/td&gt;
&lt;td&gt;Last item of the outline path&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org-clock-agg-day-format&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org-clock-agg-week-format&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org-clock-agg-month-format&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TODO keyword&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is done&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selected props&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org-clock-agg-properties&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Ensure to use &lt;code&gt;setopt&lt;/code&gt; to set the variables; otherwise, the customization logic will not be invoked:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;setopt&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-properties&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;PROJECT_NAME&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Refer also to &lt;a href=&#34;#custom-grouping-predicates-1&#34;&gt;custom grouping predicates&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;h3 id=&#34;node-formatting&#34;&gt;Node Formatting&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;org-clock-agg-node-format&lt;/code&gt; variable determines the formatting of individual tree nodes. This uses a &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Custom-Format-Strings.html&#34;&gt;format string&lt;/a&gt; that with the following format specifiers avaiable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%t&lt;/code&gt;: Node title with the level prefix, truncated to &lt;code&gt;title-width&lt;/code&gt; characters (refer to below)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%c&lt;/code&gt;: Name of the grouping function that generated the node&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%z&lt;/code&gt;: Time spent in the node, formatted according to &lt;code&gt;org-clock-agg-duration-format&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%s&lt;/code&gt;: Time share of the node against the parent node&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%S&lt;/code&gt;: Time share of the node against the top-level node&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The default value is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;%-%(+ title-width)t %20c %8z
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where &lt;code&gt;%(+ title-width)&lt;/code&gt; is &lt;code&gt;(- (window-width) org-clock-agg-node-title-width-delta)&lt;/code&gt;, with the default value of the latter set to &lt;code&gt;40&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thefore, in the default configuration, the node title is truncated to &lt;code&gt;title-width&lt;/code&gt; characters, while 40 symbols are allocated for the rest of the header, i.e. &amp;quot; %20c %8z&amp;quot; (30 symbols), along with additional space for folding symbols of &lt;code&gt;outline-minor-mode&lt;/code&gt;, line numbers, etc.&lt;/p&gt;
&lt;h3 id=&#34;record-formatting&#34;&gt;Record Formatting&lt;/h3&gt;
&lt;p&gt;When the &amp;ldquo;Show records&amp;rdquo; flag is enabled, associated records for each node are displayed. The formatting of these is defined by &lt;code&gt;org-clock-agg-elem-format&lt;/code&gt;, which is also a format string with the following specifiers:
Customize the formatting of these records through &lt;code&gt;org-clock-agg-elem-format&lt;/code&gt;, which also utilizes a format string comprising the following specifiers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%s&lt;/code&gt;: Start of the time range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%e&lt;/code&gt;: End of the time range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%d&lt;/code&gt;: Duration of the time range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%t&lt;/code&gt;: Title of the record.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The default value is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- [%s]--[%e] =&amp;gt; %d : %t
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;custom-grouping-predicates-2&#34;&gt;Custom grouping predicates&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s possible to define custom grouping predicates in addition to the default ones. In fact, it&amp;rsquo;s probably the only way to get grouping that is tailored to your particular org workflow; I haven&amp;rsquo;t included my predicates in the package because they aren&amp;rsquo;t general enough.&lt;/p&gt;
&lt;p&gt;To create new predicates, use &lt;code&gt;org-clock-agg-defgroupby&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-defgroupby&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:key1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:key2&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The available keyword arguments include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:readable-name&lt;/code&gt;: Function name for the UI.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:default-sort&lt;/code&gt;: Default sorting function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The body binds two variables - &lt;code&gt;elem&lt;/code&gt; and &lt;code&gt;extra-params&lt;/code&gt;, and must return a list of strings.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;elem&lt;/code&gt; variable is an alist that represents one org-clock record. The keys are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:start&lt;/code&gt;: Start time in seconds since the epoch&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:end&lt;/code&gt;: End time in seconds since the epoch&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:duration&lt;/code&gt;: Duration in seconds&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:headline&lt;/code&gt;: Instance of &lt;a href=&#34;https://orgmode.org/worg/dev/org-element-api.html&#34;&gt;org-element&lt;/a&gt; for the headline&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:tags&lt;/code&gt;: List of tags&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:file&lt;/code&gt;: File name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:outline-path&lt;/code&gt;: titles of all headlines from the root to the current headline&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:properties&lt;/code&gt;: List of properties; &lt;code&gt;org-clock-agg-properties&lt;/code&gt; sets the selection list&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:category&lt;/code&gt;: &lt;a href=&#34;https://orgmode.org/manual/Categories.html&#34;&gt;Category&lt;/a&gt; of the current headline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;extra-params&lt;/code&gt; variable is an alist of global parameters controlling the function&amp;rsquo;s behavior. Additional parameters can be added by customizing &lt;code&gt;org-clock-agg-extra-params&lt;/code&gt;. This alist has keys as parameter names and values as &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_mono/widget.html&#34;&gt;widget.el&lt;/a&gt; expressions (applied to &lt;code&gt;widget-create&lt;/code&gt;) controlling the UI. Each widget must contain an &lt;code&gt;:extras-key&lt;/code&gt; key.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-extra-params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Events: Offline / Online&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;checkbox&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:extras-key&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:events-online&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This adds a checkbox to the form that appears as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Events: Offline / Online [ ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When checked, &lt;code&gt;extra-params&lt;/code&gt; takes the value &lt;code&gt;((:extras-keys . t))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example predicate. I store meetings the following way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Some project
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Meetings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Some meeting 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Some meeting 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Another project
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Meetings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Another meeting 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Another meeting 2 (offline)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I want to group these meetings by title, i.e. group all instances of &amp;ldquo;Some meeting&amp;rdquo;, &amp;ldquo;Another meeting&amp;rdquo;, etc. Optionally I want to group online and offline meetings.&lt;/p&gt;
&lt;p&gt;This can be done the following way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-defgroupby&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;event&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:readable-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Event&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:default-sort&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:raw-value&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:headline&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;is-meeting&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;meeting&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;downcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-contains-p&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:tags&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mt&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;is-offline&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;offline&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;downcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-contains-p&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:tags&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;offline&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;title-without-stuff&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-trim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;digit&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(offline)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;alnum&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;) ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;is-meeting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Meeting&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:events-online&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extra-params&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;is-offline&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Offline&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Online&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;title-without-stuff&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the following result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Results
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Meetings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Some meeting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Another meeting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Ungrouped
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be coupled with a project predicate to analyze the time spent per project in a particular kind of meeting.&lt;/p&gt;
</content>
</item>
<item>
<title>Declarative filesystem management with Emacs &amp; Org Mode</title>
<link>https://sqrtminusone.xyz/posts/2023-11-11-index/</link>
<pubDate>Sat, 11 Nov 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2023-11-11-index/</guid>
<content type="html">
&lt;div class=&#34;abstract&#34;&gt;
&lt;p&gt;The post describes a Johnny.Decimal-inspired filesystem structure, declared in an org file and synchronized across machines. Different folders are available on different machines.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;
&lt;p&gt;My filesystem is, shall we say, not the most orderly place.&lt;/p&gt;
&lt;center&gt;
&lt;iframe src=&#34;https://emacs.ch/@sqrtminusone/110514686718545191/embed&#34; class=&#34;mastodon-embed&#34; style=&#34;max-width: 100%; border: 0&#34; width=&#34;500&#34; allowfullscreen=&#34;allowfullscreen&#34;&gt;&lt;/iframe&gt;&lt;script src=&#34;https://emacs.ch/embed.js&#34; async=&#34;async&#34;&gt;&lt;/script&gt;
&lt;/center&gt;
&lt;p&gt;It&amp;rsquo;s been somewhat messy, and messy in different ways across my three machines. For instance, my laptop had work projects in &lt;code&gt;~/Code/Job&lt;/code&gt;, my work machine had just &lt;code&gt;~/Code&lt;/code&gt;, and so forth.&lt;/p&gt;
&lt;p&gt;Strangely, I couldn&amp;rsquo;t find and existing solution to that problem. Surely, I can&amp;rsquo;t be the only one facing that issue, can I?&lt;/p&gt;
&lt;p&gt;Fortunately, I&amp;rsquo;m well-acquainted (make-yourself-a) Swiss Army Knife of computing called &lt;a href=&#34;https://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt;, so&amp;hellip; below is my attempt to make something of it. And another addition to the already substantial list of my Emacs uses.&lt;/p&gt;
&lt;p&gt;Also, my &lt;code&gt;M-x magit-log-buffer-file&lt;/code&gt; shows I created that file on the same day I had written the embedded toot, so this must be the longest Emacs thing I&amp;rsquo;ve been figuring out. And it&amp;rsquo;s probably the least portable, but I nevertheless hope you find it useful.&lt;/p&gt;
&lt;h2 id=&#34;idea&#34;&gt;Idea&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/images/index/index.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;So, I decided to try declarative filesystem management.&lt;/p&gt;
&lt;p&gt;At the core is my work-in-progress adaptation of &lt;a href=&#34;https://johnnydecimal.com/&#34;&gt;Johnny.Decimal&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. Essentially, it suggests prefixing your folders with numbers like &lt;code&gt;12.34&lt;/code&gt;, where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the first digit is the &amp;ldquo;&lt;a href=&#34;https://johnnydecimal.com/10-19-concepts/11-core/11.02-areas-and-categories/&#34;&gt;category&lt;/a&gt;&amp;rdquo;;&lt;/li&gt;
&lt;li&gt;the second digit is the &amp;ldquo;&lt;a href=&#34;https://johnnydecimal.com/10-19-concepts/11-core/11.02-areas-and-categories/&#34;&gt;area&lt;/a&gt;&amp;rdquo;;&lt;/li&gt;
&lt;li&gt;the last two digits are the &lt;a href=&#34;https://johnnydecimal.com/10-19-concepts/11-core/11.03-ids/&#34;&gt;ID&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The point is to organize your folder structure, limiting its depth for quicker and more straightforward access. Check the website for a more thorough description.&lt;/p&gt;
&lt;p&gt;So, what I want is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;define a Jonny.Decimal-esque file tree in a single &lt;a href=&#34;https://orgmode.org/&#34;&gt;Org&lt;/a&gt; file;&lt;/li&gt;
&lt;li&gt;have different nodes of that file tree active on different machines, e.g. I don&amp;rsquo;t want &lt;a href=&#34;https://github.com/SqrtMinusOne?tab=repositories&amp;amp;q=&amp;amp;type=&amp;amp;language=emacs+lisp&amp;amp;sort=&#34;&gt;my Emacs stuff&lt;/a&gt; on my work machine;&lt;/li&gt;
&lt;li&gt;use different tools to sync different nodes (currently &lt;a href=&#34;https://git-scm.com/&#34;&gt;git&lt;/a&gt;, &lt;a href=&#34;https://mega.nz/&#34;&gt;MEGA&lt;/a&gt;, and &amp;ldquo;nothing&amp;rdquo;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;folder-structure&#34;&gt;Folder structure&lt;/h3&gt;
&lt;p&gt;As I said, I tried (and still trying) to adapt the proposed scheme to better suit my needs. Here&amp;rsquo;s a subset of my current tree:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10-19 Code
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10 [REDACTED]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.02 Digital Schedule ; project root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03 Digital Trajectories ; project root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 12 My Emacs Packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 12.01 lyrics-fetcher.el ; managed by git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 12.02 pomm.el ; managed by git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 15 Other Projects
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 15.04 ZMU_2022 ; I&amp;#39;m done with this and don&amp;#39;t need it on any machine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;20-29 Education
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 24 Publications ; the entrire area is managed by MEGA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 24.Y20.01 [bibtex code]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 24.Y20.02 [bibtex code]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 26 Students
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 26.Y22.01 [student name]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;30-39 Life
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 32 org-mode
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 33 Library
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The root of the tree is my &lt;code&gt;$HOME&lt;/code&gt;. The entry at the third (or second) level can be either an entity itself (such as a git repository), or a &amp;ldquo;project root&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;In several places, I use year references (&lt;code&gt;Y20&lt;/code&gt;) instead of the plain &lt;code&gt;AC.ID&lt;/code&gt;. This is mainly to group things by academic years, e.g. to find all my publications or students in a specific year, which I need for occasional reports. I also have semester references (&lt;code&gt;SEM10&lt;/code&gt;) for my undergraduate studies.&lt;/p&gt;
&lt;p&gt;The project structure is more or less standard. Johnny.Decimal &lt;a href=&#34;https://johnnydecimal.com/10-19-concepts/13-multiple-projects/13.01-introduction/&#34;&gt;proposes&lt;/a&gt; using &lt;code&gt;PRO.AC.ID&lt;/code&gt; to manage multiple projects, but this doesn&amp;rsquo;t seem to fit quite as well in my case. So I came up with the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10.03 Digital Trajectories ; project root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03.A Artifacts ; managed by MEGA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03.A.04 library queries (Jan 23)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03.D Documents ; managed by MEGA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03.D.01 Initial design
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03.R Repos
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03.R.00 digital-trajectories-deploy ; managed by MEGA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03.R.01 digital-trajectories-backend ; managed by git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 10.03.U Dumps ; managed by nothing, no need to sync this
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also use year references on the third level for courses I happen to teach across multiple academic years.&lt;/p&gt;
&lt;p&gt;Perhaps this is too verbose (&lt;code&gt;10.03.R.01&lt;/code&gt;), but it works for now.&lt;/p&gt;
&lt;h3 id=&#34;tools-choice&#34;&gt;Tools choice&lt;/h3&gt;
&lt;p&gt;As I mentioned earlier, my current options to manage a particular node are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/&#34;&gt;git&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mega.nz/&#34;&gt;MEGA&lt;/a&gt; - for files that don&amp;rsquo;t fit into git, such as DOCX documents, photos, etc.;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;nothing&amp;rdquo; - for something that I don&amp;rsquo;t need to sync across machines, e.g. database dumps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another tool I considered was &lt;a href=&#34;https://github.com/restic/restic&#34;&gt;restic&lt;/a&gt;. It&amp;rsquo;s an interesting backup &amp;amp; sync solution with built-in encryption, snapshots, etc.&lt;/p&gt;
&lt;p&gt;However, a challenge I encountered is that its repositories are only accessible via restic. So, even if I use something like MEGA as a backend, I won&amp;rsquo;t be able to use the MEGA file-sharing features, which I occasionally want for document or photo folders. Hence, for now, I&amp;rsquo;m more interested in synchronizing the file tree in MEGA with &lt;a href=&#34;https://github.com/meganz/MEGAcmd&#34;&gt;MEGAcmd&lt;/a&gt; (and also clean up the mess up there).&lt;/p&gt;
&lt;p&gt;Another interesting tool is &lt;a href=&#34;https://rclone.org/&#34;&gt;rclone&lt;/a&gt;, which provides a single interface for multiple services like Google Drive, Dropbox, S3, WebDAV. It also supports MEGA, but it requires turning off the two-factor authentication, which I don&amp;rsquo;t want.&lt;/p&gt;
&lt;h2 id=&#34;implementation&#34;&gt;Implementation&lt;/h2&gt;
&lt;h3 id=&#34;dependencies&#34;&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ll need lexical binding.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;;; -*- lexical-binding: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a package called &lt;a href=&#34;https://github.com/daniel-ness/ini.el&#34;&gt;ini.el&lt;/a&gt; to parse INI files.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;ini&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;daniel-ness/ini.el&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The rest is built into Emacs.&lt;/p&gt;
&lt;h3 id=&#34;org-tree&#34;&gt;Org tree&lt;/h3&gt;
&lt;h4 id=&#34;tree-definitions&#34;&gt;Tree definitions&lt;/h4&gt;
&lt;p&gt;The root is my &lt;code&gt;$HOME&lt;/code&gt; directory.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-root&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;getenv&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;HOME&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The org tree is located in my &lt;code&gt;org-mode&lt;/code&gt; folder in a file called &lt;code&gt;index.org&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/misc/index.org&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each &amp;ldquo;area&amp;rdquo; is an Org header with the &lt;code&gt;folder&lt;/code&gt; tag; the Org hierarchy forms the file tree. A header can have the following properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;machine&lt;/code&gt; - a list of hostnames for which the node is active (or &lt;code&gt;nil&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kind&lt;/code&gt; - &lt;code&gt;mega&lt;/code&gt;, &lt;code&gt;git&lt;/code&gt;, or &lt;code&gt;dummy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remote&lt;/code&gt; - remote URL for &lt;code&gt;git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;symlink&lt;/code&gt; - in case the folder has to be symlinked somewhere else&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;E.g. a part of the tree above:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-org&#34; data-lang=&#34;org&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000080;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt; 10-19 Code &lt;/span&gt;&lt;span style=&#34;font-style:italic&#34;&gt; :folder:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#800080;font-weight:bold&#34;&gt;**&lt;/span&gt; 10 [REDACTED]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#800080;font-weight:bold&#34;&gt;***&lt;/span&gt; 10.03 Digital Trajectories
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:PROPERTIES:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:machine: indigo eminence
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:project: t
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:END:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#800080;font-weight:bold&#34;&gt;****&lt;/span&gt; 10.03.A Artifacts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:PROPERTIES:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:kind: mega
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:END:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#800080;font-weight:bold&#34;&gt;****&lt;/span&gt; 10.03.D Documents
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:PROPERTIES:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:kind: mega
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:END:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#800080;font-weight:bold&#34;&gt;****&lt;/span&gt; 10.03.R Repos
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#800080;font-weight:bold&#34;&gt;*****&lt;/span&gt; 10.03.R.00 digital-trajectories-deploy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:PROPERTIES:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:kind: mega
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:END:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#800080;font-weight:bold&#34;&gt;*****&lt;/span&gt; 10.03.R.01 digital-trajectories-backend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:PROPERTIES:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:kind: git
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:remote: [REACTED]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:END:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#800080;font-weight:bold&#34;&gt;****&lt;/span&gt; 10.03.U Dumps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:PROPERTIES:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:kind: dummy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;:END:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;parse-tree&#34;&gt;Parse tree&lt;/h4&gt;
&lt;p&gt;So, let&amp;rsquo;s parse the Org tree. This is done by recursively traversing the tree returned by &lt;code&gt;org-element-parse-buffer&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get-recursive&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Read the index tree recursively from HEADING.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;HEADING is an org-element of type &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`headline&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;If PATH is provided, it is the path to the current node. If not
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;provided, it is assumed to be the root of the index.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is an alist; see &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; for details.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-type&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;headline&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;new-path&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-root&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:raw-value&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;children&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-contents&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get-recursive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;new-path&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;identity&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;children&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;machine&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:MACHINE&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:machine&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;machine&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:SYMLINK&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:symlink&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:PROJECT&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:project&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;) &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;kind-str&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:KIND&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;intern&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind-str&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:kind&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;equal&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;git&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;remote&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:REMOTE&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;remote&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;No remote for %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:remote&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;remote&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:raw-value&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;heading&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;new-path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Read the index tree from the current org buffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a list of alists, each representing a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;folder/node. Alists can have the following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:name&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:path&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:children&amp;#39; - child nodes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:machine&amp;#39; - list of machines on which the node is active
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:symlink&amp;#39; - a symlink to create
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:kind&amp;#39; - one of \&amp;#34;git\&amp;#34;, \&amp;#34;mega\&amp;#34;, or \&amp;#34;dummy\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:remote&amp;#39; - the remote to use for git nodes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-map&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-parse-buffer&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;headline&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;identity&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:level&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-contains-p&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;substring-no-properties&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:tags&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;folder&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get-recursive&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;verify-tree&#34;&gt;Verify tree&lt;/h4&gt;
&lt;p&gt;I also want to make sure that I didn&amp;rsquo;t mess up the numbers, i.e., didn&amp;rsquo;t place &lt;code&gt;10.02&lt;/code&gt; under &lt;code&gt;11&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;p&gt;To do that, we first need to extract the number from the name:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--extact-number&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Extract the number from the index NAME.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;NAME is a string. The number is the first sequence of digits, e.g.:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- 10-19
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- 10.01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- 10.01.Y22.01&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;save-match-data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-match&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;bos&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;num&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;alpha&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;))) &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;match-string&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, we can recursively verify the numbers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/tree--verfify-recursive&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Verify that ELEM is a valid tree element.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;CURRENT is the current number or name of the parent element.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;number&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--extact-number&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Can&amp;#39;t find number: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;listp&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-some&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cand&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;string-prefix-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;cand&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;current&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Name: %s doesn&amp;#39;t match: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#00f&#34;&gt;stringp&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-prefix-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Name: %s doesn&amp;#39;t match: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;recur-value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;num&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;num&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;number&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;borders&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;number&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-to-number&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;borders&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;end&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-to-number&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;borders&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;to&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;1-&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;end&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;number-to-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;number&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/tree--verfify-recursive&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;recur-value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-verify&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Verify that TREE is a valid tree.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;Return t if it is valid, otherwise raise an error.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;See &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; for the format of TREE.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/tree--verfify-recursive&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;narrow-tree&#34;&gt;Narrow tree&lt;/h4&gt;
&lt;p&gt;Finally, we need to narrow the tree to only leave nodes that are active for the current machine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-narrow-recursive&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;machine&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Remove all children of ELEM that are not active on MACHINE.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;elem-machines&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:machine&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-some&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elem-machine&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem-machine&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;machine&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem-machines&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;identity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-narrow-recursive&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;machine&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-narrow&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Remove all elements of TREE that are not active on machine.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;identity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-narrow-recursive&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;system-name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;copy-tree&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;commands&#34;&gt;Commands&lt;/h3&gt;
&lt;p&gt;Next, apply the tree to the filesystem.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve decided to implement this by generating a bash script and executing it with &lt;code&gt;bash +x&lt;/code&gt;. This way, I can check the required changes in advance and avert potential data loss if something unexpected happens.&lt;/p&gt;
&lt;p&gt;One command for the script will be a list like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(&amp;lt;command&amp;gt; &amp;lt;category&amp;gt; &amp;lt;priority&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;filesystem&#34;&gt;Filesystem&lt;/h4&gt;
&lt;p&gt;First, we need to create non-existing folders and remove folders that aren&amp;rsquo;t supposed to exist.&lt;/p&gt;
&lt;p&gt;To do that, we need to find all such folders:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--filesystem-tree-mapping&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;active-paths&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Return a \&amp;#34;sync state\&amp;#34; between the filesystem and the tree.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;FULL-TREE and TREE are forms as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;. TREE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;is the narrowed FULL-TREE (returned by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-narrow&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;ACTIVE-PATHS is a list of paths that are currently active. If not
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;provided, it is computed from TREE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a list of alists with the following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- path - the path of the folder
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- exists - whether the folder exists on the filesystem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- has-to-exist - whether the folder exists in the tree
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- extra - if the folder exists in the filesystem but not in the tree.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- children - a list of alists with the same keys for the children of
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; the folder.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;active-paths&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;active-paths&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get-paths&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extra-folders&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-directory-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-difference&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;d&lt;/span&gt;) (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-directory-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;d&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;d&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;directory-files&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;folder-exists&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-directory-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;folder-has-to-exist&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-contains-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;active-paths&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exists&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;folder-exists&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;has-to-exist&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;folder-has-to-exist&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;children&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extra-folders&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exists&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;has-to-exist&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;extra&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--filesystem-tree-mapping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;active-paths&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And generate commands from the results of the above:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--filesystem-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mapping&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get commands to sync filesystem with the tree.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;MAPPING is a form generated by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--filesystem-tree-mapping&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;that describes the \&amp;#34;sync state\&amp;#34; between the filesystem and the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;tree.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a list of commands as defined by
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--commands-display&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mapping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exists&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exists&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;has-to-exist&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;has-to-exist&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extra&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;extra&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exists&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;has-to-exist&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mkdir \&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Make directories&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exists&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;has-to-exist&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rm -rf \&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extra&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Remove extra files&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Remove directories&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extra&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;20&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--filesystem-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;mega&#34;&gt;MEGA&lt;/h4&gt;
&lt;p&gt;As I said above, MEGA provides &lt;a href=&#34;https://github.com/meganz/MEGAcmd&#34;&gt;MEGAcmd&lt;/a&gt;, which is a convenient way to access MEGA via CLI.&lt;/p&gt;
&lt;p&gt;To initialize the session, run&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mega-login &amp;lt;login&amp;gt; &amp;lt;password&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then you&amp;rsquo;ll be able to run the rest of &lt;code&gt;mega-*&lt;/code&gt; commands.&lt;/p&gt;
&lt;p&gt;The command I want to run, &lt;code&gt;mega-sync&lt;/code&gt;, prints the results in a table-like way. So let&amp;rsquo;s parse that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/parse-table-str&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Convert a table-like STRING into alist.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The input format is as follows:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;HEADER1 HEADER2 HEADER3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;value1 value2 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;value4 value5 6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;Which creates the following output:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;\(((HEADER1. \&amp;#34;value1\&amp;#34;) (HEADER2 . \&amp;#34;value2\&amp;#34;) (HEADER3 . \&amp;#34;3\&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; ((HEADER1. \&amp;#34;value4\&amp;#34;) (HEADER2 . \&amp;#34;value5\&amp;#34;) (HEADER3 . \&amp;#34;6\&amp;#34;)))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The functions also skips lines in [square brackets] and ones that
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;start with more than 3 spaces.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;lines&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;s&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;bos&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nonl&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;bos&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;s&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;first-line&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;lines&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;first-line&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;header-indices&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;header&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-search&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;first-line&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;headers&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;lines&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;header-indices&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;header-indices&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;intern&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;header&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-trim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;end&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can invoke &lt;code&gt;mega-sync&lt;/code&gt; to get the current sync status. &lt;code&gt;--path-display-size=10000&lt;/code&gt; disables truncation of long paths.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--mega-data-from-sync&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get the current MEGA sync status.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a list of alists with the following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- path - path to file or directory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- enabled - whether the file or directory is enabled for sync&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;mega-result&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/parse-table-str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;shell-command-to-string&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mega-sync --path-display-size=10000&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;localpath&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;LOCALPATH&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-directory-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;localpath&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;localpath&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;localpath&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;enabled&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;ACTIVE&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Enabled&amp;#34;&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And get the same data from the tree.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get-paths&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get paths from TREE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;TREE is a form a defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;. KIND is either a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;filter by the kind attribute or nil, in which case all paths are
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;returned.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a list of strings.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:kind&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get-paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that information, we can generate commands to synchronize the required and actual sync paths.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--mega-local-path&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get path in the MEGA cloud by the local path PATH.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-replace&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-root&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--mega-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get commands to sync the mega-sync state with TREE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;FULL-TREE and TREE are forms as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;. TREE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;is the narrowed FULL-TREE (returned by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-narrow&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a list of commands as defined by
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--commands-display&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;paths-all&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get-paths&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mega-paths-to-enable&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get-paths&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;mega&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mega-info&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--mega-data-from-sync&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mega-paths-enabled&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;enabled&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-info&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mega-paths-disabled&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;enabled&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-info&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-difference&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-paths-to-enable&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-paths-enabled&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-contains-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-paths-disabled&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mega-sync -e \&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Mega enable sync&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mega-mkdir -p \&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--mega-local-path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Mega mkdirs&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mega-sync \&amp;#34;%s\&amp;#34; \&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--mega-local-path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Mega add sync&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;5&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-difference&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-intersection&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-paths-enabled&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;paths-all&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-paths-to-enable&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mega-sync -d \&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;1-&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Mega remove sync&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;4&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;git-repos&#34;&gt;Git repos&lt;/h4&gt;
&lt;p&gt;To sync git, we just need to clone the required git repos. Removing the repos is handled by the folder sync commands.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--git-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get commands to clone the yet uncloned git repos in TREE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;TREE is a form a defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;. This is supposed to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;be the tree narrowed to the current machine (&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-narrow&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a list of commands as defined by
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--commands-display&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:kind&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;git&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-directory-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;directory-empty-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;git clone \&amp;#34;%s\&amp;#34; \&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:remote&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Init git repos&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--git-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;wakatime&#34;&gt;Wakatime&lt;/h4&gt;
&lt;p&gt;So, that&amp;rsquo;s it for synchronization. A few other things are needed here.&lt;/p&gt;
&lt;p&gt;I use &lt;a href=&#34;https://wakatime.com/&#34;&gt;WakaTime&lt;/a&gt; to track my coding activity, and I don&amp;rsquo;t like the alphanumeric prefixes in my coding stats. Fortunately, &lt;code&gt;wakatime-cli&lt;/code&gt; provides an option called &lt;a href=&#34;https://github.com/wakatime/wakatime-cli/blob/develop/USAGE.md#project-map-section&#34;&gt;projectmap&lt;/a&gt; to rename projects, so we just have to generate its contents.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--bare-project-name&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Remove the alphanumeric prefix from NAME.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;E.g. 10.03.R.01 Project Name -&amp;gt; Project Name.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;bos&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;num&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;alpha&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;space&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-escape&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Escape STRING for use in a WakaTime config file.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\\\&amp;#39;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\\\(&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\\\)&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-get-map-tree&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get a list of (folder-name . bare-project-name) pairs from TREE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;TREE is a form as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;\&amp;#34;bare-project-name\&amp;#34; is project name without the alphanumeric
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;prefix.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:kind&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;git&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-escape&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-escape&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--bare-project-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:kind&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;git&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:symlink&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-escape&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; lmao&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; /a/b/c/ -&amp;gt; c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; /a/b/c -&amp;gt; b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-name-nondirectory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;directory-file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-name-directory&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:symlink&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-escape&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--bare-project-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-get-map-tree&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And insert that in &lt;code&gt;wakatime.cfg&lt;/code&gt; if necessary.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get commands to update WakaTime config from TREE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;TREE is a form a defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;. The return value is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;a list of commands as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--commands-display&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;map-tree&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-get-map-tree&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;map-tree-encoding&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;ini-encode&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;projectmap&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;map-tree&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;map-tree-saved&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-temp-buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert-file-contents&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.wakatime.cfg&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;regexp-quote&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;map-tree-encoding&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-string&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;map-tree-saved&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;insert-command&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;echo \&amp;#34;\n\n%s\&amp;#34; &amp;gt;&amp;gt; ~/.wakatime.cfg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;map-tree-encoding&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Update WakaTime config&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;9&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;sed -i -z &amp;#39;s/\\[projectmap\\]\\n[^[]*//g&amp;#39; ~/.wakatime.cfg&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Update WakaTime config&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;9&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;insert-command&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;symlinks&#34;&gt;Symlinks&lt;/h4&gt;
&lt;p&gt;The last part here is creating symbolic links.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-get-symlink-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get commands to create symlinks from TREE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;TREE is a form a defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;. The return value is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;a list of commands as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--commands-display&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:symlink&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Wrong symlink: %s (should be a directory)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-exists-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-symlink-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rm -rf %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Remove files to make symlinks&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;6&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-symlink-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;ln -s &amp;#39;%s&amp;#39; &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Make symlinks&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;7&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index-get-symlink-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;run-all-commands&#34;&gt;Run all commands&lt;/h4&gt;
&lt;p&gt;And put that all together.&lt;/p&gt;
&lt;p&gt;First, as I want to check what&amp;rsquo;s going to be executed, let&amp;rsquo;s make a function to display commands in a separate buffer. Making it &lt;code&gt;sh-mode&lt;/code&gt; is enough for now.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defvar-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-commands&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Commands to be executed by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index-commands-exec&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--commands-display&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;commands&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Display COMMANDS in a buffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;COMMANDS is a list of commands as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--commands-display&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;commands&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;No commands to display&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;get-buffer-create&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;*index commands*&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;groups&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-sort-by&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;g&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;g&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&amp;lt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-group-by&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;c&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;commands&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;sh-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;inhibit-read-only&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;commands-sequence&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;erase-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-commands&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;g&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;groups&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;group-name&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elems&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;# &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;group-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elems&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;my/index-commands&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buffer-read-only&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;switch-to-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In order to execute these commands, &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Compilation.html&#34;&gt;compile&lt;/a&gt; with &lt;code&gt;bash -x&lt;/code&gt; on a temporary file is quite sufficient.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-commands-exec&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;major-mode&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;sh-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Not shell mode&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;filename&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;make-temp-file&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;index-commands-&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;write-region&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;point-min&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;point-max&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;filename&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;compile&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;bash -x &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;filename&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll also try to save some time by caching the resulting index tree. &lt;code&gt;file-has-changed-p&lt;/code&gt; is pretty helpful in that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;The last version of the index tree.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-retrive&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Retrive the last version of the index tree.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;This function returns the last saved version of the index tree if it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;is still valid. Otherwise, it re-parses the index file.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt; ((&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-file-name&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;my/index-file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file-has-changed-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-file&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;index&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-temp-buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert-file-contents&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#00f&#34;&gt;buffer-file-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-file&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-get&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that, we can make the main entrypoint.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-commands-sync&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Sync the filesystem with the index.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-retrive&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-verify&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-narrow&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mega-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--mega-commands&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mapping&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--filesystem-tree-mapping&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;full-tree&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;folder-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--filesystem-commands&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mapping&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;git-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--git-commands&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;waka-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--wakatime-commands&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;symlink-commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index-get-symlink-commands&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--commands-display&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mega-commands&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;folder-commands&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;git-commands&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;waka-commands&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;symlink-commands&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;navigation&#34;&gt;Navigation&lt;/h3&gt;
&lt;p&gt;The last piece is the navigation interface.&lt;/p&gt;
&lt;p&gt;Of course, plain dired does the job fine, thanks to the relatively low-depth filesystem structure. But I still want a navigation interface like &lt;code&gt;M-x projectile-switch-project&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;navigation-data&#34;&gt;Navigation data&lt;/h4&gt;
&lt;p&gt;There are two slight problems with that.&lt;/p&gt;
&lt;p&gt;First, the index tree does not always have the full info. For instance, I have the &lt;code&gt;10.03.A Artifacts&lt;/code&gt; folder, which I sync with MEGA and which has child folders like &lt;code&gt;10.03.A.01 smth&lt;/code&gt; and so on. Names of the latter are not stored anywhere because I don&amp;rsquo;t see the point, which means we have to extract that from the filesystem.&lt;/p&gt;
&lt;p&gt;Second, as it turns out, there have to be two levels for navigation, which are delimited by the &lt;code&gt;project&lt;/code&gt; property. I&amp;rsquo;m not sure if that the optimal way to implement Jonny.Decimal, but it works for me.&lt;/p&gt;
&lt;p&gt;So, a function to tackle the first problem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-extend&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Find all index-related files in PATH.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;NAME is the name of the root index entry, e.g. \&amp;#34;10.01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;Something\&amp;#34;. If PATH containts folders like \&amp;#34;10.01.01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;Something\&amp;#34;, \&amp;#34;10.01.02 ...\&amp;#34;, they will be returned.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a form as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--nav-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-directory-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;number&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--extact-number&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;files&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-prefix-p&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;directory-files&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;matching-files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;) (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-directory-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-prefix-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;number&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;files&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;length&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;matching-files&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;length&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;matching-files&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;files&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Extraneuous files in %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;name-1&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path-1&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;matching-files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;if-let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;child-files&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-extend&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name-1&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path-1&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;child-datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name-1&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:names&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-datum&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-files&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(((&lt;span style=&#34;color:#008000&#34;&gt;:names&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;name-1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path-1&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And one to get the navigation data structure.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-get&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;names&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get the navigation structure from TREE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;TREE is a form as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--tree-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;. NAMES is a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;list of names of the parent entries, e.g. (\&amp;#34;10.01 Something\&amp;#34;), used
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;for recursive calls.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The result is a list of alists with the following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:names` - list of names, e.g.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; (\&amp;#34;10.01 Something\&amp;#34; \&amp;#34;10.01.01 Something\&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:path` - path to the folder, e.g.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; \&amp;#34;/path/10 stuff/10.01 Something/10.01.01 Something/\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- `:child-navs` - list of child navigation structures (optional)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-sort-by&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;item&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;item&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-lessp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-reduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:project&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;current-nav&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#008000&#34;&gt;:names&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;names&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;child-navs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-get&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:child-navs&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-nav&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;child-navs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-nav&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;child-navs&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;names&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-nav&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-navs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-nav&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;if-let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;extended-nav&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-extend&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-nav&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extended-nav&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:names&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-nav&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;names&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:names&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-nav&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-nav&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#008000&#34;&gt;:names&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;names&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:initial-value&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It also makes sense to cache results of the above.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Navigation stucture for the index.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-retrive&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Retrive the navigation structure from the index file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The return value is a form as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--nav-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file-has-changed-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-file&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;nav&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-retrive&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--tree-narrow&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tree&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;emacs-interface&#34;&gt;Emacs interface&lt;/h4&gt;
&lt;p&gt;As for Emacs interface, &lt;code&gt;completing-read&lt;/code&gt; is sufficient, except that I don&amp;rsquo;t want &lt;a href=&#34;https://github.com/radian-software/prescient.el&#34;&gt;prescient.el&lt;/a&gt; to interfere with the default ordering of elements.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-prompt&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Prompt the user for the navigation item to select.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;NAV is a structure as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--nav-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;collection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;item&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;last&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:names&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;item&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;item&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;ivy-prescient-sort-commands&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;assoc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;completing-read&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Index: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collection&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collection&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-find-path&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Find the navigation item in NAV with the given PATH.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;NAV is a structure as defined by &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/index--nav-get&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-find&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;item&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-prefix-p&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;item&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/index-nav&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;arg&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Navigate the filesystem index.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;ARG is the prefix argument. It modifies the behavior of the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;command as follows:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- If not in an indexed directory, or in an indexed directory with no
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; indexed children:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; - nil: Select an indexed directory.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; - &amp;#39;(4): Select an indexed directory, and select a child indexed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; directory if available.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- If in an indexed directory with indexed children (a project):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; - nil: Select another indexed directory from the project.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; - &amp;#39;(4): Select a top-level indexed directory (the same as nil for
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; the previous case).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; - &amp;#39;(16): The same as &amp;#39;(4) for the previous case.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;FUNC is the function to call with the selected path. It defaults
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;to &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`dired&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; if used interactively.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-prefix-arg&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;dired&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-retrive&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;current-nav&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-find-path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;default-directory&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;current-child-navs&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:child-navs&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-nav&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;arg&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-child-navs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;equal&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;arg&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;4&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;current-child-navs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;func&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-prompt&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;equal&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;arg&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;4&lt;/span&gt;)) (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-child-navs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;equal&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;arg&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;16&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;current-child-navs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;selected&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-find-path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-prompt&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nav&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;if-let&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;child-navs&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:child-navs&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;selected&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-prompt&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child-navs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;selected&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;arg&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;current-child-navs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/index--nav-prompt&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-child-navs&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, something that I can bind to a key.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;my-leader-def&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;i&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/index-nav&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Thanks @maddo at the former &lt;a href=&#34;https://systemcrafters.net/community/&#34;&gt;SystemCrafters&lt;/a&gt; discord for pointing that out.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;To my surprise, I found several places where I can&amp;rsquo;t use (or find how to use) paths with spaces, &lt;a href=&#34;https://guix.gnu.org/manual/en/html_node/Channels.html&#34;&gt;Guix channels&lt;/a&gt; being one. Hence, symlinks.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
</item>
<item>
<title>BIOME - Bountiful Interface to Open Meteo for Emacs</title>
<link>https://sqrtminusone.xyz/packages/biome/</link>
<pubDate>Sat, 22 Jul 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/biome/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/biome&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/biome-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Interface to &lt;a href=&#34;https://open-meteo.com/&#34;&gt;Open Meteo&lt;/a&gt; for Emacs. The service provides weather forecasts, historical weather data, climate change projections, and more.&lt;/p&gt;
&lt;p&gt;The service is AGPL-licensed; the hosted API is free for non-commercial use if you make less than 10000 requests per day.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/report.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, I prefer &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/radian-software/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or clone the repository, add it to &lt;code&gt;load-path&lt;/code&gt;, and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;The main entry point is &lt;code&gt;M-x biome&lt;/code&gt;. Each item under &amp;ldquo;Open Meteo Data&amp;rdquo; corresponds to a particular endpoint of the service. For instance, &lt;code&gt;M-x biome ww&lt;/code&gt; is a generic weather forecast. Check out the &lt;a href=&#34;https://open-meteo.com/en/docs&#34;&gt;API docs&lt;/a&gt; for more detailed descriptions.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/root.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Each of these items opens a query interface. A query consists of &amp;ldquo;global&amp;rdquo; variables, such as location, units, etc., and &amp;ldquo;group variables&amp;rdquo;. Groups are usually &amp;ldquo;hourly&amp;rdquo; and &amp;ldquo;daily&amp;rdquo;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/query.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Global variables must always include a location (section &amp;ldquo;Select Coordinates or City&amp;rdquo;). To enter a location, you can either enter latitude and longitude (Open Meteo has an &lt;a href=&#34;https://open-meteo.com/en/docs/geocoding-api&#34;&gt;API for those&lt;/a&gt; as well) or select a location from &lt;code&gt;biome-query-coords&lt;/code&gt;. Example configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-query-coords&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Helsinki, Finland&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60.16952&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;24.93545&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Berlin, Germany&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;52.52437&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;13.41053&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Dubai, UAE&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;25.0657&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;55.17128&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A timezone is also often required (&amp;ldquo;Settings&amp;rdquo; &amp;gt; &amp;ldquo;Timezone&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;The current group is switched with &lt;code&gt;&amp;lt;tab&amp;gt;&lt;/code&gt;. Each group&amp;rsquo;s section has a set of variables that can be toggled on and off, such as temperature, precipitation, etc. Check out the &lt;a href=&#34;https://open-meteo.com/en/docs&#34;&gt;API docs&lt;/a&gt; if you&amp;rsquo;re interested in the meaning of more esoteric ones.&lt;/p&gt;
&lt;p&gt;Press &lt;code&gt;RET&lt;/code&gt; after you&amp;rsquo;ve configured the query to call the API. If something goes wrong, it will output an error, such as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Open Meteo has returned an error.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Error: (error http 400)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reason: Timezone is required
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or it will open the results table (the first screenshot).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tabulated-list&lt;/code&gt; doesn&amp;rsquo;t support horizontal scrolling, so press &lt;code&gt;c&lt;/code&gt; to toggle columns&amp;rsquo; visibility.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/columns.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Press &lt;code&gt;c&lt;/code&gt; or invoke &lt;code&gt;M-x biome-grid-export-csv&lt;/code&gt; to export the results in CSV format.&lt;/p&gt;
&lt;h2 id=&#34;more-configuration&#34;&gt;More configuration&lt;/h2&gt;
&lt;p&gt;To save a query for later, press &lt;code&gt;P&lt;/code&gt; in the root of the query interface. This will generate a definition like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;biome-def-preset&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-query-preset-177&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Weather Forecast&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;windgusts_10m&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;windspeed_10m&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;cloudcover&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;surface_pressure&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;weathercode&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;snowfall&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;showers&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rain&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;relativehumidity_2m&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;temperature_2m&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;longitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;24.93545&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;latitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60.16952&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add this somewhere in your config after the package is loaded, e.g., in the &lt;code&gt;:config&lt;/code&gt; section of the &lt;code&gt;use-package&lt;/code&gt; form or wrapped in &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Hooks-for-Loading.html#index-with_002deval_002dafter_002dload&#34;&gt;with-eval-after-load&lt;/a&gt;. Running &lt;code&gt;M-x biome-query-preset-177&lt;/code&gt; will create a query interface with this preset.&lt;/p&gt;
&lt;p&gt;Alternatively, use the &lt;code&gt;add-to-list&lt;/code&gt; form (generated below the &lt;code&gt;biome-def-preset&lt;/code&gt; form). Presets added that way will show up in &lt;code&gt;M-x biome-presets&lt;/code&gt; or &amp;ldquo;Presets&amp;rdquo; in &lt;code&gt;M-x biome&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Table formatting can be configured with &lt;code&gt;biome-grid-format&lt;/code&gt;; check the docstring for more information. For instance, if you want to disable all gradients:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-grid-format&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car-safe&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;gradient&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-grid-format&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Turn off highlighting of the current hour or day as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-grid-highlight-current&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;composite-queries&#34;&gt;Composite queries&lt;/h2&gt;
&lt;p&gt;The package also allows executing multiple queries at once to join their results. This can be useful for comparing weather in different locations or for viewing different reports about the same location.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;M-x biome-multi&lt;/code&gt; to invoke the-multi query dialog.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/multi.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;(&lt;em&gt;yes, I&amp;rsquo;ve switched to a light theme since the time of the previous screenshot&lt;/em&gt;)&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;a&lt;/code&gt; invokes the standard query dialog, where pressing &lt;code&gt;RET&lt;/code&gt; returns to the root dialog, adding the query to the list. Pressing &lt;code&gt;RET&lt;/code&gt; in the root dialog executes the queries in the list.&lt;/p&gt;
&lt;p&gt;Queries are executed concurrently. The results are shown if all queries have been successfully completed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;P&lt;/code&gt; generates a preset defintion for the current query:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;biome-def-multi-preset&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-query-preset-601&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (((&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Air Quality&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;uv_index&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;european_aqi&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;longitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;24.93545&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;latitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60.16952&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Weather Forecast&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;weathercode&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;snowfall&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;showers&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rain&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;temperature_2m&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;longitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;24.93545&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;latitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60.16952&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just note that the macro is called &lt;code&gt;biome-def-multi-preset&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;implementation-notes&#34;&gt;Implementation notes&lt;/h2&gt;
&lt;p&gt;This isn&amp;rsquo;t the most complicated thing I&amp;rsquo;ve done, but it&amp;rsquo;s probably the most over-engineered one.&lt;/p&gt;
&lt;p&gt;As you may have guessed, the interfaces mirror the &lt;a href=&#34;https://open-meteo.com/en/docs&#34;&gt;API docs&lt;/a&gt;. I&amp;rsquo;ve implemented &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Parsing-HTML_002fXML.html&#34;&gt;parsing of these HTMLs&lt;/a&gt; in &lt;code&gt;biome-api-parse--generate&lt;/code&gt;, which generates the value of &lt;code&gt;biome-api-data&lt;/code&gt;. Initially, it downloaded the HTML pages by itself, but - imagine that - the website was migrated to Svelte after I implemented maybe 80% of the parsing logic, and the Svelte version populates the accordions via JavaScript. So, as of now, the function requires opening the website in the browser, manually toggling all the accordions, and copying the HTML from DevTools. Fortunately, the parsing is a one-off operation.&lt;/p&gt;
&lt;p&gt;Then, the interface&amp;hellip; I like &lt;a href=&#34;https://github.com/magit/transient/&#34;&gt;transient.el&lt;/a&gt;, so I wanted to make the interface generated dynamically from &lt;code&gt;biome-api-data&lt;/code&gt;, which turned out harder than I expected. I probably should&amp;rsquo;ve just used &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_mono/widget.html&#34;&gt;widget.el&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Generating sensible keys was a challenge. I&amp;rsquo;ve made an algorithm in &lt;code&gt;biome-query--unique-keys&lt;/code&gt; that sort of works well.&lt;/p&gt;
&lt;p&gt;And as for populating transient prefixes, I tried to use &lt;code&gt;:setup-children&lt;/code&gt; in a few places, but it&amp;rsquo;s not general enough, namely, it doesn&amp;rsquo;t seem to support specifying &lt;code&gt;:class&lt;/code&gt; for child groups&amp;hellip; So I ended up overriding &lt;code&gt;transient--layout&lt;/code&gt; in the prefix setup. This doesn&amp;rsquo;t seem to have any undesirable side effects.&lt;/p&gt;
&lt;p&gt;Also, the only way I found to use custom infix classes in these dynamic definitions was to eval &lt;code&gt;transient-define-infix&lt;/code&gt; for each required place. Unfortunately, that adds a lot of stuff to the interactive functions namespace.&lt;/p&gt;
&lt;p&gt;Getting to the results display, Lars Ingebrigtsen&amp;rsquo;s &lt;a href=&#34;https://lars.ingebrigtsen.no/2022/04/13/more-vtable-fun/&#34;&gt;vtable&lt;/a&gt; comes only in Emacs 29, so I used &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Tabulated-List-Mode.html&#34;&gt;tabulated-list&lt;/a&gt;. The only disadvantage of the latter is the lack of horizontal scroll support, which can be worked around by hiding columns with &lt;code&gt;biome-grid-columns&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most variables are formatted with a gradient, colors for which were mostly inspired by &lt;a href=&#34;https://www.windy.com/&#34;&gt;Windy&lt;/a&gt;. Formatting for things like air quality variables is probably all over the place, so take the red color with a grain of salt.&lt;/p&gt;
</content>
</item>
<item>
<title>micromamba.el</title>
<link>https://sqrtminusone.xyz/packages/micromamba/</link>
<pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/micromamba/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/micromamba&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/micromamba-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Emacs package for working with &lt;a href=&#34;https://mamba.readthedocs.io/en/latest/user_guide/micromamba.html&#34;&gt;micromamba&lt;/a&gt; environments.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://mamba.readthedocs.io/en/latest/index.html&#34;&gt;mamba&lt;/a&gt; is a reimplementation of the &lt;a href=&#34;https://docs.conda.io/en/latest/&#34;&gt;conda&lt;/a&gt; package manager in C++. &lt;code&gt;mamba&lt;/code&gt; is notably much faster and essentially compatible with &lt;code&gt;conda&lt;/code&gt;, so it also works with &lt;a href=&#34;https://github.com/necaris/conda.el&#34;&gt;conda.el&lt;/a&gt;. &lt;code&gt;micromamba&lt;/code&gt;, however, implements only a subset of &lt;code&gt;mamba&lt;/code&gt; commands, and as such requires a separate integration.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, I prefer &lt;code&gt;use-package&lt;/code&gt; and &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;micromamba&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or clone the repository, add it to the &lt;code&gt;load-path&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;p&gt;If your &lt;code&gt;micromamba&lt;/code&gt; binary is located in some place unknown to &lt;code&gt;executable-find&lt;/code&gt;, set the &lt;code&gt;micromamba-executable&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;If you are running shells (e.g. &lt;a href=&#34;https://github.com/akermu/emacs-libvterm&#34;&gt;vterm&lt;/a&gt;) from Emacs, you probably want to set &lt;code&gt;auto_activate_base&lt;/code&gt; in your &lt;a href=&#34;https://docs.conda.io/projects/conda/en/latest/user-guide/configuration/index.html&#34;&gt;.condarc&lt;/a&gt; or &lt;a href=&#34;https://mamba.readthedocs.io/en/latest/user_guide/configuration.html&#34;&gt;.mambarc&lt;/a&gt;, because the shells are launched in the correct environment anyway.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;The package has two entrypoints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-x micromamba-activate&lt;/code&gt; - activate the environment&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x micromamba-deactivate&lt;/code&gt; - deactivate the environment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;micromamba-activate&lt;/code&gt; prompts for the environment (by parsing &lt;code&gt;micromamba env list&lt;/code&gt;). If some environments have duplicate names, these names are replaced by full paths.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve noticed that &lt;code&gt;micromamba&lt;/code&gt; also sees &lt;code&gt;conda&lt;/code&gt; environments, so migrating from &lt;code&gt;conda&lt;/code&gt; was rather painless for me.&lt;/p&gt;
&lt;h2 id=&#34;implementation-notes&#34;&gt;Implementation notes&lt;/h2&gt;
&lt;p&gt;I initially wanted to extend &lt;a href=&#34;https://github.com/necaris/conda.el&#34;&gt;conda.el&lt;/a&gt;, but decided it would be counterproductive for a few reasons.&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;conda&lt;/code&gt; is rather slow, so &lt;code&gt;conda.el&lt;/code&gt; does various tricks to avoid calling the &lt;code&gt;conda&lt;/code&gt; executable. For instance, it gets the environment list from scanning the anaconda home directory instead of running &lt;code&gt;conda env list&lt;/code&gt;. This is really not necessary with &lt;code&gt;micromamba&lt;/code&gt;, which is written in C++.&lt;/p&gt;
&lt;p&gt;Second, and more importantly, &lt;code&gt;conda.el&lt;/code&gt; relies heavily on passing &lt;code&gt;shell.posix+json&lt;/code&gt; to &lt;code&gt;conda&lt;/code&gt;. &lt;code&gt;micromamba&lt;/code&gt; doesn&amp;rsquo;t support that. It supports the &lt;code&gt;--json&lt;/code&gt; flag in some places, but not in the &lt;code&gt;activate&lt;/code&gt; command, so I have to parse the output of &lt;code&gt;micromamba shell -s bash activate&lt;/code&gt; and &lt;code&gt;micromamba shell -s bash deactivate&lt;/code&gt; to get the environment configuration.&lt;/p&gt;
&lt;p&gt;This also means the package most likely won&amp;rsquo;t work out-of-the-box on Windows.&lt;/p&gt;
</content>
</item>
<item>
<title>916 days of Emacs</title>
<link>https://sqrtminusone.xyz/posts/2023-04-13-emacs/</link>
<pubDate>Thu, 13 Apr 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2023-04-13-emacs/</guid>
<content type="html">
&lt;style&gt;
.quote-title {
margin-left: 24px;
}
&lt;/style&gt;
&lt;blockquote&gt;
&lt;p&gt;Poof I made my free-time disappear&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class=&#34;quote-title&#34;&gt;- &lt;a href=&#34;https://elken.dev&#34;&gt;Ellis Kenyő&lt;/a&gt;, on being called an &#34;elisp mage&#34;
&lt;p&gt;Little did I know on the fateful day of &lt;strong&gt;&lt;span class=&#34;timestamp-wrapper&#34;&gt;&lt;span class=&#34;timestamp&#34;&gt;[2020-10-09 Fri]&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;, when I had installed &lt;a href=&#34;https://www.gnu.org/software/emacs/&#34;&gt;GNU Emacs&lt;/a&gt;. I wasn&amp;rsquo;t thinking about the &lt;a href=&#34;https://www.gnu.org/philosophy/philosophy.html&#34;&gt;ethical aspects&lt;/a&gt; of free software, the &lt;a href=&#34;https://www.webofstories.com/play/marvin.minsky/44&#34;&gt;aesthetics of Lisp&lt;/a&gt;, or these other things with which an occasional layperson might explain how an almost &lt;a href=&#34;https://www.jwz.org/doc/emacs-timeline.html&#34;&gt;half a century old&lt;/a&gt; program can still be in &lt;a href=&#34;https://emacsconf.org/2022/talks/survey/&#34;&gt;active use&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In fact, when considering using software X for anything, the most important question to me was: can X provide a better user experience? For Emacs, the answer to most of these questions turned out to be yes.&lt;/p&gt;
&lt;p&gt;So over time, Emacs has become my programming environment, email client, window manager, knowledge base, &lt;a href=&#34;https://sqrtminusone.xyz/configs/emacs/&#34;&gt;and a lot more&lt;/a&gt;. I think I ended up using Emacs for almost as many things as possible; I even authored a few packages that implement certain parts of my workflows that weren&amp;rsquo;t readily available.&lt;/p&gt;
&lt;p&gt;Among other things, the Emacs community is responsible for my introduction to &lt;a href=&#34;https://zettelkasten.de/&#34;&gt;Zettelkasten&lt;/a&gt;, RSS, Lisps&amp;hellip; Perhaps even my English became slightly less broken because Emacs is so text-centered. A lot has changed over the course of these short 2.5 years.&lt;/p&gt;
&lt;p&gt;Anyway, this post is an attempt to quantify some aspects of that story. The numbers mostly come from projects called &lt;a href=&#34;https://activitywatch.net/&#34;&gt;ActivityWatch&lt;/a&gt; and &lt;a href=&#34;https://wakatime.com/&#34;&gt;WakaTime&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mostly I&amp;rsquo;m curious myself, but also every now and then I see Emacs people discussing their journeys through the Elisp-land, or a potential convert wondering whether this rabbit hole is worth investigating. If any of this applies to you, you might find something interesting in this document.&lt;/p&gt;
&lt;noscript&gt;
Also, I use a lot of JavaScript here, but it&#39;s all open source. The only 3rd party library is the MIT-licensed &lt;a href=&#34;https://www.chartjs.org/&#34;&gt;chart.js&lt;/a&gt;. So you need to enable JavaScript if you want to see the charts and some of the numbers that are dynamically calculated.
&lt;/noscript&gt;
&lt;h2 id=&#34;everything-goes-into-emacs&#34;&gt;Everything goes into Emacs&lt;/h2&gt;
&lt;p&gt;As I mentioned earlier, I use Emacs for a lot of things, which are described in my &lt;a href=&#34;https://sqrtminusone.xyz/configs/emacs/#introduction&#34;&gt;Emacs config&lt;/a&gt;. Fig. 1 shows how Emacs replaced various programs over time.&lt;/p&gt;
&lt;canvas id=&#34;chart-emacs-history&#34;&gt;
&lt;p&gt;Also, unfortunately this post turned out to be rather inaccessible for those reading that with a screen-reader. I guess, if that applies to you, just mentally skip the figure references.&lt;/p&gt;
&lt;p&gt;I did try to describe what&#39;s going on in these in the post body.&lt;/p&gt;
&lt;/canvas&gt;
&lt;p&gt;As you can see, I used Neovim for a little over a year. We&amp;rsquo;ll get into some numbers on that later.&lt;/p&gt;
&lt;p&gt;The process of moving from knowing nothing about Emacs to using EXWM took about 13 months.&lt;/p&gt;
&lt;p&gt;Fig. 2 shows the dynamics of the direct screen time ratio spent in Emacs per month, i.e. the average number of non-AFK seconds in the Emacs window.&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;chart-emacs-screen-time&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s hard to discern any general trend here. It appears that the ratio started at 0.2 in October 2020, oscillated around 0.3 for about 7 months, then moved closer to 0.4 until January 2023, after which jumped to 0.45-0.5.&lt;/p&gt;
&lt;p&gt;The three peaks in September 2021 (0.526), January 2022 (0.532), and August 2022 (0.568) may correspond to my vacations, during which I didn&amp;rsquo;t have to spend time in Chrome DevTools (I do web development as my &amp;ldquo;primary&amp;rdquo; job), but I&amp;rsquo;m not entirely sure.&lt;/p&gt;
&lt;p&gt;The jump in January 2023 definitely matches my adoption of &lt;a href=&#34;https://github.com/zevlg/telega.el&#34;&gt;telega.el&lt;/a&gt; instead of the official desktop client. The time redistributes rather cleanly in the detailed ActivityWatch data.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also interesting that switching from &lt;a href=&#34;https://i3wm.org/&#34;&gt;i3&lt;/a&gt; to &lt;a href=&#34;https://github.com/ch11ng/exwm&#34;&gt;EXWM&lt;/a&gt; didn&amp;rsquo;t seem to have any distinguishable effects.&lt;/p&gt;
&lt;p&gt;The mean Emacs screen time ratios are 0.39 since October 2020 and 0.47 since January 2023. So, as you might infer, Emacs is quite prominent in my PC usage.&lt;/p&gt;
&lt;h2 id=&#34;time-spent-in-emacs&#34;&gt;Time spent in Emacs&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s examine the structure of time spent in Emacs. Fig. 3 shows how many Emacs-hours per month I spent on different activities, and Fig. 4 shows the same in stacked form.&lt;/p&gt;
&lt;p&gt;Unlike Fig. 2, the time here is calculated with a 15-minute timeout preference, as &lt;a href=&#34;https://wakatime.com/faq#timeout&#34;&gt;it&amp;rsquo;s done in WakaTime&lt;/a&gt;. For instance, if I work on a project in Emacs for 10 minutes, then switch to something else for 10 minutes (i.e. no &lt;a href=&#34;https://wakatime.com/developers/#heartbeats&#34;&gt;heartbeats&lt;/a&gt; recorded during that time), then return to the project another 10 minutes, this will be counted as 30 minutes in that project.&lt;/p&gt;
&lt;p&gt;This is mostly so because it&amp;rsquo;s the default format for the &lt;a href=&#34;https://wakatime.com/faq#exporting&#34;&gt;WakaTime export&lt;/a&gt;, but I also believe it&amp;rsquo;s reasonable since I may open package documentation during configuration, experiment in scratch buffers while working on a package, and so on. This time really has to be included in the final tally.&lt;/p&gt;
&lt;p&gt;Of course, this will also include all the times I was distracted by the &lt;a href=&#34;https://wiki.systemcrafters.net/community/chat-with-us/&#34;&gt;System Crafters&lt;/a&gt; Discord server, &lt;a href=&#34;https://emacs.ch/&#34;&gt;emacs.ch&lt;/a&gt; Mastodon instance, or whatever else. Therefore, consider the numbers that follow as an upper bound.&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;chart-emacs-time&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;chart-emacs-time-stacked&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;p&gt;The categories are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Config&lt;/strong&gt; (&lt;span data-num=&#34;config_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; total hours, &lt;span data-num=&#34;config_hours_percent&#34;&gt;[REDACTED]&lt;/span&gt;% of all time)&lt;br /&gt;
Time spent on actual Emacs configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Emacs Packages&lt;/strong&gt; (&lt;span data-num=&#34;package_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; total hours, &lt;span data-num=&#34;package_hours_percent&#34;&gt;[REDACTED]&lt;/span&gt;% of all time)&lt;br /&gt;
Time spent in other Emacs Lisp files, such as writing my packages or debugging other packages. See the &lt;a href=&#34;#emacs-packages&#34;&gt;packages&lt;/a&gt; section.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Org Mode&lt;/strong&gt; (&lt;span data-num=&#34;orgmode_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; total hours, &lt;span data-num=&#34;orgmode_hours_percent&#34;&gt;[REDACTED]&lt;/span&gt;% of all time)&lt;br /&gt;
Time spent in my &lt;code&gt;org-mode&lt;/code&gt; project, which is mostly &lt;a href=&#34;https://github.com/bastibe/org-journal&#34;&gt;org-journal&lt;/a&gt;, &lt;a href=&#34;https://www.orgroam.com/&#34;&gt;org-roam&lt;/a&gt;, and project management. By the way, guess the month in which I read &lt;a href=&#34;https://www.soenkeahrens.de/en/takesmartnotes&#34;&gt;Sönke Ahrens&amp;rsquo; book&lt;/a&gt; about Zettelkasten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sqrtminusone.xyz&lt;/strong&gt; (&lt;span data-num=&#34;sqrt_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; total hours, &lt;span data-num=&#34;sqrt_hours_percent&#34;&gt;[REDACTED]&lt;/span&gt;% of all time)&lt;br /&gt;
Working on this strange little website.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other Code&lt;/strong&gt; (&lt;span data-num=&#34;other_code_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; total hours, &lt;span data-num=&#34;other_code_hours_percent&#34;&gt;[REDACTED]&lt;/span&gt;% of all time)&lt;br /&gt;
Doing something marginally useful in Emacs, which is mostly work, education, and a few personal projects unrelated to Emacs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Misc&lt;/strong&gt; (&lt;span data-num=&#34;misc_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; total hours, &lt;span data-num=&#34;misc_hours_percent&#34;&gt;[REDACTED]&lt;/span&gt;% of all time)
Time spent in Emacs but not in an actual project (i.e. accounted by the &lt;a href=&#34;https://github.com/ActivityWatch/aw-watcher-window&#34;&gt;window watcher&lt;/a&gt; of ActivityWatch but not WakaTime, which watches for files). That includes reading RSS, writing emails, using messengers, doing some idle experimentation in scratch buffers, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;span data-num=&#34;config_hours_percent&#34;&gt;[REDACTED]&lt;/span&gt;% of time spent on configuration is actually less than I expected. Unsurprisingly, the first month had the highest value of around 20% (I used Emacs without WakaTime for a few days).&lt;/p&gt;
&lt;p&gt;By the way, I spent just 39.0 hours configuring Neovim, although the number is probably not representative anymore because Neovim has changed a lot over these 2 years.&lt;/p&gt;
&lt;h2 id=&#34;switching-from-neovim&#34;&gt;Switching from Neovim&lt;/h2&gt;
&lt;p&gt;The period of my transition from Neovim to Emacs seems particularly interesting. Fig 5 zooms in on that, with the switch represented by &amp;ldquo;Other Code (Emacs)&amp;rdquo; replacing &amp;ldquo;Other Code (Vim)&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;chart-emacs-vim-switch&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;p&gt;It appears that getting from zero to somewhat productive took me about 11.1 hours over 4 days of just experimenting with Emacs, and one day with 3.8 hours on configuring and 4.4 hours on coding, apparently alternating between the two.&lt;/p&gt;
&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;
&lt;p&gt;Now, let&amp;rsquo;s examine where these &lt;span data-num=&#34;config_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; config hours went.&lt;/p&gt;
&lt;p&gt;Configuration sizes are a common topic of discussion among Emacs users. I&amp;rsquo;d guess that mine falls into the category of the longest, although maybe I&amp;rsquo;ll do some research on that someday. Fig. 6 shows how my configuration size changed over time.&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;chart-emacs-config-size&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;p&gt;So, my Emacs.org is &lt;span data-num=&#34;emacs_org_length&#34;&gt;[REDACTED]&lt;/span&gt; lines long, and the resulting init.el is &lt;span data-num=&#34;init_el_length&#34;&gt;[REDACTED]&lt;/span&gt; lines long.&lt;/p&gt;
&lt;p&gt;As you can see, I switched to &lt;a href=&#34;https://leanpub.com/lit-config&#34;&gt;literate configuration&lt;/a&gt; pretty early on, and so far, I have not regretted it. It&amp;rsquo;s also interesting to note how the two sizes diverged as I was writing more elaborate commentary.&lt;/p&gt;
&lt;p&gt;Also, I never had any substantial issues with maintaining that configuration. Perhaps &lt;a href=&#34;https://www.emacswiki.org/emacs/DotEmacsBankruptcy&#34;&gt;Emacs Bankruptcies&lt;/a&gt; are just not that common nowadays.&lt;/p&gt;
&lt;p&gt;For the sake of completeness, let&amp;rsquo;s compare that to my Neovim usage. Fig. 7 shows the dynamics of config size for the first 400 days of using both programs.&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;chart-emacs-vim-config-size&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;p&gt;As I previously mentioned, Neovim (or rather its ecosystem) seems to have undergone significant changes since I last used it, so my number of &lt;span data-num=&#34;init_vim_length&#34;&gt;[REDACTED]&lt;/span&gt; init.vim lines may no longer be relevant. Nonetheless, it&amp;rsquo;s quite interesting.&lt;/p&gt;
&lt;h2 id=&#34;emacs-packages&#34;&gt;Emacs packages&lt;/h2&gt;
&lt;p&gt;Working with Emacs packages was an interesting experience, not least because it was my first experience with Lisp. Fig. 8 shows the breakdown of the &lt;span data-num=&#34;package_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; hours I spent on that.&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;chart-emacs-packages&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;p&gt;As I expected, my &lt;a href=&#34;https://github.com/SqrtMinusOne/org-journal-tags&#34;&gt;org-journal-tags&lt;/a&gt; tops the chart with &lt;span data-num=&#34;org-journal-tags_total&#34;&gt;[REDACTED]&lt;/span&gt; hours. The most interesting part was implementing set logic on the &lt;a href=&#34;https://github.com/bastibe/org-journal&#34;&gt;org-journal&lt;/a&gt; entities to create a query engine. I&amp;rsquo;m fairly certain that I&amp;rsquo;m the only user of this package, but I use it all the time.&lt;/p&gt;
&lt;p&gt;The second place, &amp;ldquo;Unknown project&amp;rdquo;, stands for Emacs Lisp files that didn&amp;rsquo;t belong to any project, which should be mostly built-in Emacs files.&lt;/p&gt;
&lt;p&gt;My &lt;a href=&#34;https://github.com/SqrtMinusOne/elfeed-summary&#34;&gt;elfeed-summary&lt;/a&gt; (&lt;span data-num=&#34;elfeed-summary_total&#34;&gt;[REDACTED]&lt;/span&gt; hours), &lt;a href=&#34;https://github.com/SqrtMinusOne/lyrics-fetcher.el&#34;&gt;lyrics-fetcher&lt;/a&gt; (&lt;span data-num=&#34;lyrics-fetcher_total&#34;&gt;[REDACTED]&lt;/span&gt; hours), and &lt;a href=&#34;https://github.com/SqrtMinusOne/reverso.el&#34;&gt;reverso&lt;/a&gt; (&lt;span data-num=&#34;reverso_total&#34;&gt;[REDACTED]&lt;/span&gt; hours) are also among the packages that I use almost daily. Thus, I do not regret investing time in developing any of those.&lt;/p&gt;
&lt;h2 id=&#34;org-roam&#34;&gt;&lt;code&gt;org-roam&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s not directly related to Emacs, but I include it here because it&amp;rsquo;s highly unlikely that I would have heard the term &amp;ldquo;Zettelkasten&amp;rdquo; outside the Emacs space.&lt;/p&gt;
&lt;p&gt;I already mentioned &lt;a href=&#34;https://www.soenkeahrens.de/en/takesmartnotes&#34;&gt;Sönke Ahrens&amp;rsquo; book&lt;/a&gt;, but I believe the website &lt;a href=&#34;https://zettelkasten.de/posts/overview/&#34;&gt;zettelkasten.de&lt;/a&gt; would be a better resource if you are curious about that. And I was initially made curious by &lt;a href=&#34;https://www.youtube.com/watch?v=-TpWahIzueg&#34;&gt;this stream&lt;/a&gt; of David Wilson.&lt;/p&gt;
&lt;p&gt;Anyway, Fig. 9 shows the dynamics of my &lt;a href=&#34;https://github.com/org-roam/org-roam&#34;&gt;org-roam&lt;/a&gt; node count over time. A significant fraction of my &lt;span data-num=&#34;orgmode_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; hours spent on Org Mode went there. Although I don&amp;rsquo;t have any particular goals in this regard.&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;chart-roam-nodes&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;h2 id=&#34;some-observations&#34;&gt;Some observations&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s see where all of that leads us.&lt;/p&gt;
&lt;p&gt;As I said, I started from the point of zero experience with Lisp. I had a degree in software engineering, but I don&amp;rsquo;t feel like it has helped me in any direct sense. At most, it exposed me to different kinds and concepts of programming, but I am confident that it&amp;rsquo;s anything but a prerequisite, as also shown by the story of &lt;a href=&#34;https://protesilaos.com/&#34;&gt;Protesilaos&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The number of &lt;span data-num=&#34;config_hours_total&#34;&gt;[REDACTED]&lt;/span&gt; total hours of configuration may seem huge, but I don&amp;rsquo;t think it&amp;rsquo;s that much over 2.5 years and in comparison to the alternatives. For instance, it would take 6th place from the top if placed among my job projects. Also, my &lt;a href=&#34;https://antennapod.org/&#34;&gt;AntennaPod&lt;/a&gt; shows 196.9 hours of podcasts played since December 2021, and some of my friends report having spent thousands of hours on video games.&lt;/p&gt;
&lt;p&gt;And keep in mind that I use Emacs almost as extensively as it gets. You might as well spend much less time figuring it out for a more minimal use case. So, at least in my view, this weighs against describing Emacs usage in terms of sunk cost fallacy.&lt;/p&gt;
&lt;p&gt;However, my story is consistent with the perception of a &lt;a href=&#34;https://stackoverflow.com/questions/10942008/what-does-emacs-learning-curve-actually-look-like&#34;&gt;steep learning curve&lt;/a&gt; in the Emacs community. 19.3 hours over 5 days to get started is definitely a lot.&lt;/p&gt;
</content>
</item>
<item>
<title>Running Gource with Emacs</title>
<link>https://sqrtminusone.xyz/posts/2023-01-02-gource/</link>
<pubDate>Mon, 02 Jan 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2023-01-02-gource/</guid>
<content type="html">
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/images/gource/gource.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&#34;https://gource.io/&#34;&gt;Gource&lt;/a&gt; is a program that draws an animated graph of users changing the repository over time.&lt;/p&gt;
&lt;p&gt;Although it can work without extra effort (just run &lt;code&gt;gource&lt;/code&gt; in a &lt;a href=&#34;https://git-scm.com/&#34;&gt;git&lt;/a&gt; repo), there are some tweaks that can be done:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gource supports using custom pictures for users. &lt;a href=&#34;https://en.gravatar.com/&#34;&gt;Gravatar&lt;/a&gt; is an obvious place to get these.&lt;/li&gt;
&lt;li&gt;Occasionally, the same people have different names and/or emails in history.&lt;br /&gt;
It may happen when people use forges like &lt;a href=&#34;https://gitlab.com/&#34;&gt;GitLab&lt;/a&gt; or just have different settings on different machines. It would be nice to merge these names.&lt;/li&gt;
&lt;li&gt;Visualizing the history of multiple repositories (e.g. frontend and backend) requires combining multiple gource logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, why not try doing that with Emacs?&lt;/p&gt;
&lt;h2 id=&#34;gravatars&#34;&gt;Gravatars&lt;/h2&gt;
&lt;p&gt;Much to my surprise, Emacs turned out to have a built-in package called &lt;a href=&#34;https://github.com/emacs-mirror/emacs/blob/master/lisp/image/gravatar.el&#34;&gt;gravatar.el&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s make a function to retrieve a gravatar and save it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/gravatar-retrieve-sync&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get gravatar for EMAIL and save it to FILE-NAME.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;gravatar-default-image&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;identicon&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;gravatar-size&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;coding-system-for-write&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;binary&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;write-region-annotate-functions&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;write-region-post-annotation-function&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;write-region&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;image-property&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;gravatar-retrieve-synchronously&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt;) &lt;span style=&#34;color:#008000&#34;&gt;:data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:silent&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To use these images, we need to save them to some folder and use usernames as file names. The folder:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/gravatar-folder&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/.cache/gravatars/&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the function that downloads a gravatar if necessary:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/gravatar-save&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Download gravatar for EMAIL.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;AUTHOR is the username.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/gravatar-folder&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.png&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mkdir&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/gravatar-folder&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Fetching gravatar for %s (%s)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/gravatar-retrieve-sync&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;merging-authors&#34;&gt;Merging authors&lt;/h2&gt;
&lt;p&gt;Now to merging authors.&lt;/p&gt;
&lt;p&gt;Gource itself uses only usernames (without emails), but we can use &lt;code&gt;git log&lt;/code&gt; to get both. The required information can be extracted like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git log --pretty&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;format:&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%ae|%an&amp;#34;&lt;/span&gt; | sort | uniq -c | sed &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s/^[ \t]*//;s/ /|/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output is a list of pipe-separated strings, where the values are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Number of occurrences for this combination of username and email&lt;/li&gt;
&lt;li&gt;Email&lt;/li&gt;
&lt;li&gt;Username&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, that part would have to be changed appropriately for other version control systems if you happen to use one.&lt;/p&gt;
&lt;p&gt;So, below is one hell of a function that wraps this command and tries to merge emails and usernames belonging to one author:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/git-get-authors&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors-init&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Extract and merge all combinations of authors &amp;amp; emails from REPO.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;REPO is the path to a git repository.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;AUTHORS-INIT is the previous output of &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/git-get-authors&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;. It can
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;be used to extract that information from multiple repositories.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;The output is a list of alists with following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- emails: list of (&amp;lt;email&amp;gt; . &amp;lt;count&amp;gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- authors: list of (&amp;lt;username&amp;gt; . &amp;lt;count&amp;gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- email: the most popular email
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;- author: the most popular username
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;I.e. one alist is all emails and usernames of one author.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;default-directory&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;shell-command-to-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;git log --pretty=format:\&amp;#34;%ae|%an\&amp;#34; | sort | uniq -c | sed \&amp;#34;s/^[ \t]*//;s/ /|/\&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;string-to-number&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;downcase&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;author&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-reduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;authors&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:initial-value&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;email&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-reduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emails&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:initial-value&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-reduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;author&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;email&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;count&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;count&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-find&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emails&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;cand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;authors&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;cand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;authors&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;cand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emails&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;cand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;progn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emails&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-incf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emails&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;count&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emails&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;authors&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-incf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;authors&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;count&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;authors&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;saved-value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;emails&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; ((&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;count&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; ((&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;count&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:initial-value&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors-init&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Despite the probable we-enjoy-typing-ness of the implementation, it&amp;rsquo;s actually pretty simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The output of &lt;code&gt;git log&lt;/code&gt; is parsed into a list of alists with &lt;code&gt;count&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;author&lt;/code&gt; as keys.&lt;/li&gt;
&lt;li&gt;This list is reduced by &lt;code&gt;cl-reduce&lt;/code&gt; into a list of alists with &lt;code&gt;emails&lt;/code&gt; and &lt;code&gt;authors&lt;/code&gt; as keys and the respective counts as values, e.g. &lt;code&gt;((&amp;lt;email-1&amp;gt; . 1) (&amp;lt;email-2&amp;gt; . 3))&lt;/code&gt;.&lt;br /&gt;
I&amp;rsquo;ve seen a couple of cases where people would swap their username and email (lol), so &lt;code&gt;seq-find&lt;/code&gt; also looks for an email in the list of authors and vice versa.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;mapcar&lt;/code&gt; call determines the most popular email and username for each authors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The output is another list of alists, now with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;emails&lt;/code&gt; - list of elements like &lt;code&gt;(&amp;lt;email&amp;gt; . &amp;lt;count&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;authors&lt;/code&gt; - list of elements like &lt;code&gt;(&amp;lt;author-name&amp;gt; . &amp;lt;count&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email&lt;/code&gt; - the most popular email&lt;/li&gt;
&lt;li&gt;&lt;code&gt;author&lt;/code&gt; - the most popular username.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;running-for-multiple-repos&#34;&gt;Running for multiple repos&lt;/h2&gt;
&lt;p&gt;This section was mostly informed by &lt;a href=&#34;https://github.com/acaudwell/Gource/wiki/Visualizing-Multiple-Repositories&#34;&gt;this page&lt;/a&gt; in the &lt;a href=&#34;https://github.com/acaudwell/Gource/wiki&#34;&gt;gource wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As I said above, by default &lt;code&gt;gource&lt;/code&gt; just creates a visualization for the current repo. To change something in it, we need to invoke the program like that: &lt;code&gt;gource --output-custom-log PATH&lt;/code&gt;, where &lt;code&gt;PATH&lt;/code&gt; is either the path to the log file or &lt;code&gt;-&lt;/code&gt; for stdout.&lt;/p&gt;
&lt;p&gt;The log consists of lines of pipe-separated strings, e.g.:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1600769568|dsofronov|A|/studentor/.dockerignore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1600769568|dsofronov|A|/studentor/.editorconfig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1600769568|dsofronov|A|/studentor/.flake8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1600769568|dsofronov|A|/studentor/.gitignore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where the values of one line are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UNIX timestamp&lt;/li&gt;
&lt;li&gt;Author name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A&lt;/code&gt; for add, &lt;code&gt;M&lt;/code&gt; for modify, and &lt;code&gt;D&lt;/code&gt; for delete&lt;/li&gt;
&lt;li&gt;Path to file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The file has to be sorted by the timestamp in ascending order.&lt;/p&gt;
&lt;p&gt;So, the function that prepares the log for one repository:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/gource-prepare-log&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Create gource log string for REPO.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;AUTHORS is the output of &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/git-get-authors&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#00f&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;shell-command-to-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;gource --output-custom-log - &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;authors-mapping&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;make-hash-table&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:test&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;equal&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;prefix&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file-name-base&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author-datum&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;author&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author-datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/gravatar-save&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;email&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author-datum&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-author&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;authors&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author-datum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-author&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;puthash&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-author&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors-mapping&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;log&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;fragments&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;fragments&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;when-let&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mapped-author&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;gethash&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;fragments&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors-mapping&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;fragments&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;mapped-author&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;fragments&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;prefix&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;fragments&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-join&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;fragments&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Downloads a gravatar for each author&lt;/li&gt;
&lt;li&gt;Replaces all usernames of one author with the most frequent one&lt;/li&gt;
&lt;li&gt;Prepends the file path with the repository name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The output is a string in the gource log format as described above.&lt;/p&gt;
&lt;p&gt;Finally, as we need to invoke all of this for multiple repositories, why not do that with &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html&#34;&gt;dired&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/gource-dired-create-logs&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;repos&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;log-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Create combined gource log for REPOS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;REPOS is a list of strings, where a string is a path to a git repo.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;LOG-NAME is the path to the resulting log file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;This function is meant to be invoked from &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`dired&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;, where the required
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;repositories are marked.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dired-get-marked-files&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;file-directory-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Select at least one directory&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;read-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Log file name: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;combined.log&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-reduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/git-get-authors&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;acc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:initial-value&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-temp-file&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;log-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-join&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-sort-by&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;if-let&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-to-number&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&amp;lt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapconcat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/gource-prepare-log&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;repos&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function extracts authors from each repository and merges the logs as required by gource, that is sorting the result by time in ascending order.&lt;/p&gt;
&lt;h2 id=&#34;using-the-function&#34;&gt;Using the function&lt;/h2&gt;
&lt;p&gt;To use the function above, mark the required repos in a dired buffer and run &lt;code&gt;M-x my/gource-dired-create-logs&lt;/code&gt;. This also works nicely with &lt;a href=&#34;https://github.com/Fuco1/dired-hacks&#34;&gt;dired-subtree&lt;/a&gt;, in case your repos are located in different folders.&lt;/p&gt;
&lt;p&gt;The function will create a combined log file (by default &lt;code&gt;combined.log&lt;/code&gt;). To visualize the log, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gource &amp;lt;log-file&amp;gt; --user-image-dir &amp;lt;path-to-gravatars&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check the &lt;a href=&#34;https://github.com/acaudwell/Gource&#34;&gt;README&lt;/a&gt; for possible parameters, such as the speed of visualization, different elements, etc. That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;I thought about making something like a &lt;a href=&#34;https://github.com/magit/transient&#34;&gt;transient.el&lt;/a&gt; wrapper around the &lt;code&gt;gource&lt;/code&gt; command but figured it wasn&amp;rsquo;t worth the effort for something that I run just a handful of times in a year.&lt;/p&gt;
</content>
</item>
<item>
<title>Podcast transcripts with elfeed &amp; speech recognition engine</title>
<link>https://sqrtminusone.xyz/posts/2022-09-16-vosk/</link>
<pubDate>Fri, 16 Sep 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2022-09-16-vosk/</guid>
<content type="html">
&lt;p&gt;&lt;strong&gt;Edit &lt;span class=&#34;timestamp-wrapper&#34;&gt;&lt;span class=&#34;timestamp&#34;&gt;&amp;lt;2022-10-13 Thu&amp;gt;&lt;/span&gt;&lt;/span&gt;:&lt;/strong&gt; Just a couple of days after this post, OpenAI released a speech recognition model called &lt;a href=&#34;https://openai.com/blog/whisper/&#34;&gt;Whisper&lt;/a&gt;, which is so much better than anything I&amp;rsquo;ve ever seen before. I&amp;rsquo;ve decided to leave this post as it is, but check the &lt;a href=&#34;https://sqrtminusone.xyz/configs/emacs/#podcast-transcripts&#34;&gt;Emacs config&lt;/a&gt; for the updated version.&lt;/p&gt;
&lt;p&gt;In my experience, finding something in a podcast is particularly troublesome. For example, occasionally I want to refer to some line in the podcast to make an &lt;a href=&#34;https://github.com/org-roam/org-roam&#34;&gt;org-roam&lt;/a&gt; node, e.g. I want to check that I got that part right.&lt;/p&gt;
&lt;p&gt;And I have no reasonable way to get there because audio files in themselves don&amp;rsquo;t allow for &lt;a href=&#34;https://en.wikipedia.org/wiki/Random_access&#34;&gt;random access&lt;/a&gt;, i.e. there are no &amp;ldquo;landmarks&amp;rdquo; that point to this or that portion of the file. At least if nothing like a transcript is available.&lt;/p&gt;
&lt;p&gt;For obvious reasons, podcasts rarely ship with transcripts. So in this post, I&amp;rsquo;ll be using a speech recognition engine to make up for that. A generated transcript is not quite as good as a manually written one, but for the purpose of finding a fragment of a known podcast, it works well enough.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/images/vosk/img.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The general idea is to get the podcast info from &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt;, process it with &lt;a href=&#34;https://github.com/alphacep/vosk-api&#34;&gt;vosk-api&lt;/a&gt; and feed it to &lt;a href=&#34;https://github.com/sachac/subed&#34;&gt;subed&lt;/a&gt; to control the playback in &lt;a href=&#34;https://mpv.io/&#34;&gt;MPV&lt;/a&gt;. I&amp;rsquo;ve done something similar for &lt;a href=&#34;https://sqrtminusone.xyz/posts/2022-05-09-pdf/#youtube-transcripts&#34;&gt;YouTube videos&lt;/a&gt; in the previous post, by the way.&lt;/p&gt;
&lt;p&gt;Be sure to enable &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html&#34;&gt;lexical binding&lt;/a&gt; for the context of evaluation. For instance, for &lt;code&gt;init.el&lt;/code&gt; you can add the following line to the top:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;;; -*- lexical-binding: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;vosk-api&#34;&gt;Vosk API&lt;/h2&gt;
&lt;p&gt;After some search, I found &lt;a href=&#34;https://github.com/alphacep/vosk-api&#34;&gt;Vosk API&lt;/a&gt;, an offline speech recognition toolkit.&lt;/p&gt;
&lt;p&gt;I want to make a program that receives an audio file and outputs an &lt;a href=&#34;https://en.wikipedia.org/wiki/SubRip&#34;&gt;SRT&lt;/a&gt; file. Vosk provides bindings to different languages, of which I choose Python because&amp;hellip; reasons.&lt;/p&gt;
&lt;p&gt;So, with the help of kindly provided &lt;a href=&#34;https://github.com/alphacep/vosk-api/tree/master/python/example&#34;&gt;examples&lt;/a&gt; of how to use the Python API, the resulting script is listed below. Except Vosk, the script uses &lt;a href=&#34;https://click.palletsprojects.com/en/8.1.x/&#34;&gt;click&lt;/a&gt; to make a simple CLI, a library aptly called &lt;a href=&#34;https://github.com/cdown/srt&#34;&gt;srt&lt;/a&gt; to make srt files, and &lt;a href=&#34;https://ffmpeg.org/&#34;&gt;ffmpeg&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;datetime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;math&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;subprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;click&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;srt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;vosk&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; KaldiRecognizer, Model, SetLogLevel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f&#34;&gt;@click.command&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f&#34;&gt;@click.option&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;--file-path&amp;#39;&lt;/span&gt;, required&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;True&lt;/span&gt;, help&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;Path to the audio file&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f&#34;&gt;@click.option&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;--model-path&amp;#39;&lt;/span&gt;, required&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;True&lt;/span&gt;, help&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;Path to the model&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f&#34;&gt;@click.option&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;--save-path&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; required&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;True&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; default&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;result.srt&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; help&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;Path to resulting SRT file&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f&#34;&gt;@click.option&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;--words-per-line&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; required&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;True&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;int&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; default&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;14&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; help&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;Number of words per line&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;transcribe&lt;/span&gt;(file_path, model_path, save_path, words_per_line&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;7&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sample_rate &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;16000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; SetLogLevel(&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; model &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; Model(model_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rec &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; KaldiRecognizer(model, sample_rate)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rec&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;SetWords(&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; process &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; subprocess&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Popen(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;ffmpeg&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;-loglevel&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;quiet&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;-i&amp;#39;&lt;/span&gt;, file_path, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;-ar&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;str&lt;/span&gt;(sample_rate), &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;-ac&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;1&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;-f&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;s16le&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;-&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; stdout&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;subprocess&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;PIPE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; results &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; data &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; process&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;stdout&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;read(&lt;span style=&#34;color:#666&#34;&gt;4000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;len&lt;/span&gt;(data) &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; rec&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;AcceptWaveform(data):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;loads(rec&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Result())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; results&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(res)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; math&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;log2(&lt;span style=&#34;color:#008000&#34;&gt;len&lt;/span&gt;(results)) &lt;span style=&#34;color:#666&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;Progress: &lt;/span&gt;&lt;span style=&#34;color:#b68;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;len&lt;/span&gt;(results)&lt;span style=&#34;color:#b68;font-weight:bold&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; results&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(json&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;loads(rec&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;FinalResult()))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; subs &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;for&lt;/span&gt; res &lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;in&lt;/span&gt; results:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;result&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;in&lt;/span&gt; res:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; words &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; res[&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;result&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;for&lt;/span&gt; j &lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#008000&#34;&gt;len&lt;/span&gt;(words), words_per_line):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; line &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; words[j:j &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; words_per_line]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; s &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; srt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Subtitle(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; index&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;len&lt;/span&gt;(subs),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; content&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;join([l[&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;word&amp;#39;&lt;/span&gt;] &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;for&lt;/span&gt; l &lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;in&lt;/span&gt; line]),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; start&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;datetime&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;timedelta(seconds&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;line[&lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;][&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;start&amp;#39;&lt;/span&gt;]),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; end&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;datetime&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;timedelta(seconds&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;line[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;][&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;end&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; subs&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; srt_res &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; srt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;compose(subs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;open&lt;/span&gt;(save_path, &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; f&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;write(srt_res)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; __name__ &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; transcribe()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the corresponding &lt;code&gt;requirements.txt&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vosk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;click
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;srt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another piece we need is a speech recognition model, some of which you can download &lt;a href=&#34;https://alphacephei.com/vosk/models&#34;&gt;on their website&lt;/a&gt;. I chose a small English model called &lt;code&gt;vosk-model-small-en-us-0.15&lt;/code&gt; because all my podcasts are in English and also because larger models are much slower.&lt;/p&gt;
&lt;p&gt;Now that we have the script and the model, we need to create a virtual environment. Somehow I couldn&amp;rsquo;t install the &lt;code&gt;vosk&lt;/code&gt; package with &lt;a href=&#34;https://docs.conda.io/en/latest/&#34;&gt;conda&lt;/a&gt;, but the Guix version of Python with &lt;code&gt;virtualenv&lt;/code&gt; worked just fine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 -m virtualenv venv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;source&lt;/span&gt; venv/bin/activate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After which the script can be used as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python main.py --file-path &amp;lt;path-to-file&amp;gt; --model-path ./model-small --save-path &amp;lt;path-to-subtitles-file&amp;gt;.srt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;running-it-from-emacs&#34;&gt;Running it from Emacs&lt;/h2&gt;
&lt;p&gt;The next step is to run the script from Emacs. This is rather straightforward to do with &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Asynchronous-Processes.html&#34;&gt;asyncronous processes&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/vosk-script-path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Code/system-crafting/podcasts-vosk/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Path to the &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`podcasts-vosk&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; script folder.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/invoke-vosk&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;output&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Extract subtitles from the audio file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;INPUT is the audio file, OUTPUT is the path to the resulting SRT file.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;read-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Input file: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;read-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SRT file: &amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;generate-new-buffer&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;vosk&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;default-directory&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/vosk-script-path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;start-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;vosk_api&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/vosk-script-path&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;venv/bin/python&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;main.py&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--file-path&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--model-path&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;./model-small&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--save-path&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--words-per-line&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;14&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;set-process-sentinel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;_msg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-exit-status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exit&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;notifications-notify&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SRT conversion completed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Vosk API&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exit&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;signal&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;err&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-string&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;kill-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Error in Vosk API: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;err&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If run interactively, the defined function prompts for paths to both files.&lt;/p&gt;
&lt;p&gt;The process sentinel sends a &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Desktop-Notifications.html&#34;&gt;desktop notification&lt;/a&gt; because it&amp;rsquo;s a bit more noticeable than &lt;code&gt;message&lt;/code&gt;, and the process is expected to take some time.&lt;/p&gt;
&lt;h2 id=&#34;integrating-with-elfeed&#34;&gt;Integrating with elfeed&lt;/h2&gt;
&lt;p&gt;To actually run the function from the section above, we need to download the file in question.&lt;/p&gt;
&lt;p&gt;So first, let&amp;rsquo;s extract the file name from the URL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/get-file-name-from-url&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Extract file name from the URL.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-match&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;color:#ba2121&#34;&gt;? &lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;match-string&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;No file name found. Somehow&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Remove the first /&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Remove the trailing /&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;1-&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;match&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I use a library called &lt;a href=&#34;https://github.com/tkf/emacs-request&#34;&gt;request.el&lt;/a&gt; to download files elsewhere, so I&amp;rsquo;ll re-use it here. You can just as well invoke &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt; via a asynchronous process.&lt;/p&gt;
&lt;p&gt;This function downloads the file to a non-temporary folder, which is &lt;code&gt;~/.elfeed/podcast-files/&lt;/code&gt; if you didn&amp;rsquo;t move the elfeed database. That is so because a permanently downloaded file works better for the next section.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;with-eval-after-load&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;elfeed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-podcast-files-directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-db-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/podcast-files/&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-get-transcript-new&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;srt-path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/get-file-name-from-url&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file-path&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-podcast-files-directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Download started&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-podcast-files-directory&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;mkdir&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-podcast-files-directory&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;request&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:encoding&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;binary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:complete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;allow-other-keys&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;coding-system-for-write&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;binary&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;write-region-annotate-functions&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;write-region-post-annotation-function&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;write-region&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-path&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:silent&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Conversion started&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/invoke-vosk&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-path&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;srt-path&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;error-thrown&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;allow-other-keys&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Error!: %S&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;error-thrown&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also experimented with a bunch of options to write binary data in Emacs, of which the way with &lt;code&gt;write-region&lt;/code&gt; (as implemented in &lt;a href=&#34;https://github.com/rejeep/f.el&#34;&gt;f.el&lt;/a&gt;) seems to be the fastest. &lt;a href=&#34;https://emacs.stackexchange.com/questions/59449/how-do-i-save-raw-bytes-into-a-file&#34;&gt;This thread on StackExchange&lt;/a&gt; suggests that it may screw some bytes towards the end, but whether or not this is the case, mp3 files survive the procedure. The proposed solution with &lt;code&gt;seq-doseq&lt;/code&gt; takes at least a few seconds.&lt;/p&gt;
&lt;p&gt;Finally, we need a function to show the transcript if it exists or invoke &lt;code&gt;my/elfeed-vosk-get-transcript-new&lt;/code&gt; if it doesn&amp;rsquo;t. And this is the function that we&amp;rsquo;ll call from an &lt;code&gt;elfeed-entry&lt;/code&gt; buffer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-get-transcript&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Retrieve transcript for the enclosure of the current elfeed ENTRY.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;enclosure&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;caar&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-enclosures&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;enclosure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;No enclosure found!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;srt-path&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-srt-dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-ref-id&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.srt&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;srt-path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;find-file-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;srt-path&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-get-transcript-new&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;enclosure&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;srt-path&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;integrating-with-subed&#34;&gt;Integrating with subed&lt;/h2&gt;
&lt;p&gt;Now that we&amp;rsquo;ve produced a &lt;code&gt;.srt&lt;/code&gt; file, we can use a package called &lt;a href=&#34;https://github.com/sachac/subed&#34;&gt;subed&lt;/a&gt; to control the playback, like I had done in the previous post.&lt;/p&gt;
&lt;p&gt;By the way, this wasn&amp;rsquo;t the most straightforward thing to figure out, because the MPV window doesn&amp;rsquo;t show up for an audio file, and the player itself starts in the paused state. So I thought nothing was happening until I enabled the debug log.&lt;/p&gt;
&lt;p&gt;With that in mind, here&amp;rsquo;s a function to launch MPV from the buffer generated by &lt;code&gt;my/elfeed-vosk-get-transcript&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-subed&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Run MPV for the current Vosk-generated subtitles file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;ENTRY is an instance of &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`elfeed-entry&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;No entry!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;derived-mode-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;subed-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Not subed mode!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;subed-mpv-video-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-vosk-podcast-files-directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/get-file-name-from-url&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;caar&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-enclosures&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;subed-mpv--play&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;subed-mpv-video-file&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After running &lt;code&gt;M-x my/elfeed-vosk-subed&lt;/code&gt;, run &lt;code&gt;M-x subed-toggle-loop-over-current-subtitle&lt;/code&gt; (&lt;code&gt;C-c C-l&lt;/code&gt;), because somehow it&amp;rsquo;s turned on by default, and &lt;code&gt;M-x subed-toggle-pause-while-typing&lt;/code&gt; (&lt;code&gt;C-c C-p&lt;/code&gt;), because sometimes this made my instance of MPV lag.&lt;/p&gt;
&lt;p&gt;After that, &lt;code&gt;M-x subed-mpv-toggle-pause&lt;/code&gt; should start the playback, which you can control by moving the cursor in the buffer.&lt;/p&gt;
&lt;p&gt;You can also run &lt;code&gt;M-x subed-toggle-sync-point-to-player&lt;/code&gt; (&lt;code&gt;C-c .&lt;/code&gt;) to toggle syncing the point in the buffer to the currently played subtitle (this automatically gets disabled when you switch buffers).&lt;/p&gt;
&lt;p&gt;Running &lt;code&gt;M-x subed-toggle-sync-player-to-point&lt;/code&gt; (&lt;code&gt;C-c ,&lt;/code&gt;) does the opposite, i.e. sets the player position to the subtitle under point. These two functions are useful since the MPV window controls aren&amp;rsquo;t available.&lt;/p&gt;
&lt;h2 id=&#34;some-observations&#34;&gt;Some observations&lt;/h2&gt;
&lt;p&gt;So, the functions above work for my purposes.&lt;/p&gt;
&lt;p&gt;I think it should be possible to get transcripts of better quality by using a better speech recognition model, adding a speaker detection model and a model to restore case &amp;amp; punctuation. But it seems to be harder to implement, and this would take more time and resources. On my PC, the smallest Vosk model runs maybe 10 times faster than the playback time, which is still a few minutes for an hour-long podcast. Waiting longer is probably not worth it.&lt;/p&gt;
&lt;p&gt;Also, technically MPV can stream files without downloading them, and it&amp;rsquo;s even possible to feed stream data into Vosk. But MPV isn&amp;rsquo;t particularly good at seeking in streamed files, at least not with my Internet connection.&lt;/p&gt;
</content>
</item>
<item>
<title>reverso.el</title>
<link>https://sqrtminusone.xyz/packages/reverso/</link>
<pubDate>Sun, 28 Aug 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/reverso/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/reverso&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/reverso-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Emacs client for &lt;a href=&#34;https://www.reverso.net/&#34;&gt;Reverso&lt;/a&gt;. The implemented features are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reverso.net/text-translation&#34;&gt;Translation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://context.reverso.net/translation/&#34;&gt;Context&lt;/a&gt; (AKA bilingual concordances)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reverso.net/spell-checker/english-spelling-grammar/&#34;&gt;Grammar check&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://synonyms.reverso.net/synonym/&#34;&gt;Synonyms search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://conjugator.reverso.net/conjugation-english.html&#34;&gt;Conjugation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, e.g. with &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/radian-software/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;reverso&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or &lt;a href=&#34;https://tony-zorman.com/posts/use-package-vc.html&#34;&gt;use-package with vc&lt;/a&gt;, which works on Emacs 30 out-of-the-box.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;reverso&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:vc&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;https://github.com/SqrtMinusOne/reverso.el.git&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, clone the repository, add it to the &lt;code&gt;load-path&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a single entrypoint for all implemented functions: &lt;code&gt;M-x reverso&lt;/code&gt;. The UI is implemented using the excellent &lt;a href=&#34;https://github.com/magit/transient/&#34;&gt;transient.el&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;input-handling&#34;&gt;Input Handling&lt;/h3&gt;
&lt;p&gt;All commands handle input as follows:&lt;/p&gt;
&lt;p&gt;By default, the input string is empty. If a command is launched with a region selected, use the string of that region. If launched with the prefix argument (&lt;code&gt;C-u&lt;/code&gt;), use the entire buffer.&lt;/p&gt;
&lt;p&gt;Results are displayed in &lt;code&gt;reverso-result-mode&lt;/code&gt; buffers. When launched within that buffer, the command uses the input string specific to the buffer. If launched with &lt;code&gt;C-u&lt;/code&gt;, it uses the output string from that buffer (if available).&lt;/p&gt;
&lt;h3 id=&#34;translation&#34;&gt;Translation&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso t&lt;/code&gt; or &lt;code&gt;M-x reverso-translate&lt;/code&gt; to invoke the translation transient.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/translation-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The &amp;ldquo;Source language&amp;rdquo; and &amp;ldquo;Target language&amp;rdquo; parameters are self-explanatory. Note that not every language is compatible with every other language in the general case. &amp;ldquo;Swap languages&amp;rdquo; attempts to swap them.&lt;/p&gt;
&lt;p&gt;Enabling &amp;ldquo;Brief translation output&amp;rdquo; will display only the translated version of the string in the output buffer.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/translation-res.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Otherwise, the result buffer may contain the following sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Source text&lt;/strong&gt; and &lt;strong&gt;Translation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corrected text&lt;/strong&gt;, if available&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context results&lt;/strong&gt;, if available&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Context results typically appear for short strings, as seen in the example from the screenshot.&lt;/p&gt;
&lt;h3 id=&#34;context&#34;&gt;Context&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso c&lt;/code&gt; or &lt;code&gt;M-x reverso-context&lt;/code&gt; to invoke context search (or &lt;a href=&#34;https://en.wikipedia.org/w/index.php?title=Online_bilingual_concordance&amp;amp;redirect=no&#34;&gt;bilingual concordances&lt;/a&gt;, essentially a Rosetta stone generator).&lt;/p&gt;
&lt;p&gt;The input/output UI resembles that of the translation command.&lt;/p&gt;
&lt;p&gt;Interestingly, direct context search often yields different results than the &amp;ldquo;Context results&amp;rdquo; section of the translation command. Hence, checking both might provide more comprehensive data.&lt;/p&gt;
&lt;h3 id=&#34;synonyms&#34;&gt;Synonyms&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso s&lt;/code&gt; or &lt;code&gt;M-x reverso-synonyms&lt;/code&gt; to invoke the synonyms search.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/synonyms-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/synonyms-res.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;If necessary, results are segmented by parts of speech.&lt;/p&gt;
&lt;p&gt;Each part of speech section contains up to three subsections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Synonyms&lt;/li&gt;
&lt;li&gt;Examples&lt;/li&gt;
&lt;li&gt;Antonyms&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;conjugation&#34;&gt;Conjugation&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso o&lt;/code&gt; or &lt;code&gt;M-x reverso-conjugation&lt;/code&gt; to invoke verb conjugation dialog.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/conjugation-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/conjugation-res.png&#34;&gt;
&lt;/figure&gt;
&lt;h3 id=&#34;grammar-check&#34;&gt;Grammar check&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso g&lt;/code&gt; or &lt;code&gt;M-x reverso-grammar&lt;/code&gt; to invoke the grammar check.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/grammar-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Currently, only English, French, Spanish, and Italian languages are available.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/grammar-res.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The results may contain the following sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Source text&lt;/strong&gt;, highlighting errors with &lt;code&gt;reverso-error-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corrected text&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corrections&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;grammar-check-in-buffer&#34;&gt;Grammar check in buffer&lt;/h3&gt;
&lt;p&gt;It can be convenient to apply the grammar check directly to the current buffer without displaying results in another buffer. Use &lt;code&gt;M-x reverso b&lt;/code&gt; or &lt;code&gt;M-x reverso-grammar-buffer&lt;/code&gt; for this.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/grammar-buffer-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Running &lt;code&gt;e&lt;/code&gt; there (or &lt;code&gt;M-x reverso-check-buffer&lt;/code&gt;) utilizes the current buffer as input and highlights any found errors using overlays. If a region is selected, the check is confined to that region.&lt;/p&gt;
&lt;p&gt;There are a couple of caveats there. First, the service considers each linebreak as a new line, which is incompatible with &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Filling.html&#34;&gt;filling text&lt;/a&gt;, i.e. breaking it into lines of a specified width. The &amp;ldquo;Remove linebreaks&amp;rdquo; option (&lt;code&gt;l&lt;/code&gt;) is a workaround for this.&lt;/p&gt;
&lt;p&gt;Secondly, the service usually freaks out with special syntax, for instance, Org Mode links.&lt;/p&gt;
&lt;p&gt;The third issue partly follows from the second one, as the service often finds &amp;ldquo;errors&amp;rdquo; within hidden parts of Org links. Either skip these errors or execute &lt;code&gt;M-x org-toggle-link-display&lt;/code&gt; in Org files beforehand.&lt;/p&gt;
&lt;p&gt;Lastly (and this applies to all other methods as well), the API usually restricts input size. If the service returns an error, try running the command on a smaller region of the buffer.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/grammar-buffer-res.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;When the cursor is placed on an error, the &amp;ldquo;Information&amp;rdquo; section provides details.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Fix error&amp;rdquo; (&lt;code&gt;f&lt;/code&gt; or &lt;code&gt;M-x reverso-check-fix-at-point&lt;/code&gt;) opens a completion interface with potential fixes. &amp;ldquo;Ignore error&amp;rdquo; (&lt;code&gt;i&lt;/code&gt; or &lt;code&gt;M-x reverso-check-ignore-error&lt;/code&gt;) simply removes the overlay and moves to the next error.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Previous error&amp;rdquo; (&lt;code&gt;p&lt;/code&gt; or &lt;code&gt;M-x reverso-check-prev-error&lt;/code&gt;), &amp;ldquo;Next error&amp;rdquo; (&lt;code&gt;n&lt;/code&gt; or &lt;code&gt;M-x reverso-check-next-error&lt;/code&gt;), &amp;ldquo;First error&amp;rdquo; (&lt;code&gt;P&lt;/code&gt; or &lt;code&gt;M-x reverso-check-first-error&lt;/code&gt;) and &amp;ldquo;Last error&amp;rdquo; (&lt;code&gt;L&lt;/code&gt; or &lt;code&gt;M-x reverso-check-last-error&lt;/code&gt;) serve to navigate the error list.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Clear&amp;rdquo; (&lt;code&gt;c&lt;/code&gt; or &lt;code&gt;M-x reverso-clear&lt;/code&gt;) removes error overlays. If a region is selected, it removes overlays only in that region; otherwise, it removes them from the entire buffer.&lt;/p&gt;
&lt;h3 id=&#34;history&#34;&gt;History&lt;/h3&gt;
&lt;p&gt;Enable &lt;code&gt;reverso-history-mode&lt;/code&gt; to keep history:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;reverso-history-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I haven&amp;rsquo;t implemented persistence yet, but I might in the future.&lt;/p&gt;
&lt;p&gt;After enabling the minor mode, &lt;code&gt;M-x reverso-history&lt;/code&gt; or &lt;code&gt;M-x reverso h&lt;/code&gt; will display recent commands. &lt;code&gt;RET&lt;/code&gt; on shows the results of each command.&lt;/p&gt;
&lt;h2 id=&#34;caveats&#34;&gt;Caveats&lt;/h2&gt;
&lt;p&gt;Before proceeding further, here are some caveats to be aware of.&lt;/p&gt;
&lt;p&gt;First, the package uses a reverse-engineered API, so all the typical consequences apply, such as sudden irreparable breakages. Although I&amp;rsquo;ve been using it for over a year, so&amp;hellip; maybe not.&lt;/p&gt;
&lt;p&gt;Second, the limit on input size has been mentioned. The obvious workaround is executing commands on a smaller region.&lt;/p&gt;
&lt;p&gt;Third, there have been reports that Reverso dispatches &lt;strong&gt;IP bans&lt;/strong&gt; to particularly enthusiastic users, so be cautious if you&amp;rsquo;re sending lots of automated queries. This is also why I didn&amp;rsquo;t implement running one command for multiple consecutive regions.&lt;/p&gt;
&lt;p&gt;Finally, exercise caution with the content sent to the service. Avoid inadvertently sharing confidential information (like passwords) or anything that could be used against you in other ways. While the service claims to be &lt;a href=&#34;https://www.reverso.net/privacy.aspx?lang=EN&#34;&gt;GDPR-compliant&lt;/a&gt;, we can&amp;rsquo;t actually check that.&lt;/p&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;M-x customize-group reverso&lt;/code&gt; to view the available parameters. Here are a few.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t need all 17 languages, customize the &lt;code&gt;reverso-languages&lt;/code&gt; variable to narrow down the list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;reverso-languages&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;english&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;german&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;russian&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the length of &lt;code&gt;reverso-languages&lt;/code&gt; exceeds &lt;code&gt;reverso-language-completing-read-threshold&lt;/code&gt;, switching a language in transient buffers will invoke &lt;code&gt;completing-read&lt;/code&gt; (minibuffer completion). Otherwise, it will simply switch to the next language available.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;reverso-max-display-lines-in-input&lt;/code&gt; controls the maximum number of lines displayed in the input section of a transient buffer.&lt;/p&gt;
&lt;p&gt;The available faces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;reverso-highlight-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso-error-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso-heading-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso-keyword-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso-definition-face&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;are inherited from the faces of &lt;code&gt;transient.el&lt;/code&gt; and &lt;code&gt;basic-faces&lt;/code&gt; to look nice.&lt;/p&gt;
&lt;h2 id=&#34;elisp-api&#34;&gt;Elisp API&lt;/h2&gt;
&lt;p&gt;In Emacs Lisp, there are four primary functions that interact with the Reverso API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;reverso--translate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso--get-context&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso--get-grammar&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso--get-context&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Refer to the docstrings for more detailed information.&lt;/p&gt;
&lt;p&gt;Each function is asynchronous, and the results are retrieved via a callback.&lt;/p&gt;
&lt;p&gt;As Reverso sometimes modifies its available languages and compatibility matrix, so if you change that, execute &lt;code&gt;reverso-verify-settings&lt;/code&gt; to check for potential errors.&lt;/p&gt;
&lt;h2 id=&#34;alternatives-and-observations&#34;&gt;Alternatives and Observations&lt;/h2&gt;
&lt;p&gt;A widely recognized translation service is &lt;a href=&#34;https://translate.google.com/&#34;&gt;Google Translate&lt;/a&gt;, so of course, there&amp;rsquo;s an &lt;a href=&#34;https://github.com/atykhonov/google-translate&#34;&gt;Emacs client&lt;/a&gt; for it.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/emacs-grammarly&#34;&gt;emacs-grammarly&lt;/a&gt; package series provides the Elisp API for &lt;a href=&#34;https://www.grammarly.com/&#34;&gt;Grammarly&lt;/a&gt; (a grammar checking service) along with multiple frontends. Unlike Reverso, Grammarly has an official API (so you don&amp;rsquo;t risk getting an IP ban), and it allows a much larger input size.&lt;/p&gt;
&lt;p&gt;Additionally, Grammarly is less bothered by Org and Markdown syntax, although it struggles with inline code blocks. It seems to do work generally better than Reverso, but it also generates a lot of false positives. For instance, it finds a lot of issues in &lt;a href=&#34;https://www.economist.com/&#34;&gt;The Economist&lt;/a&gt; articles, which, I think, have beautiful English.&lt;/p&gt;
&lt;p&gt;Another notable grammar-checking solution is &lt;a href=&#34;https://languagetool.org/&#34;&gt;LanguageTool&lt;/a&gt;, which can be &lt;a href=&#34;https://dev.languagetool.org/http-server&#34;&gt;run offline&lt;/a&gt; and used with its &lt;a href=&#34;https://github.com/mhayashi1120/Emacs-langtool&#34;&gt;Emacs package&lt;/a&gt;. This tool offers the advantage of unlimited usage and doesn&amp;rsquo;t transmit your data to a third-party server you can&amp;rsquo;t control. But it still doesn&amp;rsquo;t like markup syntaxes.&lt;/p&gt;
&lt;p&gt;Also, I&amp;rsquo;ve been pretty happy with &lt;a href=&#34;https://github.com/valentjn/ltex-ls&#34;&gt;LTeX LS&lt;/a&gt;, which is a LanguageTool-based language server explicitly designed to support markup formats like Org, Markdown, LaTeX, among others.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://www.npmjs.com/package/reverso-api&#34;&gt;reverso-api&lt;/a&gt; npm package implements the same commands in JavaScript. It also provided invaluable information for creating this package.&lt;/p&gt;
</content>
</item>
<item>
<title>elfeed-sync</title>
<link>https://sqrtminusone.xyz/packages/elfeed-sync/</link>
<pubDate>Sun, 29 May 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/elfeed-sync/</guid>
<content type="html">
&lt;p&gt;Sync read/marked status of entries between &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt; and &lt;a href=&#34;https://tt-rss.org/&#34;&gt;tt-rss&lt;/a&gt;. Supports &lt;a href=&#34;https://github.com/SqrtMinusOne/elfeed-summary&#34;&gt;elfeed-summary&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;DISCLAIMER: It&amp;rsquo;s still an alpha version of the package, so you may want to backup your elfeed index and tt-rss database.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/elfeed-sync-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The project consists of the tt-rss plugin and the Emacs package.&lt;/p&gt;
&lt;p&gt;If you are using the &lt;a href=&#34;https://git.tt-rss.org/fox/ttrss-docker-compose.git/tree/README.md&#34;&gt;tt-rss docker&lt;/a&gt; setup, the steps are as follows. Change them accordingly if you are not.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Mount the &lt;code&gt;/var/www/html&lt;/code&gt; directory from the container somewhere to the filesystem as described &lt;a href=&#34;https://git.tt-rss.org/fox/ttrss-docker-compose.wiki.git/tree/Home.md#how-do-i-use-dynamic-image-for-development&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Put the repository to the &lt;code&gt;tt-rss/plugins.local/elfeed_sync&lt;/code&gt; folder:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ./html/tt-rss/plugins.local/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/SqrtMinusOne/elfeed-sync.git elfeed_sync
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add &lt;code&gt;elfeed_sync&lt;/code&gt; to the &lt;code&gt;TTRSS_PLUGINS&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-dotenv&#34; data-lang=&#34;dotenv&#34;&gt;TTRSS_PLUGINS=auth_internal, auth_remote, nginx_xaccel, elfeed_sync
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Allow larger request body sizes in nginx. Add the following to the &lt;code&gt;server&lt;/code&gt; directive:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;client_max_body_size 10M;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For me, the sync payload is around 3M.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Increase the read timeout in nginx. Add the following to the php location directive:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;fastcgi_read_timeout 600;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Syncing the entries is usually pretty fast, but the first feed sync takes a while.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then restart tt-rss. Check if the plugin appears in the Preferences &amp;gt; Plugins section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable &amp;ldquo;Allows accessing this account through the API&amp;rdquo; in the Preferences &amp;gt; Preferences. You also may want to disable &amp;ldquo;Purge unread articles&amp;rdquo;, because elfeed doesn&amp;rsquo;t do that.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Install the Emacs package however you normally install packages, I prefer use-package and straight.el. Make sure to enable &lt;code&gt;elfeed-sync-mode&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-sync&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne/elfeed-sync&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-sync-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then set up the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-tt-rss-instance&lt;/code&gt; - point that to your tt-rss instance, e.g.
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://example.com/tt-rss
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;(No trailing slash)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-tt-rss-login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-tt-rss-password&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-unread-tag&lt;/code&gt; - elfeed tag to map to read status in tt-rss. &lt;code&gt;unread&lt;/code&gt; by default.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-marked-tag&lt;/code&gt; - elfeed tag to map to marked status in tt-rss. &lt;code&gt;later&lt;/code&gt; by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;h3 id=&#34;syncing-the-feed-list&#34;&gt;Syncing the feed list&lt;/h3&gt;
&lt;p&gt;The first thing you probably want to do is to sync the feed list.&lt;/p&gt;
&lt;p&gt;It makes little sense to sync tt-rss feeds to elfeed, because people often use projects like &lt;a href=&#34;https://github.com/remyhonig/elfeed-org&#34;&gt;elfeed-org&lt;/a&gt;. But it&amp;rsquo;s possible to sync elfeed feeds to tt-rss.&lt;/p&gt;
&lt;p&gt;The function &lt;code&gt;M-x elfeed-sync-feeds&lt;/code&gt; does exactly that. If you have &lt;a href=&#34;https://github.com/SqrtMinusOne/elfeed-summary&#34;&gt;elfeed-summary&lt;/a&gt; installed and tt-rss categories enabled, the function will recreate the elfeed-summary tree in tt-rss.&lt;/p&gt;
&lt;p&gt;The first run of the function takes a while because tt-rss has to fetch the feed at the moment of the first subscription. Which is why increasing the timeout may be necessary.&lt;/p&gt;
&lt;p&gt;However, running the function multiple times until it succeeds should also work.&lt;/p&gt;
&lt;h3 id=&#34;syncing-the-entry-list&#34;&gt;Syncing the entry list&lt;/h3&gt;
&lt;p&gt;To sync the entry list, run &lt;code&gt;M-x elfeed-sync&lt;/code&gt;. The sync usually takes a couple of seconds.&lt;/p&gt;
&lt;p&gt;The sync finishes at the &amp;ldquo;Sync complete!&amp;rdquo; message. Check the &lt;code&gt;*elfeed-log*&lt;/code&gt; buffer for statistics.&lt;/p&gt;
&lt;p&gt;Occasionally, some entries do not match. Here are the possible cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Entry exists in the elfeed database, but not in tt-rss.
Run &lt;code&gt;M-x elfeed-sync-search-missing&lt;/code&gt; to display such entries.&lt;/li&gt;
&lt;li&gt;Entry exists in the tt-rss database, but not in elfeed:
&lt;ul&gt;
&lt;li&gt;Entry appeared in the feed after the last &lt;code&gt;elfeed-update&lt;/code&gt;.
Run &lt;code&gt;M-x elfeed-update&lt;/code&gt; and then &lt;code&gt;M-x elfeed-sync&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Entry appeared and disappeared in the feed after the last &lt;code&gt;elfeed-update&lt;/code&gt;.
Such an entry will never get to the elfeed database. If you want to, run &lt;code&gt;M-x elfeed-sync&lt;/code&gt; and then &lt;code&gt;M-x elfeed-sync-read-ttrss-missing&lt;/code&gt; to mark all such entries as read.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Entry appeared in the feed before &lt;code&gt;elfeed-sync-look-back&lt;/code&gt;.
Such an entry will never be matched. This is an inconvenience if you have just set up tt-rss, it fetched old entries from the feeds and such entries remain permanently unread because they are untouched by the &lt;code&gt;M-x elfeed-sync&lt;/code&gt;.
To mark such entries as read, run &lt;code&gt;M-x elfeed-sync-read-ttrss-old&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;implementation-details&#34;&gt;Implementation details&lt;/h2&gt;
&lt;p&gt;The heavy-lifting is done on the elisp side because I ran into strange performance issues with associative arrays in PHP.&lt;/p&gt;
&lt;p&gt;Check the &lt;code&gt;elfeed-sync--do-sync&lt;/code&gt; function for the description of the synchronization algorithm. The tl;dr is to download all entries from tt-rss and match each entry against the elfeed database. In the case of discrepancy update whichever entry has the lower priority.&lt;/p&gt;
</content>
</item>
<item>
<title>Extending elfeed with PDF viewer and subtitles fetcher</title>
<link>https://sqrtminusone.xyz/posts/2022-05-09-pdf/</link>
<pubDate>Tue, 10 May 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2022-05-09-pdf/</guid>
<content type="html">
&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt; is one of the most popular Emacs packages, and it&amp;rsquo;s also one in which I ended up investing a lot of effort. I wrote about the &lt;a href=&#34;https://sqrtminusone.xyz/posts/2021-09-07-emms/&#34;&gt;EMMS integration&lt;/a&gt; and even made a &lt;a href=&#34;https://github.com/SqrtMinusOne/elfeed-summary&#34;&gt;custom frontpage&lt;/a&gt; to my liking.&lt;/p&gt;
&lt;p&gt;However, sites frequently limit the amount of information shipped in the RSS feed. Oftentimes the entry doesn&amp;rsquo;t include the entire content (of which, by the way, this blog was guilty).&lt;/p&gt;
&lt;p&gt;Also, there&amp;rsquo;s non-textual content, of which in this post I consider YouTube subscriptions. It&amp;rsquo;s possible to watch YouTube from elfeed, for instance with the aforementioned EMMS integration, but we can do more.&lt;/p&gt;
&lt;p&gt;So, the plan for the post is to discuss:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;using &lt;a href=&#34;https://github.com/eafer/rdrview&#34;&gt;rdrview&lt;/a&gt; to extend elfeed articles;&lt;/li&gt;
&lt;li&gt;using &lt;a href=&#34;https://pandoc.org&#34;&gt;pandoc&lt;/a&gt; and LaTeX to convert articles to PDFs;&lt;/li&gt;
&lt;li&gt;using &lt;a href=&#34;https://github.com/jdepoix/youtube-transcript-api&#34;&gt;youtube-transcript-api&lt;/a&gt; to download YouTube subtitles and &lt;a href=&#34;https://github.com/sachac/subed&#34;&gt;subed&lt;/a&gt; to control the MPV playback;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, heads up! You&amp;rsquo;ll need lexical binding enabled for the code blocks. The easiest way to accomplish this is to add the following to the first line of &lt;code&gt;init.el&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;;; -*- lexical-binding: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;rdrview&#34;&gt;rdrview&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/eafer/rdrview&#34;&gt;rdrview&lt;/a&gt; is a command-line tool to strip webpages from clutter, extracting only parts related to the actual content. It&amp;rsquo;s a standalone port of the corresponding feature of Firefox, called &lt;a href=&#34;https://support.mozilla.org/en-US/kb/firefox-reader-view-clutter-free-web-pages&#34;&gt;Reader View&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It seems like the tool &lt;a href=&#34;https://repology.org/project/rdrview/versions&#34;&gt;isn&amp;rsquo;t available&lt;/a&gt; in a whole lot of package repositories, but it&amp;rsquo;s pretty easy to compile. I&amp;rsquo;ve put together a &lt;a href=&#34;https://github.com/SqrtMinusOne/channel-q/blob/master/rdrview.scm&#34;&gt;Guix definition&lt;/a&gt;, which &lt;em&gt;one day&lt;/em&gt; I&amp;rsquo;ll submit to upstream.&lt;/p&gt;
&lt;h3 id=&#34;integrating-rdrview-with-emacs&#34;&gt;Integrating rdrview with Emacs&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s start by integrating &lt;code&gt;rdrview&lt;/code&gt; with Emacs. In the general case, we want to fetch both metadata and the actual content from the page.&lt;/p&gt;
&lt;p&gt;However, the interface of &lt;code&gt;rdrview&lt;/code&gt; is a bit awkward in this part, so we have the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;call &lt;code&gt;rdrview&lt;/code&gt; two times: with &lt;code&gt;-M&lt;/code&gt; flag to fetch the metadata, and without the flag to fetch the HTML;&lt;/li&gt;
&lt;li&gt;call &lt;code&gt;rdrview&lt;/code&gt; with &lt;code&gt;-T&lt;/code&gt; flag to append the metadata to the resulting HTML.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve decided to go with the second option. Here is a function that calls rdrview with the required flags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-get&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;callback&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get the rdrview representation of URL.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;Call CALLBACK with the output.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;generate-new-buffer&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rdrview&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rdrview&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rdrview&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-T&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;title,sitename,body&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-H&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;set-process-sentinel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;_msg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-exit-status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exit&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;progn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;callback&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-string&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;kill-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))) )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exit&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;signal&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;err&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-string&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;kill-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Error in rdrview: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;err&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function calls &lt;code&gt;callback&lt;/code&gt; with the output of &lt;code&gt;rdrview&lt;/code&gt;. This usually doesn&amp;rsquo;t take long, but it&amp;rsquo;s still nice to avoid freezing Emacs that way.&lt;/p&gt;
&lt;p&gt;Now we have to parse the output. The &lt;code&gt;-T&lt;/code&gt; flag puts the title in the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag, the site name site in the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; tag, and the content in a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;. What&amp;rsquo;s more, headers of the content are often shifted, e.g. the top-level header may well end up being and &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;, which does not look great in LaTeX.&lt;/p&gt;
&lt;p&gt;With that said, here&amp;rsquo;s a function that does the required changes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-parse&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dom-string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;dom&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-temp-buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dom-string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;libxml-parse-html-region&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;point-min&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;point-max&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;sitename&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dom-children&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dom-by-id&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dom&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;readability-page-1&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;listp&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dom-text&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;sitename&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dom-text&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;div&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;child&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dom-by-tag&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dom-search&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;listp&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h2&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h3&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h4&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h3&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h5&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h4&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h6&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setf&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;h5&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;sitename&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;sitename&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;with-temp-buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dom-print&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-string&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;using-rdrview-from-elfeed&#34;&gt;Using rdrview from elfeed&lt;/h3&gt;
&lt;p&gt;Because I didn&amp;rsquo;t find a smart way to advise the desired behavior into elfeed, here&amp;rsquo;s a modification of the &lt;code&gt;elfeed-show-refresh--mail-style&lt;/code&gt; function with two changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it uses &lt;code&gt;rdrview&lt;/code&gt; to fetch the HTML;&lt;/li&gt;
&lt;li&gt;it saves the resulting HTML into a buffer-local variable (we&amp;rsquo;ll need that later).&lt;/li&gt;
&lt;/ul&gt;
&lt;!--listend--&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defvar-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-show-rdrview-html&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-elfeed-show&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;No elfeed entry in this buffer!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-link&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;result&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-parse&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;inhibit-read-only&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-title&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;date&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seconds-to-time&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-date&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-meta&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:authors&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;link&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-link&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tags&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-tags&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tagsstr&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapconcat&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tags&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;nicedate&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%a, %e %b %Y %T %Z&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;date&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;feed&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-feed&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;feed-title&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-feed-title&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;feed&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;base&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;feed&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-compute-base&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-feed-url&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;feed&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;erase-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Title: %s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-subject&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry-author&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;formatted&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed--show-format-author&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;author&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Author: %s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;formatted&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-to&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Date: %s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nicedate&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-other&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Feed: %s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;feed-title&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-other&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tags&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Tags: %s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tagsstr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-other&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Link: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-insert-link&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;link&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;enclosure&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-enclosures&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Enclosure: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;message-header-name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-insert-link&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;enclosure&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-insert-html&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;base&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;propertize&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(empty)\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;face&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;italic&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-show-rdrview-html&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;point-min&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That way, calling &lt;code&gt;M-x my/rdrview-elfeed-show&lt;/code&gt; replaces the original content with one from &lt;code&gt;rdrview&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;how-well-does-it-work&#34;&gt;How well does it work?&lt;/h3&gt;
&lt;p&gt;Rather ironically, it works well with sites that already ship with proper RSS, like &lt;a href=&#34;https://protesilaos.com/&#34;&gt;Protesilaos Stavrou&amp;rsquo;s&lt;/a&gt; or &lt;a href=&#34;https://karthinks.com/software/simple-folding-with-hideshow/&#34;&gt;Karthik Chikmagalur&amp;rsquo;s&lt;/a&gt; blogs or &lt;a href=&#34;https://www.theatlantic.com/world/&#34;&gt;The Atlantic&lt;/a&gt; magazine.&lt;/p&gt;
&lt;p&gt;Of my other subscriptions, it does a pretty good job with &lt;a href=&#34;https://www.theverge.com/&#34;&gt;The Verge&lt;/a&gt;, which by default sends entries truncated by the words &amp;ldquo;Read the full article&amp;rdquo;. For &lt;a href=&#34;https://arstechnica.com/&#34;&gt;Ars Technica&lt;/a&gt;, it works only if the story is not large enough, otherwise the site returns its HTML-based pagination interface.&lt;/p&gt;
&lt;p&gt;For paywalled sites such as &lt;a href=&#34;https://www.nytimes.com/&#34;&gt;New York Times&lt;/a&gt; or &lt;a href=&#34;https://www.economist.com/&#34;&gt;The Economist&lt;/a&gt;, this usually doesn&amp;rsquo;t work (by the way, what&amp;rsquo;s the problem with providing individual RSS feeds for subscribers?). If you need this kind of thing, I&amp;rsquo;d suggest using the &lt;a href=&#34;https://github.com/RSS-Bridge/rss-bridge&#34;&gt;RSS-Bridge&lt;/a&gt; project. And if something is not available, contributing business logic there definitely makes more sense than implementing workarounds in Emacs Lisp.&lt;/p&gt;
&lt;h2 id=&#34;latex-and-pandoc&#34;&gt;LaTeX and pandoc&lt;/h2&gt;
&lt;p&gt;However, I also find that I&amp;rsquo;m not really a fan of reading articles from Emacs. Somehow what works for program code doesn&amp;rsquo;t work that well for natural text. When I have to, I usually switch the Emacs theme to a light one.&lt;/p&gt;
&lt;p&gt;But the best solution I&amp;rsquo;ve found so far is to render the required articles as PDFs. I may even print out some large articles I want to read.&lt;/p&gt;
&lt;h3 id=&#34;template&#34;&gt;Template&lt;/h3&gt;
&lt;p&gt;So first, we need a LaTeX template. Pandoc already ships with one, but I don&amp;rsquo;t like it too much, so I&amp;rsquo;ve put up a template from my LaTeX styles, targeting my preferred XeLaTeX engine.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll add the code here for completeness&amp;rsquo; sake, but if you use LaTeX, you&amp;rsquo;ll probably be better off using your own setup. Be sure to define the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main-lang&lt;/code&gt; and &lt;code&gt;other-lang&lt;/code&gt; for polyglossia (or remove them if you have only one language)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;subtitle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;author&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;date&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!--listend--&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\documentclass&lt;/span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;[a4paper, 12pt]&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;extarticle&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Math ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;amsmath&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Math stuff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;amssymb&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;mathspec&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== List ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;enumitem&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;etoolbox&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlist&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;nosep, topsep=-10pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Remove sep-s beetween list elements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlist&lt;/span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;[enumerate]&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;label*=&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\arabic*&lt;/span&gt;.&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlist&lt;/span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;[enumerate,1]&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;after=&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\vspace&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;0.5&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\baselineskip&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlist&lt;/span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;[itemize,1]&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;after=&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\vspace&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;0.5&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\baselineskip&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\AtBeginEnvironment&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;itemize&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlist&lt;/span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;[enumerate]&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;label=&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\arabic*&lt;/span&gt;.&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlist&lt;/span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;[enumerate,1]&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;after=&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\vspace&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;0&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\baselineskip&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\providecommand&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\tightlist&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlength&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\itemsep&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;0pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlength&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\parskip&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;0pt&lt;span style=&#34;color:#008000&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Link ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;xcolor&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;hyperref&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Links
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\hypersetup&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; colorlinks=true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; citecolor=blue,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; filecolor=blue,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; linkcolor=blue,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; urlcolor=blue,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Linebreaks for urls
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\expandafter\def\expandafter\UrlBreaks\expandafter&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\UrlBreaks&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% save the current one
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\do\a\do\b\do\c\do\d\do\e\do\f\do\g\do\h\do\i\do\j&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\do\k\do\l\do\m\do\n\do\o\do\p\do\q\do\r\do\s\do\t&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\do\u\do\v\do\w\do\x\do\y\do\z\do\A\do\B\do\C\do\D&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\do\E\do\F\do\G\do\H\do\I\do\J\do\K\do\L\do\M\do\N&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\do\O\do\P\do\Q\do\R\do\S\do\T\do\U\do\V\do\W\do\X&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\do\Y\do\Z&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Table ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;array&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;booktabs&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;longtable&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;multirow&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;calc&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Images ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;graphicx&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Pictures
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\makeatletter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\def\maxwidth&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\ifdim\Gin&lt;/span&gt;@nat@width&amp;gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\linewidth\linewidth\else\Gin&lt;/span&gt;@nat@width&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\fi&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\def\maxheight&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\ifdim\Gin&lt;/span&gt;@nat@height&amp;gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\textheight\textheight\else\Gin&lt;/span&gt;@nat@height&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\fi&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\makeatother&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Scale images if necessary, so that they will not overflow the page
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% margins by default, and it is still possible to overwrite the defaults
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% using explicit options in \includegraphics[width, height, ...]{}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setkeys&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;Gin&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;width=&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\maxwidth&lt;/span&gt;,height=&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\maxheight&lt;/span&gt;,keepaspectratio&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Set default figure placement to htbp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\makeatletter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\def\fps&lt;/span&gt;@figure&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;htbp&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\makeatother&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\newcommand&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\noimage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlength&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\fboxsep&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;-&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\fboxrule&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\fbox&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\phantom&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\rule&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;150pt&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;100pt&lt;span style=&#34;color:#008000&#34;&gt;}}}&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Framed box
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\makeatletter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\patchcmd&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\Gin&lt;/span&gt;@ii&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\begingroup&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% &amp;lt;search&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\begingroup\renewcommand&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\@&lt;/span&gt;latex@error&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;[2]&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\noimage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}}&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% &amp;lt;replace&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% &amp;lt;success&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% &amp;lt;failure&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\makeatother&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Misc ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;fancyvrb&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;csquotes&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;[normalem]&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;ulem&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Quotes and verses style
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\AtBeginEnvironment&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;quote&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\singlespacing&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\AtBeginEnvironment&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;verse&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\singlespacing&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Text spacing ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;setspace&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% String spacing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\onehalfspacing&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;indentfirst&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlength\parindent&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;0cm&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlength\parskip&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;6pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Page layout ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;[ &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% Margins
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;left=2cm,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;right=2cm,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;top=2cm,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bottom=2cm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;geometry&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Document sectioning ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;titlesec&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titleformat*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\section&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\bfseries&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titleformat*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\subsection&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\bfseries&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titleformat*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\subsubsection&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\bfseries&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titleformat*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\paragraph&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\bfseries&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titleformat*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\subparagraph&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\bfseries\itshape&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% chktex 6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titlespacing*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\section&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;0cm&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;12pt&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;3pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titlespacing*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\subsection&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;0cm&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;12pt&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;3pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titlespacing*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\subsubsection&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;0cm&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;12pt&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;0pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titlespacing*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\paragraph&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;0pt&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;6pt&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;6pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\titlespacing*&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\subparagraph&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;0pt&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;6pt&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;3pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\makeatletter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\providecommand&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\subtitle&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;[1]&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\apptocmd&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\@&lt;/span&gt;title&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\par&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\large&lt;/span&gt; #1 &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\par&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}}{}{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\makeatother&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Pandoc =======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;highlighting&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;macros&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;highlighting&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;macros&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;endif&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;% ====== Language ======
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;polyglossia&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setdefaultlanguage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;lang&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setotherlanguage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;other&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;lang&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\defaultfontfeatures&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;Ligatures=&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;TeX&lt;span style=&#34;color:#008000&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setmainfont&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;Open Sans&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\newfontfamily\cyrillicfont&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;Open Sans&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setmonofont&lt;/span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;[Scale=0.9]&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;DejaVu Sans Mono&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\newfontfamily&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\cyrillicfonttt&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;DejaVu Sans Mono&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;[Scale=0.8]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;bidi&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;microtype&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\setlength&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\emergencystretch&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}{&lt;/span&gt;3pt&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;title&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\title&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;title&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;endif&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;subtitle&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\subtitle&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;subtitle&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;endif&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;author&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\author&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;author&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;author&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;sep&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\and&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;endfor&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;endif&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;date&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\date&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;date&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;endif&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\begin&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;document&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\maketitle&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;body&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;\end&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;{&lt;/span&gt;document&lt;span style=&#34;color:#008000&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;invoking-pandoc&#34;&gt;Invoking pandoc&lt;/h3&gt;
&lt;p&gt;Now that we have the template, let&amp;rsquo;s save it somewhere and store the path to a variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-template&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;user-emacs-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rdrview.tex&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And let&amp;rsquo;s invoke pandoc. We need to pass the following flags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--pdf-engine=xelatex&lt;/code&gt;, of course&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--template &amp;lt;path-to-template&amp;gt;&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o &amp;lt;path-to-pdf&amp;gt;&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--variable key=value&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In fact, pandoc is a pretty awesome tool in the sense that it allows for feeding custom variables to rich-language templates.&lt;/p&gt;
&lt;p&gt;So, the rendering function is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;cl-defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-render&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;variables&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;callback&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;overwrite&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Render CONTENT with pandoc.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;TYPE is a file extension as supported by pandoc, for instance,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;html or txt. VARIABLES is an alist that is fed into the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;template. After the rendering is complete successfully, CALLBACK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;is called with the resulting PDF.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;FILE-NAME is a path to the resulting PDF. If nil it&amp;#39;s generated
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;randomly.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;If a file with the given FILE-NAME already exists, the function will
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;invoke CALLBACK straight away without doing the rendering, unless
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;OVERWRITE is non-nil.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/tmp/%d.pdf&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;random&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;100000000&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;temp-file-name&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/tmp/%d.%s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;random&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;100000000&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;variables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;progn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--variable&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;params&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;push&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%s=%s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;params&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;params&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nreverse&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;params&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;overwrite&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-temp-file&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;temp-file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;start-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;pandoc&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;get-buffer-create&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;*Pandoc*&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;pandoc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;temp-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-o&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--pdf-engine=xelatex&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--template&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;params&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;set-process-sentinel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;_msg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-exit-status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exit&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;progn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Done!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exit&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;signal&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Error in pandoc. Check the *Pandoc* buffer&amp;#34;&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;opening-elfeed-entries&#34;&gt;Opening elfeed entries&lt;/h3&gt;
&lt;p&gt;Now we have everything required to open elfeed entries.&lt;/p&gt;
&lt;p&gt;Also, in my case elfeed entries come in two languages, so I have to set &lt;code&gt;main-lang&lt;/code&gt; and &lt;code&gt;other-lang&lt;/code&gt; variables accordingly. Here&amp;rsquo;s the main function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-pdf-dir&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.elfeed/pdf/&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-open-pdf&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;overwrite&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Open the current elfeed ENTRY with a pdf viewer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;If OVERWRITE is non-nil, do the rendering even if the resulting
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;PDF already exists.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-prefix-arg&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;m&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt;)) (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-meta&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:authors&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;feed-title&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-feed-title&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-feed&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tags&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapconcat&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;symbol-name&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-tags&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;date&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%a, %e %b %Y&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seconds-to-time&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-date&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-deref&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-pdf-dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-ref-id&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.pdf&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;main-language&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;english&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-language&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;russian&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;No content!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;subtitle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;seq-empty-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;feed-title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-empty-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;regexp-quote&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;feed-title&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;feed-title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-join&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;authors&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\\\&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;feed-title&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;ru&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-tags&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;main-language&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;russian&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-language&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;english&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-render&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;bound-and-true-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-show-rdrview-html&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-show-rdrview-html&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-content-type&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-title&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;subtitle&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;subtitle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;date&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;date&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;tags&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;tags&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;main-lang&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;main-language&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-lang&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;other-language&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;xdg-open&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;xdg-open&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:file-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:overwrite&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-prefix-arg&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the &lt;code&gt;my/elfeed-show-rdrview-html&lt;/code&gt; variable is bound and true, then the content in this buffer was retrieved via &lt;code&gt;rdrview&lt;/code&gt;, so we&amp;rsquo;ll use that instead of the output of &lt;code&gt;elfeed-deref&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we can open elfeed entries in a PDF viewer, which I find much nicer to read. Given that RSS feeds generally ship with simpler HTML than the regular websites, results usually look awesome:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/images/pdf-prot.png&#34;&gt;
&lt;/figure&gt;
&lt;h3 id=&#34;opening-arbitrary-sites&#34;&gt;Opening arbitrary sites&lt;/h3&gt;
&lt;p&gt;As you may have noticed, we also can display arbitrary web pages with this setup, so let&amp;rsquo;s go ahead and implement that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/get-languages&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;main-lang&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;english&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-lang&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;russian&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.ru&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;main-lang&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;russian&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-lang&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;english&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;main-lang&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-lang&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-open&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;overwrite&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;read-from-minibuffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;URL: &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;bound-and-true-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-link&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;URL is empty&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-prefix-arg&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-parse&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;langs&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/get-languages&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/rdrview-render&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;html&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;title&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;subtitle&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;sitename&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;main-lang&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;langs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-lang&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;langs&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;xdg-open&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;xdg-open&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, this part doesn&amp;rsquo;t work that well, so we can&amp;rsquo;t just uninstall Firefox or Chromium and browse the web from a PDF viewer.&lt;/p&gt;
&lt;p&gt;The most common problem I&amp;rsquo;ve encountered is incorrectly formed pictures, such as &lt;code&gt;.png&lt;/code&gt; files without the boundary info. I&amp;rsquo;m sure you&amp;rsquo;ve also come across this if you ever tried to insert a lot of Internet pictures into a LaTeX document.&lt;/p&gt;
&lt;p&gt;However, sans the pictures issue, for certain sites like Wikipedia this is usable. For instance, here&amp;rsquo;s how the Emacs page looks:
&lt;img src=&#34;https://sqrtminusone.xyz/images/pdf-emacs.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;youtube-transcripts&#34;&gt;YouTube transcripts&lt;/h2&gt;
&lt;h3 id=&#34;getting-subtitles&#34;&gt;Getting subtitles&lt;/h3&gt;
&lt;p&gt;Finally, let&amp;rsquo;s get to transcripts.&lt;/p&gt;
&lt;p&gt;In principle, the YouTube API allows for downloading subtitles, but I&amp;rsquo;ve found &lt;a href=&#34;https://github.com/jdepoix/youtube-transcript-api&#34;&gt;this awesome Python script&lt;/a&gt; which does the same. You can install it from &lt;code&gt;pip&lt;/code&gt;, or here&amp;rsquo;s mine &lt;a href=&#34;https://github.com/SqrtMinusOne/channel-q/blob/master/youtube-transcript-api.scm&#34;&gt;Guix definition&lt;/a&gt; once again.&lt;/p&gt;
&lt;p&gt;Much like the previous cases, we need to invoke the program and save the output. The &lt;a href=&#34;https://en.wikipedia.org/wiki/WebVTT&#34;&gt;WebVTT&lt;/a&gt; format will work well enough for our purposes. Here comes the function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;cl-defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/youtube-subtitles-get&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;video-id&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;overwrite&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get subtitles for VIDEO-ID in WebVTT format.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;Call CALLBACK when done.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;FILE-NAME is a path to the resulting WebVTT file. If nil it&amp;#39;s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;generated randomly.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;If a file with the given FILE-NAME already exists, the function will
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;invoke CALLBACK straight away without doing the rendering, unless
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;OVERWRITE is non-nil.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/tmp/%d.vtt&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;random&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;100000000&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;overwrite&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;generate-new-buffer&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;youtube-transcripts&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;youtube_transcript_api&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;youtube_transcript_api&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;video-id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--languages&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;en&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;ru&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;de&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--format&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;webvtt&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;set-process-sentinel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;_msg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-exit-status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exit&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;progn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;buffer-file-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;save-buffer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;kill-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exit&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;signal&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;err&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-string&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;kill-buffer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;process-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;process&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Error in youtube_transcript_api: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;err&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;proc&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;elfeed-and-subed&#34;&gt;elfeed and subed&lt;/h3&gt;
&lt;p&gt;Now that we have a standalone function, let&amp;rsquo;s invoke it with the current &lt;code&gt;elfeed-show-entry&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-srt-dir&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.elfeed/srt/&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-youtube-subtitles&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Get subtitles for the current elfeed ENTRY.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;Works only in the entry is a YouTube video.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;If ARG is non-nil, re-fetch the subtitles regardless of whether
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;they were fetched before.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-prefix-arg&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;video-id&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cadr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;assoc&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;watch?v&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url-parse-query-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url-generic-parse-url&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-link&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;video-id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Can&amp;#39;t get video ID from the entry&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/youtube-subtitles-get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;video-id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;find-file-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;point-min&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:file-name&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-srt-dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-ref-id&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-content&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.vtt&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:overwrite&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;arg&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That opens up a &lt;code&gt;.vtt&lt;/code&gt; buffer with the subtitles for the current video, which means now we can use the functionality of Sacha Chua&amp;rsquo;s awesome package called &lt;a href=&#34;https://github.com/sachac/subed&#34;&gt;subed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This package, besides syntax highlighting, allows for controlling the MPV playback, for instance by moving the cursor in the subtitles buffer. Using that requires having the URL of the video in this buffer, which necessitates the line with &lt;code&gt;setq-local&lt;/code&gt; in the previous function.&lt;/p&gt;
&lt;p&gt;Also, the package launches its own instance of MPV to control it via JSON-IPC, so there seems to be no easy way to integrate it with EMMS. But at least I can reuse the &lt;code&gt;emms-player-mpv-parameters&lt;/code&gt; variable, the method of setting which I&amp;rsquo;ve discussed in a &lt;a href=&#34;https://sqrtminusone.xyz/posts/2021-09-07-emms/&#34;&gt;previous blog post&lt;/a&gt;. The function is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/subed-elfeed&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Open the video file from elfeed ENTRY in MPV.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;This has to be launched from inside the subtitles buffer, opened
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;by the &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/elfeed-youtube-subtitles&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;No entry!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;derived-mode-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;subed-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;user-error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Not subed mode!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;subed-mpv-arguments&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-uniq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;subed-mpv-arguments&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-player-mpv-parameters&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;subed-mpv-video-file&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-link&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;subed-mpv--play&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;subed-mpv-video-file&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s how it looks when used (the video on the screenshot is &lt;a href=&#34;https://www.youtube.com/watch?v=qjAIXCmhCQQ&#34;&gt;this System Crafters&amp;rsquo; stream&lt;/a&gt;):
&lt;img src=&#34;https://sqrtminusone.xyz/images/pdf-subed.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Keep in mind that this function has to be launched inside the buffer opened by the &lt;code&gt;my/elfeed-youtube-subtitles&lt;/code&gt; function.&lt;/p&gt;
</content>
</item>
<item>
<title>avy-dired</title>
<link>https://sqrtminusone.xyz/packages/avy-dired/</link>
<pubDate>Fri, 01 Apr 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/avy-dired/</guid>
<content type="html">
&lt;p&gt;Doing some experimentation with avy &amp;amp; dired. Still somewhat flaky.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/avy-dired-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The only available command is &lt;code&gt;M-x avy-dired-goto-line&lt;/code&gt;. Use &lt;code&gt;K&lt;/code&gt; and &lt;code&gt;J&lt;/code&gt; to scroll up and down while in the avy state, &lt;code&gt;C-g&lt;/code&gt; or &lt;code&gt;q&lt;/code&gt; to quit.&lt;/p&gt;
</content>
</item>
<item>
<title>elfeed-summary</title>
<link>https://sqrtminusone.xyz/packages/elfeed-summary/</link>
<pubDate>Sat, 26 Mar 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/elfeed-summary/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/elfeed-summary&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/elfeed-summary-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;The package provides a tree-based feed summary interface for &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt;. The tree can include individual feeds, &lt;a href=&#34;https://github.com/skeeto/elfeed#filter-syntax&#34;&gt;searches&lt;/a&gt;, and groups. It mainly serves as an easier &amp;ldquo;jumping point&amp;rdquo; for elfeed, so to make querying a subset of the elfeed database one action away.&lt;/p&gt;
&lt;p&gt;Inspired by &lt;a href=&#34;https://github.com/newsboat/newsboat&#34;&gt;newsboat&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/elfeed-summary-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA, so install it however you normally install packages. My preferred way is &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, you have to have &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt; configured.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Running &lt;code&gt;M-x elfeed-summary&lt;/code&gt; opens up the summary buffer, as shown on the screenshot.&lt;/p&gt;
&lt;p&gt;The tree consists of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;feeds;&lt;/li&gt;
&lt;li&gt;searches;&lt;/li&gt;
&lt;li&gt;groups, that can include other groups, feeds, and searches.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Groups can also be generated automatically.&lt;/p&gt;
&lt;p&gt;Available keybindings in the summary mode:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Keybinding&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary--action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open thing under the cursor (a feed, search, or a group). If there is at least one unread item, it will show only unread items.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;M-RET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary--action-show-read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open thing under the cursor, but always include read items&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&amp;hellip;&lt;/td&gt;
&lt;td&gt;Quit the summary buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary--refresh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Refresh the summary buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary-update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run update for elfeed feeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary-toggle-only-unread&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle showing only unread entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;U&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary--action-mark-read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark everything in the entry under the cursor as read&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The standard keybindings from &lt;a href=&#34;https://magit.vc/manual/magit.html#Sections&#34;&gt;magit-section&lt;/a&gt; are also available, for instance &lt;code&gt;TAB&lt;/code&gt; toggles the visibility of the current group. &lt;a href=&#34;https://github.com/emacs-evil/evil&#34;&gt;evil-mode&lt;/a&gt; is also supported.&lt;/p&gt;
&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;
&lt;h3 id=&#34;tree-configuration&#34;&gt;Tree configuration&lt;/h3&gt;
&lt;p&gt;The structure of the tree is determined by the &lt;code&gt;elfeed-summary-settings&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;This is a list of these possible items:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Group &lt;code&gt;(group . &amp;lt;group-params&amp;gt;)&lt;/code&gt;
Groups are used to group elements under collapsible sections.&lt;/li&gt;
&lt;li&gt;Query &lt;code&gt;(query . &amp;lt;query-params&amp;gt;)&lt;/code&gt;
Query extracts a subset of elfeed feeds based on the given criteria. Each found feed will be represented as a line.&lt;/li&gt;
&lt;li&gt;Search &lt;code&gt;(search . &amp;lt;search-params&amp;gt;)&lt;/code&gt;
Elfeed search, as defined by &lt;code&gt;elfeed-search-set-filter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Tags tree &lt;code&gt;(auto-tags . &amp;lt;auto-tags-params&amp;gt;)&lt;/code&gt;
A tree generated automatically from the available tags.&lt;/li&gt;
&lt;li&gt;Tag groups &lt;code&gt;(tag-groups . &amp;lt;tag-group-params&amp;gt;)&lt;/code&gt;
Insert one tag as one group.&lt;/li&gt;
&lt;li&gt;a few special forms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;group-params&amp;gt;&lt;/code&gt; is an alist with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:title&lt;/code&gt; (mandatory)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:elements&lt;/code&gt; (mandatory) - elements of the group. The structure is the same as in the root definition.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:face&lt;/code&gt; - group face. The default face is &lt;code&gt;elfeed-summary-group-face&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:hide&lt;/code&gt; - if non-nil, the group is collapsed by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;query-params&amp;gt;&lt;/code&gt; can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A symbol of a tag.
A feed will be matched if it has that tag.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:all&lt;/code&gt;. Will match anything.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(title . &amp;quot;string&amp;quot;)&lt;/code&gt; or &lt;code&gt;(title . &amp;lt;form&amp;gt;)&lt;/code&gt;
Match feed title with &lt;code&gt;string-match-p&lt;/code&gt;. &amp;lt;form&amp;gt; makes sense if you
want to pass something like &lt;code&gt;rx&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(author . &amp;quot;string&amp;quot;)&lt;/code&gt; or &lt;code&gt;(author . &amp;lt;form&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(url . &amp;quot;string&amp;quot;)&lt;/code&gt; or &lt;code&gt;(url . &amp;lt;form&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(and &amp;lt;q-1&amp;gt; &amp;lt;q-2&amp;gt; ... &amp;lt;q-n&amp;gt;)&lt;/code&gt;
Match if all the conditions 1, 2, &amp;hellip;, n match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(or &amp;lt;q-1&amp;gt; &amp;lt;q-2&amp;gt; ... &amp;lt;q-n&amp;gt;)&lt;/code&gt; or &lt;code&gt;(&amp;lt;q-1&amp;gt; &amp;lt;q-2&amp;gt; ... &amp;lt;q-n&amp;gt;)&lt;/code&gt;
Match if any of the conditions 1, 2, &amp;hellip;, n match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(not &amp;lt;query&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feed tags for the query are determined by the &lt;code&gt;elfeed-feeds&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;Query examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(emacs lisp)&lt;/code&gt;
Return all feeds that have either &amp;ldquo;emacs&amp;rdquo; or &amp;ldquo;lisp&amp;rdquo; tags.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(and emacs lisp)&lt;/code&gt;
Return all feeds that have both &amp;ldquo;emacs&amp;rdquo; and &amp;ldquo;lisp&amp;rdquo; tags.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(and (title . &amp;quot;Emacs&amp;quot;) (not planets))&lt;/code&gt;
Return all feeds that have &amp;ldquo;Emacs&amp;rdquo; in their title and don&amp;rsquo;t have
the &amp;ldquo;planets&amp;rdquo; tag.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;search-params&amp;gt;&lt;/code&gt; is an alist with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:filter&lt;/code&gt; (mandatory) filter string, as defined by
&lt;code&gt;elfeed-search-set-filter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:title&lt;/code&gt; (mandatory) title.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:tags&lt;/code&gt; - list of tags to get the face of the entry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;auto-tags-params&amp;gt;&lt;/code&gt; is an alist with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:max-level&lt;/code&gt; - maximum level of the tree (default 2)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:source&lt;/code&gt; - which feeds to use to build the tree.
Can be &lt;code&gt;:misc&lt;/code&gt; (default) or &lt;code&gt;(query . &amp;lt;query-params&amp;gt;)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:original-order&lt;/code&gt; - do not try to build a more concise tree by
putting the most frequent tags closer to the root of the tree.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:faces&lt;/code&gt; - list of faces for groups.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;tag-group-params&amp;gt;&lt;/code&gt; is an alist with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:source&lt;/code&gt; - which feeds to use to build the tree.
Can be &lt;code&gt;:misc&lt;/code&gt; (default) or &lt;code&gt;(query . &amp;lt;query-params&amp;gt;)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:repeat-feeds&lt;/code&gt; - allow feeds to repeat. Otherwise, each feed is
assigned to group with the least amount of members.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:face&lt;/code&gt; - face for groups.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Available special forms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:misc&lt;/code&gt; - print out feeds, not found by any query above.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also keep in mind that &lt;code&gt;&#39;(key . ((values)))&lt;/code&gt; is the same as &lt;code&gt;&#39;(key (values))&lt;/code&gt;. This helps to shorten the form in many cases.&lt;/p&gt;
&lt;p&gt;Also, this variable is not validated by any means, so wrong values can produce somewhat cryptic errors. Sorry about that.&lt;/p&gt;
&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;Here is an excerpt from my configuration that was used to produce this screenshot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary-settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;GitHub&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne.private.atom&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Guix packages&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;guix_packages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:hide&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Blogs [Software]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;software_blogs&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Blogs [People]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;blogs&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;people&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emacs&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Emacs&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;blogs&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;people&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emacs&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Podcasts&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;podcasts&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Videos&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Music&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;videos&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;music&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Tech&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;videos&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tech&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;History&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;videos&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;history&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Miscellaneous&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Searches&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;search&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:filter&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;@6-months-ago sqrtminusone&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;About me&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;search&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:filter&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;+later&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Check later&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Ungrouped&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:misc&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;automatic-generation-of-groups&#34;&gt;Automatic generation of groups&lt;/h3&gt;
&lt;h4 id=&#34;auto-tags&#34;&gt;&lt;code&gt;auto-tags&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;As described in the &lt;a href=&#34;#tree-configuration-1&#34;&gt;tree configuration&lt;/a&gt; section, there are two ways to avoid defining all the relevant groups manually, &lt;code&gt;auto-tags&lt;/code&gt; and &lt;code&gt;tag-groups&lt;/code&gt;. Both use tags that are defined in &lt;code&gt;elfeed-feeds&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auto-tags&lt;/code&gt; tries to build the most concise tree from these tags. E.g. if we have feeds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed1 tag1 tag2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed2 tag1 tag2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed3 tag1 tag3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed4 tag1 tag3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It will create the following tree:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The tree is truncated by &lt;code&gt;:max-level&lt;/code&gt;, which is 2 by default.&lt;/p&gt;
&lt;p&gt;If tags don&amp;rsquo;t form this kind of hierarchy in &lt;code&gt;elfeed-feeds&lt;/code&gt;, the algorithm will still try to build the most &amp;ldquo;optimal&amp;rdquo; tree, where the most frequent tags are on the top.&lt;/p&gt;
&lt;p&gt;To avoid that you can set &lt;code&gt;(:original-order . t)&lt;/code&gt;, in which case each feed will be placed at the path &lt;code&gt;tag1 tag2 ... tagN feed&lt;/code&gt;, where the order of tags is the same as in &lt;code&gt;elfeed-feeds&lt;/code&gt;. By the way, this allows reproducing the hierarchy of &lt;a href=&#34;https://github.com/remyhonig/elfeed-org&#34;&gt;elfeed-org&lt;/a&gt;, e.g. this structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* tag1 :tag1:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed2 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed3 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* tag3 :tag3:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed4 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed5 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed6 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Will be converted to this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whereas without &lt;code&gt;:original-order&lt;/code&gt; the structure will be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;tag-groups&#34;&gt;&lt;code&gt;tag-groups&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The second option is &lt;code&gt;tag-groups&lt;/code&gt;, which creates a group for each tag.&lt;/p&gt;
&lt;p&gt;By default, each feed is assigned to its less frequent tag. This can be turned off by setting &lt;code&gt;(:repeat-feeds . t)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;E.g., the elfeed-org setup from the section above will be converted to this structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And with &lt;code&gt;:repeat-feeds&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;common-options&#34;&gt;Common options&lt;/h4&gt;
&lt;p&gt;Both &lt;code&gt;auto-tags&lt;/code&gt; and &lt;code&gt;tag-groups&lt;/code&gt; allow setting the &lt;code&gt;:search&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;The default value is &lt;code&gt;(:search . :misc)&lt;/code&gt;, i.e. use feeds that weren&amp;rsquo;t found by other queries.&lt;/p&gt;
&lt;p&gt;Passing &lt;code&gt;(:search . (query . &amp;lt;query-params&amp;gt;))&lt;/code&gt; is another option.&lt;/p&gt;
&lt;h3 id=&#34;faces&#34;&gt;Faces&lt;/h3&gt;
&lt;p&gt;Group faces by default use the &lt;code&gt;elfeed-summary-group-faces&lt;/code&gt; variable, which serves as a list of faces for each level of the tree. Individual group faces can be overridden with the &lt;code&gt;:face&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;Feed faces by default reuse &lt;a href=&#34;https://github.com/skeeto/elfeed#custom-tag-faces&#34;&gt;the existing elfeed mechanism&lt;/a&gt;. The tags for feeds are taken from the &lt;code&gt;elfeed-feeds&lt;/code&gt; variable; if a feed has at least one unread entry, the unread tag is added to the list. This can be overridden by setting the &lt;code&gt;elfeed-summary-feed-face-fn&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;Searches are mostly the same as feeds, but tags for the search are taken from the &lt;code&gt;:tags&lt;/code&gt; attribute. This also can be overridden with &lt;code&gt;elfeed-summary-search-face-fn&lt;/code&gt; variable.&lt;/p&gt;
&lt;h3 id=&#34;opening-elfeed-search-in-other-window&#34;&gt;Opening &lt;code&gt;elfeed-search&lt;/code&gt; in other window&lt;/h3&gt;
&lt;p&gt;If you set:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary-other-window&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then &lt;code&gt;RET&lt;/code&gt; and &lt;code&gt;M-RET&lt;/code&gt; in the &lt;code&gt;elfeed-summary&lt;/code&gt; buffer will open the search buffer in other window.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;elfeed-summary-width&lt;/code&gt; regulates the width of the remaining summary window in this case. It is useful because the data in the search buffer is generally wider than in the summary buffer. The variable can also be set to &lt;code&gt;nil&lt;/code&gt; to disable this behavior.&lt;/p&gt;
&lt;h3 id=&#34;skipping-feeds&#34;&gt;Skipping feeds&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://tt-rss.org/&#34;&gt;tt-rss&lt;/a&gt; has a feature to disable updating a particular feed but keep it in the feed list. I also want that for elfeed.&lt;/p&gt;
&lt;p&gt;To use that, set &lt;code&gt;elfeed-summary-skip-sync-tag&lt;/code&gt; to some value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary-skip-sync-tag&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;skip&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And tag the feeds you want to skip with this tag. Then, running &lt;code&gt;M-x elfeed-summary-update&lt;/code&gt; will skip them. This won&amp;rsquo;t affect &lt;code&gt;M-x elfeed-update&lt;/code&gt; unless you:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-update&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:override&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary-update&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also watch out if you use &lt;a href=&#34;https://github.com/remyhonig/elfeed-org&#34;&gt;elfeed-org&lt;/a&gt; and want to use the &lt;code&gt;ignore&lt;/code&gt; tag, because this package omits feeds with this tag altogether (configurable by &lt;code&gt;rmh-elfeed-org-ignore-tag&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;other-options&#34;&gt;Other options&lt;/h3&gt;
&lt;p&gt;Also take a look at &lt;code&gt;M-x customize-group elfeed-summary&lt;/code&gt; for the rest of available options.&lt;/p&gt;
&lt;h2 id=&#34;ideas-and-alternatives&#34;&gt;Ideas and alternatives&lt;/h2&gt;
&lt;p&gt;The default interface of elfeed is just a list of all entries. Naturally, it gets hard to navigate when there are a lot of sources with varying frequencies of posts.&lt;/p&gt;
&lt;p&gt;Elfeed itself provides one solution, which is using &lt;a href=&#34;https://github.com/skeeto/elfeed#bookmarks&#34;&gt;bookmarks&lt;/a&gt; to save individual &lt;a href=&#34;https://github.com/skeeto/elfeed#filter-syntax&#34;&gt;searches&lt;/a&gt;. This can work, but it can be somewhat cumbersome.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sp1ff/elfeed-score&#34;&gt;elfeed-score&lt;/a&gt; is another solution, which introduces scoring rules for entries. Thus, with proper rules set, the most important entries should be on the top of the list. You can take a look at &lt;a href=&#34;https://www.youtube.com/watch?v=rvWbUGx9U5E&#34;&gt;this video by John Kitchin&lt;/a&gt; to see how this can work.&lt;/p&gt;
&lt;p&gt;However, I mostly had &lt;code&gt;elfeed-score&lt;/code&gt; to group entries to sets with equal scores, and I then processed one such set or the other. This is why I decided this package is a better fit for my workflow.&lt;/p&gt;
&lt;p&gt;Another idea I used often before that is this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-search-filter-source&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Filter elfeed search buffer by the feed under the cursor.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-search-selected&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:ignore-region&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-search-set-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;@6-months-ago &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;+unread &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;?&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;not-newline&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-feed-url&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-feed&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve bound it to &lt;code&gt;o&lt;/code&gt;, so I would open &lt;code&gt;elfeed&lt;/code&gt;, press &lt;code&gt;o&lt;/code&gt;, and only see unread entries from a particular feed. Then I cleaned the filter and switched to the next feed. Once again, a tree with feeds is obviously a better tool for such a workflow.&lt;/p&gt;
&lt;p&gt;The last solution I want to mention is &lt;a href=&#34;https://github.com/manojm321/elfeed-dashboard&#34;&gt;elfeed-dashboard&lt;/a&gt;, although I didn&amp;rsquo;t test this one. It looks similar to this package but seems to require much more fine-tuning, for instance, it doesn&amp;rsquo;t allow to list all the feeds with a certain tag in a group.&lt;/p&gt;
</content>
</item>
<item>
<title>password-store-ivy</title>
<link>https://sqrtminusone.xyz/packages/password-store-ivy/</link>
<pubDate>Sun, 13 Feb 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/password-store-ivy/</guid>
<content type="html">
&lt;p&gt;A &lt;a href=&#34;https://www.passwordstore.org/&#34;&gt;pass&lt;/a&gt; frontend based on &lt;a href=&#34;https://github.com/abo-abo/swiper#ivy&#34;&gt;Ivy&lt;/a&gt;, made primarily to use with &lt;a href=&#34;https://github.com/ch11ng/exwm&#34;&gt;EXWM&lt;/a&gt; and &lt;a href=&#34;https://github.com/tumashu/ivy-posframe&#34;&gt;ivy-posframe&lt;/a&gt;. Types fields from entries.&lt;/p&gt;
&lt;p&gt;Also take a look at Nicolas Petton&amp;rsquo;s &lt;a href=&#34;https://github.com/NicolasPetton/pass&#34;&gt;pass&lt;/a&gt;, &lt;code&gt;password-store-ivy&lt;/code&gt; is designed as complementary to the Nicolas&amp;rsquo; package.&lt;/p&gt;
&lt;p&gt;This package is made with Ivy because I need some fine-tuning like actions and turning off sorting in some completions, and Ivy happens to be the completion system I&amp;rsquo;m using now.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;As the package isnt yet available anywhere but in this repository, you can clone the repository, add it to the load-path and require the package. My preferred way is &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;password-store-ivy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne/password-store-ivy&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This package types stuff with &lt;code&gt;xdotool&lt;/code&gt;, so you need to have that available in your &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Emacs&amp;rsquo; built-in &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/auth/The-Unix-password-store.html&#34;&gt;password store&lt;/a&gt; integration has to be set up.&lt;/p&gt;
&lt;p&gt;The only command is &lt;code&gt;M-x password-store-ivy&lt;/code&gt;, which invokes Ivy to select an entry from the pass database. Available commands in the selection buffer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-a&lt;/code&gt;. Perform autotype&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-p&lt;/code&gt;. Type password&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-u&lt;/code&gt;. Type username&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-U&lt;/code&gt;. Type url&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-f&lt;/code&gt;. Select a field to type&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;There are a few parameters that control delays:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;password-store-ivy-initial-wait&lt;/code&gt; controls the initial delay before starting to type a sequence (in milliseconds)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;password-store-ivy-delay&lt;/code&gt; controls the delay between typing characters (in milliseconds)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is also &lt;code&gt;password-store-ivy-sequences&lt;/code&gt; that determines the sequence of actions &lt;code&gt;password-store-ivy&lt;/code&gt; performs.&lt;/p&gt;
&lt;p&gt;It is an alist with the following required keys (corresponding to the basic actions):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;autotype&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;password&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;username&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;url&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The values are lists of the following elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wait&lt;/code&gt;. Wait for &lt;code&gt;password-store-ivy-initial-wait&lt;/code&gt; milliseconds&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(wait &amp;lt;milliseconds&amp;gt;)&lt;/code&gt;. Wait for &lt;code&gt;&amp;lt;milliseconds&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(key &amp;lt;key&amp;gt;)&lt;/code&gt;. Type &lt;code&gt;&amp;lt;key&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(field &amp;lt;field&amp;gt;)&lt;/code&gt;. Type &lt;code&gt;&amp;lt;field&amp;gt;&lt;/code&gt; of entry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, the starting values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;autotype&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;wait&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Tab&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;secret&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Return&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;password&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;wait&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;secret&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;username&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;wait&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;wait&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In addition to the global override, sequences can be overriden per-entry with a field called &lt;code&gt;sequence-&amp;lt;name&amp;gt;&lt;/code&gt;, where &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; is a key of &lt;code&gt;password-store-ivy-sequences&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, here is an override to press &lt;code&gt;Tab&lt;/code&gt; twice:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;pass&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;username: thexcloud@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;url: &amp;lt;url&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sequence-autotype: (wait (field . &amp;#34;username&amp;#34;) (key . &amp;#34;Tab&amp;#34;) (key . &amp;#34;Tab&amp;#34;) (field . secret) (key . &amp;#34;Return&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</content>
</item>
<item>
<title>A few cases of literate configuration</title>
<link>https://sqrtminusone.xyz/posts/2022-02-12-literate/</link>
<pubDate>Sat, 12 Feb 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2022-02-12-literate/</guid>
<content type="html">
&lt;p&gt;A post that arose from the discussion of literate configuration on the &lt;a href=&#34;https://systemcrafters.net/&#34;&gt;System Crafters&lt;/a&gt; Discord.&lt;/p&gt;
&lt;p&gt;I am using the &lt;a href=&#34;https://leanpub.com/lit-config&#34;&gt;literate configuration&lt;/a&gt; strategy (based on &lt;a href=&#34;https://orgmode.org/&#34;&gt;Emacs&amp;rsquo; Org Mode&lt;/a&gt;) to manage most of my configuration files. A piece of such a configuration can be as simple as an Org file, which is tangled to one or many plain-text configuration files, but it can be more.&lt;/p&gt;
&lt;p&gt;In my opinion, a literate configuration can be more straightforward and concise than a &amp;ldquo;normal&amp;rdquo; one, thanks to Org Mode&amp;rsquo;s capabilities of &lt;a href=&#34;https://orgmode.org/manual/Working-with-Source-Code.html&#34;&gt;working with source code&lt;/a&gt;. So here I present a few examples from my configuration where I think this is the case:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Managing system colors&lt;/li&gt;
&lt;li&gt;Managing manifests for Guix profiles&lt;/li&gt;
&lt;li&gt;Configuring modules in polybar&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope you find something interesting here!&lt;/p&gt;
&lt;h2 id=&#34;colors&#34;&gt;Colors&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s start with system colors.&lt;/p&gt;
&lt;p&gt;My favorite color theme is Palenight (&lt;a href=&#34;https://github.com/JonathanSpeek/palenight-iterm2&#34;&gt;color codes&lt;/a&gt;), and I want to have one source of truth for these colors. Except for Emacs itself, which has &lt;a href=&#34;https://github.com/doomemacs/themes#theme-list&#34;&gt;doom-palenight&lt;/a&gt; (and in which I occasionally switch to &lt;code&gt;doom-one-light&lt;/code&gt;, e.g. when reading a long text), it can be done rather nicely with Org Mode.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s define a table with all the color codes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+tblname: colors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| color | key | value |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|---------------+---------+---------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| black | color0 | #292d3e |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| red | color1 | #f07178 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| green | color2 | #c3e88d |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| yellow | color3 | #ffcb6b |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| blue | color4 | #82aaff |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| magenta | color5 | #c792ea |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| cyan | color6 | #89ddff |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| white | color7 | #d0d0d0 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| light-black | color8 | #434758 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| light-red | color9 | #ff8b92 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| light-green | color10 | #ddffa7 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| light-yellow | color11 | #ffe585 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| light-blue | color12 | #9cc4ff |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| light-magenta | color13 | #e1acff |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| light-cyan | color14 | #a3f7ff |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| light-white | color15 | #ffffff |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| color-fg | | #000000 |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Contents of this table can then be &lt;a href=&#34;https://orgmode.org/manual/Environment-of-a-Code-Block.html&#34;&gt;accessed from a code block&lt;/a&gt;. Let&amp;rsquo;s define one to return the color code based on its name:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: get-color
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src emacs-lisp :var table=colors name=&amp;#34;black&amp;#34; quote=0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(let ((color (seq-some (lambda (e) (and (string= name (car e)) (nth 2 e))) table)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (if (&amp;gt; quote 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (concat &amp;#34;\&amp;#34;&amp;#34; color &amp;#34;\&amp;#34;&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; color))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Evaluating this block of code should return color code, corresponding to &amp;ldquo;black&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;And the best part is that the results of evaluation of one code block can be included to others with &lt;a href=&#34;https://orgmode.org/manual/Noweb-Reference-Syntax.html&#34;&gt;noweb&lt;/a&gt;. For instance, here&amp;rsquo;s my &lt;a href=&#34;https://pwmt.org/projects/zathura/&#34;&gt;zathura&lt;/a&gt; config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src conf-space :noweb yes :tangle .config/zathura/zathurarc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set abort-clear-search false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set guioptions cs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set selection-clipboard clipboard
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set recolor true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map &amp;lt;C-r&amp;gt; set recolor false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map &amp;lt;C-R&amp;gt; set recolor true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set recolor-lightcolor &amp;lt;&amp;lt;get-color(name=&amp;#34;black&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set completion-bg &amp;lt;&amp;lt;get-color(name=&amp;#34;black&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set completion-fg &amp;lt;&amp;lt;get-color(name=&amp;#34;white&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set completion-group-bg &amp;lt;&amp;lt;get-color(name=&amp;#34;light-black&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set completion-group-fg &amp;lt;&amp;lt;get-color(name=&amp;#34;white&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set completion-highlight-bg &amp;lt;&amp;lt;get-color(name=&amp;#34;magenta&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set completion-highlight-fg &amp;lt;&amp;lt;get-color(name=&amp;#34;black&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set inputbar-bg &amp;lt;&amp;lt;get-color(name=&amp;#34;black&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set inputbar-fg &amp;lt;&amp;lt;get-color(name=&amp;#34;light-magenta&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set statusbar-bg &amp;lt;&amp;lt;get-color(name=&amp;#34;black&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set statusbar-fg &amp;lt;&amp;lt;get-color(name=&amp;#34;light-magenta&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set notification-error-bg &amp;lt;&amp;lt;get-color(name=&amp;#34;red&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set notification-error-fg &amp;lt;&amp;lt;get-color(name=&amp;#34;color-fg&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set notification-warning-bg &amp;lt;&amp;lt;get-color(name=&amp;#34;yellow&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set notification-warning-fg &amp;lt;&amp;lt;get-color(name=&amp;#34;color-fg&amp;#34;, quote=1)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running &lt;code&gt;M-x org-babel-expand-src-block&lt;/code&gt; (&lt;code&gt;C-c C-v v&lt;/code&gt;) on this code block will open the code buffer with noweb expressions expanded, for instance the line with &lt;code&gt;set recolor-lightcolor&lt;/code&gt; will look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set recolor-lightcolor &amp;#34;#292d3e&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;M-x org-babel-tangle&lt;/code&gt; (&lt;code&gt;C-c C-v t&lt;/code&gt;) will also produce &lt;code&gt;zathurarc&lt;/code&gt; with the colors set (given that there&amp;rsquo;s &lt;code&gt;:noweb yes&lt;/code&gt; somewhere in the code block configuration).&lt;/p&gt;
&lt;p&gt;One note is that by default running these commands will require the user to confirm evaluation of each code block. To avoid that, you can set &lt;code&gt;org-confirm-babel-evaluate&lt;/code&gt; to &lt;code&gt;nil&lt;/code&gt;, for example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/org-config-files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Emacs.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Desktop.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Console.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Guix.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Mail.org&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;org-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;member&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-file-name&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;my/org-config-files&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-confirm-babel-evaluate&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, to close the loop on colors, let&amp;rsquo;s generate &lt;code&gt;.Xresources&lt;/code&gt; from that table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: get-xresources
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src emacs-lisp :var table=colors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(mapconcat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (lambda (elem)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (concat &amp;#34;*&amp;#34; (nth 1 elem) &amp;#34;: &amp;#34; (nth 2 elem)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (seq-filter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (lambda (elem) (and (nth 1 elem)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (not (string-empty-p (nth 1 elem)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; table)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;\n&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src conf-xdefaults :noweb yes :tangle ~/.Xresources
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&amp;lt;get-xresources()&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*background: &amp;lt;&amp;lt;get-color(name=&amp;#34;black&amp;#34;)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*foreground: &amp;lt;&amp;lt;get-color(name=&amp;#34;white&amp;#34;)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, whenever a program is capable of reading &lt;code&gt;.Xresources&lt;/code&gt;, it will get colors from there, otherwise, it will get colors from noweb expressions in the literate config. Thus, in both cases, the color is set in a single Org Mode table.&lt;/p&gt;
&lt;h2 id=&#34;guix-dependencies&#34;&gt;Guix dependencies&lt;/h2&gt;
&lt;p&gt;Another case I want to cover is &lt;a href=&#34;https://guix.gnu.org/en/cookbook/en/html_node/Advanced-package-management.html#Advanced-package-management&#34;&gt;using profiles in GNU Guix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A &amp;ldquo;profile&amp;rdquo; in Guix is a way to group package installations. For instance, I have a &amp;ldquo;music&amp;rdquo; profile that has software like &lt;a href=&#34;https://www.musicpd.org/&#34;&gt;MPD&lt;/a&gt;, &lt;a href=&#34;https://github.com/ncmpcpp/ncmpcpp&#34;&gt;ncmpcpp&lt;/a&gt; that I&amp;rsquo;m still occasionally using because of its tag editor, etc. Corresponding to that profile, there&amp;rsquo;s a manifest named &lt;code&gt;music.scm&lt;/code&gt; that looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scheme&#34; data-lang=&#34;scheme&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;specifications-&amp;gt;manifest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;flac&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;cuetools&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;shntool&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mpd-mpc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mpd-watcher&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;picard&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;ncmpcpp&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mpd&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I could generate this file with &lt;code&gt;org-babel&lt;/code&gt; as any other, but that is often not so convenient. For example, I have a &lt;a href=&#34;https://github.com/polybar/polybar&#34;&gt;polybar&lt;/a&gt; module that uses &lt;a href=&#34;https://github.com/risacher/sunwait&#34;&gt;sunwait&lt;/a&gt; to show sunset and sunrise times, and ideally, I want to declare &lt;code&gt;sunwait&lt;/code&gt; to be in the &amp;ldquo;desktop-polybar&amp;rdquo; profile in the same section that has the polybar module definition and the bash script.&lt;/p&gt;
&lt;p&gt;So here&amp;rsquo;s an approach I came up with. The relevant section of the config looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** sun
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Category | Guix dependency |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-----------------+-----------------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| desktop-polybar | sunwait |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Prints out the time of sunrise/sunset. Uses [[https://github.com/risacher/sunwait][sunwait]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src bash :tangle ./bin/polybar/sun.sh :noweb yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...script...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src conf-windows :noweb yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...polybar module definition...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;sunwait&lt;/code&gt; is declared in an Org table that looks like that:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Guix dependency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;desktop-polybar&lt;/td&gt;
&lt;td&gt;sunwait&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Such tables are spread through my &lt;code&gt;Desktop.org&lt;/code&gt;, for instance, here is another one for a polybar module that depends on dateutils:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Guix dependency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;desktop-polybar&lt;/td&gt;
&lt;td&gt;dateutils&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Thus I made a function that extracts packages from all such tables from the current Org buffer. The rules are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If a column name matches &lt;code&gt;[G|g]uix.*dep&lt;/code&gt;, its contents are added to the result.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;CATEGORY&lt;/code&gt; is passed, a column with name &lt;code&gt;[C|c]ategory&lt;/code&gt; is used to filter results. That way, one Org file can be used to produce multiple manifests.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;CATEGORY&lt;/code&gt; is not passed, entries with the non-empty category are filtered out&lt;/li&gt;
&lt;li&gt;If there is a &lt;code&gt;[D|d]isabled&lt;/code&gt; column, entries that have a non-empty value in this column are filtered out.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here is the implementation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/extract-guix-dependencies&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;dependencies&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;()))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-table-map-tables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;q&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;q&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;hline&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-table-to-lisp&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dep-name-index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-position&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;substring-no-properties&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;table&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:test&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;[G|g]uix.*dep&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;category-name-index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-position&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;substring-no-properties&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;table&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:test&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.*[C|c]ategory.*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;disabled-name-index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-position&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;substring-no-properties&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;table&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:test&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.*[D|d]isabled.*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dep-name-index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;table&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Category&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Category is not set and not present in the table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category-name-index&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Category is set and present in the table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category-name-index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category-name-index&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Not disabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;disabled-name-index&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-empty-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;disabled-name-index&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;add-to-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring-no-properties&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dep-name-index&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dependencies&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s execute this function in the current buffer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;my/extract-guix-dependencies&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;desktop-polybar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;dateutils&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;sunwait&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As expected, it found both &lt;code&gt;dateutils&lt;/code&gt; and &lt;code&gt;sunwait&lt;/code&gt;. To make it work in the configuration, it is necessary to format the list so that Scheme could read it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/format-guix-dependencies&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapconcat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/extract-guix-dependencies&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;category&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we need an Org snippet such as this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src emacs-lisp :tangle no :var category=&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(my/format-guix-dependencies category)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, creating a manifest for the &lt;code&gt;desktop-polybar&lt;/code&gt; profile is as simple as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src scheme :tangle ~/.config/guix/manifests/desktop-polybar.scm :noweb yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(specifications-&amp;gt;manifest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#39;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;&amp;lt;packages(&amp;#34;desktop-polybar&amp;#34;)&amp;gt;&amp;gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a newline symbol between &amp;ldquo;(&amp;rdquo; and &lt;code&gt;&amp;lt;&amp;lt;packages(&amp;quot;desktop-polybar&amp;quot;)&amp;gt;&amp;gt;&lt;/code&gt; because whenever a noweb expression expands into multiple lines, for each new line noweb duplicates contents between the start of the line and the start of the expression.&lt;/p&gt;
&lt;p&gt;One reason this is so is to support languages where indentation is a part of the syntax, for instance, Python:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;TestClass&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;class&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;contents&lt;span style=&#34;color:#666&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So every line of &lt;code&gt;&amp;lt;&amp;lt;class-contents&amp;gt;&amp;gt;&lt;/code&gt; will be indented appropriately. In our case though, it is a minor inconvenience to be aware of.&lt;/p&gt;
&lt;h2 id=&#34;polybar&#34;&gt;Polybar&lt;/h2&gt;
&lt;p&gt;Now, the most &lt;del&gt;crazy&lt;/del&gt; advanced case I&amp;rsquo;ve come up with so far.&lt;/p&gt;
&lt;p&gt;Basically, here is how my &lt;a href=&#34;https://github.com/polybar/polybar&#34;&gt;polybar&lt;/a&gt; currently looks:
&lt;img src=&#34;https://sqrtminusone.xyz/images/literate--polybar.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;It has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;colors from the general color theme;&lt;/li&gt;
&lt;li&gt;powerline-ish decorations between modules.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;colors&#34;&gt;Colors&lt;/h3&gt;
&lt;p&gt;The &amp;ldquo;colors&amp;rdquo; part is straightforward enough. Polybar can use &lt;code&gt;Xresources&lt;/code&gt;, so we just need to generate the appropriate bindings of Xresources to the polybar variables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: get-polybar-colors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src emacs-lisp :var table=colors :tangle no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(mapconcat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (lambda (elem)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (format &amp;#34;%s = ${xrdb:%s}&amp;#34; (nth 0 elem) (nth 1 elem)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (seq-filter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (lambda (elem) (when-let (name (nth 1 elem))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (not (string-empty-p name))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; table)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;\n&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src conf-windows :noweb yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[colors]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&amp;lt;get-polybar-colors()&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;background = ${xrdb:background}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;module-decorations&#34;&gt;Module decorations&lt;/h3&gt;
&lt;p&gt;As for the module decorations though, I find it ironic that with all this fancy rendering around I have to resort to Unicode glyphs.&lt;/p&gt;
&lt;p&gt;Anyhow, the approach is to put a glyph between two blocks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;block1  block2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And set the foreground and background colors like that:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;block1&lt;/th&gt;
&lt;th&gt;glyph&lt;/th&gt;
&lt;th&gt;block2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;foreground&lt;/td&gt;
&lt;td&gt;F1&lt;/td&gt;
&lt;td&gt;B2&lt;/td&gt;
&lt;td&gt;F2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;background&lt;/td&gt;
&lt;td&gt;B1&lt;/td&gt;
&lt;td&gt;B1&lt;/td&gt;
&lt;td&gt;B2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;So, that&amp;rsquo;s a start. First, let&amp;rsquo;s define the glyph symbols in the polybar config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;[glyph]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;gleft&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;gright&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;defining-modules&#34;&gt;Defining modules&lt;/h4&gt;
&lt;p&gt;As we want to interweave polybar modules with these glyphs in the right order and with the right colors, it is reasonable to define a single source of truth:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: polybar_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Index | Module | Color | Glyph |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-------+-------------+---------------+-------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 1 | pulseaudio | light-magenta | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 2 | mpd | magenta | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 9 | battery | light-cyan | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 3 | cpu | cyan | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 4 | ram-memory | light-green | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 5 | swap-memory | green | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 6 | network | light-red | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 7 | openvpn | light-red | |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 8 | xkeyboard | red | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 10 | weather | light-yellow | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 12 | sun | yellow | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 13 | aw-afk | light-blue | + |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 14 | date | blue | + |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also excluding some modules from certain monitors, which for now is about excluding &lt;code&gt;battery&lt;/code&gt; from the monitors of my desktop PC:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: polybar_modules_exclude
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Monitor | Exclude |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|----------+---------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| DVI-D-0 | battery |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| HDMI-A-0 | battery |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;generating-glyphs&#34;&gt;Generating glyphs&lt;/h4&gt;
&lt;p&gt;To generate the required set of glyphs, we need a glyph for every possible combination of adjacent colors that can occur in polybar.&lt;/p&gt;
&lt;p&gt;Most of these combinations can be inferred from the &lt;code&gt;polybar_modules&lt;/code&gt; table, the rest are defined in another table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: polybar_extra_colors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Color 1 | Color 2 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|------------+---------------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| background | white |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| background | light-magenta |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| blue | background |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a definition of the source block with the required variables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: polybar-generate-glyphs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src emacs-lisp :var table=polybar_modules exclude-table=polybar_modules_exclude extra=polybar_extra_colors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...source...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And there is the source block itself (because I want to have some syntax highlighting for this one in the post):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;monitors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exclude-table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-map&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-uniq&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exclude-combinations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;monitor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;monitor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exclude-table&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;monitors&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;module-glyph-combinations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exclude-combinations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exclude&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;elt&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;member&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;elt&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;exclude&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;elt&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-uniq&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;color-changes&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extra&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;add-to-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;color-changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;e&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;comb&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;module-glyph-combinations&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;dotimes&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;1-&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;comb&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;add-to-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;color-changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;comb&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;1+&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;comb&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapconcat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;colors&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;[module/glyph-%s--%s]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;type = custom/text
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;content-background = ${colors.%s}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;content-foreground = ${colors.%s}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;content = ${glyph.gright}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;content-font = 5&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;colors&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;colors&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;colors&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;colors&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;color-changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s a rough outline of how the code works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;monitors&lt;/code&gt; is a list of unique monitors in &lt;code&gt;exclude-table&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exclude-combilnations&lt;/code&gt; is a list of lists of module names to be excluded for each monitor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;module-glyphs-combinations&lt;/code&gt; is a list of lists of actual modules for each monitor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;color-changes&lt;/code&gt; is a list of unique adjacent colors across modules in all monitors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, &lt;code&gt;color-changes&lt;/code&gt; is used to generate glyph modules that look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;[module/glyph-light-cyan--cyan]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;custom/text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;content-background&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;${colors.light-cyan}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;content-foreground&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;${colors.cyan}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;${glyph.gright}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;content-font&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As of now, 15 of such modules is generated.&lt;/p&gt;
&lt;p&gt;And including this in the polybar config itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src conf-windows :noweb yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&amp;lt;polybar-generate-glyphs()&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;individual-modules&#34;&gt;Individual modules&lt;/h4&gt;
&lt;p&gt;Another thing we need to do is to set the color of modules in accordance with the &lt;code&gt;polybar_modules&lt;/code&gt; table. The background can be determined from the &lt;code&gt;Color&lt;/code&gt; column with the following code block:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: get-polybar-bg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src emacs-lisp :var table=polybar_modules module=&amp;#34;pulseaudio&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(format
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;${colors.%s}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (nth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (seq-find
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (lambda (el) (string-equal (nth 1 el) module))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; table)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that block is meant to be invoked in each module definition, e.g. for the &lt;code&gt;cpu&lt;/code&gt; module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src conf-windows :noweb yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[module/cpu]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;type = internal/cpu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;format = &amp;#34; &amp;lt;label&amp;gt;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;label = %percentage%%
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;format-background = &amp;lt;&amp;lt;get-polybar-bg(module=&amp;#34;cpu&amp;#34;)&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;global-polybar-configuration&#34;&gt;Global polybar configuration&lt;/h4&gt;
&lt;p&gt;To configure polybar itself, we first need to generate a set of modules for each monitor.&lt;/p&gt;
&lt;p&gt;Here is the source block definition:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+NAME: polybar-generate-modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src emacs-lisp :var table=polybar_modules exclude-table=polybar_modules_exclude monitor=&amp;#34;DVI-D-0&amp;#34; first-color=&amp;#34;background&amp;#34; last-color=&amp;#34;background&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The parameters here, excluding the two required tables, are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;monitor&lt;/code&gt; - the current monitor on which to filter out the blocks by the &lt;code&gt;polybar_modules_exclude&lt;/code&gt; table,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;first-color&lt;/code&gt; - the first color of the first glyph,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;last-color&lt;/code&gt; - the second color of the last glyph.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here is the source:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;exclude-modules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exclude-table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;monitor&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-map&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;modules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;member&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;exclude-modules&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;prev-color&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;first-color&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;ret&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapconcat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;apply&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;ret&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;glyph-%s--%s &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;prev-color&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;prev-color&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;ret&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;el&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;modules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;last-color&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34; glyph-%s--%s &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;prev-color&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;last-color&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s how it evaluates on my current monitor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;glyph-background--light-magenta pulseaudio glyph-light-magenta--magenta mpd glyph-magenta--cyan cpu glyph-cyan--light-green ram-memory glyph-light-green--green swap-memory glyph-green--light-red network openvpn glyph-light-red--red xkeyboard glyph-red--light-yellow weather glyph-light-yellow--yellow sun glyph-yellow--light-blue aw-afk glyph-light-blue--blue date glyph-blue--background
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The polybar config doesn&amp;rsquo;t support conditional statements, but it does support environment variables, so we can pass the parameters from something like a bash script. Here&amp;rsquo;s an excerpt from mine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;declare&lt;/span&gt; -A &lt;span style=&#34;color:#19177c&#34;&gt;BLOCKS&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;eDP&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;]=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;lt;&amp;lt;polybar-generate-modules(monitor=&amp;#34;&lt;/span&gt;eDP&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;)&amp;gt;&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;eDP-1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;]=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;lt;&amp;lt;polybar-generate-modules(monitor=&amp;#34;&lt;/span&gt;eDP-1&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;)&amp;gt;&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;DVI-D-0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;]=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;lt;&amp;lt;polybar-generate-modules(monitor=&amp;#34;&lt;/span&gt;DVI-D-0&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;)&amp;gt;&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;HDMI-A-0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;]=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;lt;&amp;lt;polybar-generate-modules(monitor=&amp;#34;&lt;/span&gt;HDMI-A-0&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;)&amp;gt;&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pkill polybar
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;for&lt;/span&gt; m in &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;xrandr --query | grep &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34; connected&amp;#34;&lt;/span&gt; | cut -d&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; -f1&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt;; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;RIGHT_BLOCKS&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b68;font-weight:bold&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;BLOCKS&lt;/span&gt;[&lt;span style=&#34;color:#19177c&#34;&gt;$MONITOR&lt;/span&gt;]&lt;span style=&#34;color:#b68;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; polybar mybar &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(The full script has a lot of stuff that is not relevant to this post, but you can &lt;a href=&#34;https://github.com/SqrtMinusOne/dotfiles/blob/master/Desktop.org#launch-script-1&#34;&gt;check here&lt;/a&gt; if you are interested.)&lt;/p&gt;
&lt;p&gt;So, in the case of polybar, literate configuration allows for implementing a sort of logic that wouldn&amp;rsquo;t be available with the base configuration (also a promise of projects like Guix Home, by the way). Maintaining this configuration, e.g. changing the order of modules, is much easier this way than it would be if everything was hardcoded in the polybar config itself.&lt;/p&gt;
</content>
</item>
<item>
<title>org-journal-tags</title>
<link>https://sqrtminusone.xyz/packages/org-journal-tags/</link>
<pubDate>Sun, 06 Feb 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/org-journal-tags/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/org-journal-tags&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/org-journal-tags-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A package to make sense of &lt;del&gt;my life&lt;/del&gt; &lt;a href=&#34;https://github.com/bastibe/org-journal&#34;&gt;org-journal&lt;/a&gt; records.&lt;/p&gt;
&lt;p&gt;The package adds the &lt;code&gt;org-journal:&lt;/code&gt; link type to Org Mode. When placed in an org-journal file, the link serves as a &amp;ldquo;tag&amp;rdquo; that references one or many paragraphs of the journal or the entire section. These tags are aggregated in the database that can be queried in various ways.&lt;/p&gt;
&lt;h2 id=&#34;rationale&#34;&gt;Rationale&lt;/h2&gt;
&lt;p&gt;Journal files, by their very nature, are weakly structured. A single journal note can reference multiple entities (or none) and can itself be composed of multiple parts that have in common only the date and time when they were written. Needless to say, it&amp;rsquo;s hard to find anything in such records.&lt;/p&gt;
&lt;p&gt;This package attempts to improve the accessibility of the journal by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Taking advantage of temporal data, e.g. allowing to query entries in some date range.&lt;/li&gt;
&lt;li&gt;Allowing to extract (and reference) only certain parts of a particular journal entry.&lt;/li&gt;
&lt;li&gt;Compensating weak structure by with more advanced query engine.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For instance, when I&amp;rsquo;m writing down the progress on a job project, I can leave a tag like &lt;code&gt;job.&amp;lt;project-name&amp;gt;&lt;/code&gt; in the paragraph(s) related to that project. Later, I can query only those paragraphs that are referenced by this particular tag. The query results can then be narrowed, for instance, to include the word &amp;ldquo;backend&amp;rdquo;, or extended with some other tag.&lt;/p&gt;
&lt;p&gt;If no tag matches the subject matter, the journal can be queried with a regular expression, e.g. by searching some regex within a specific time frame. Subsequent searches are also significantly faster than the built-in &lt;code&gt;org-journal&lt;/code&gt; search functionality due to the to caching mechanism.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, my preferred way is &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-journal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-autosync-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;basic-usage&#34;&gt;Basic usage&lt;/h2&gt;
&lt;h3 id=&#34;adding-tags&#34;&gt;Adding tags&lt;/h3&gt;
&lt;p&gt;To add an inline tag, you can manually create a link of the following format:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[org-journal:&amp;lt;tag-name&amp;gt;][&amp;lt;tag-description&amp;gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or run &lt;code&gt;M-x org-journal-tags-insert-tag&lt;/code&gt; to insert a tag with a completion interface. The description is not aggregated and thus optional. Also, &lt;code&gt;&amp;lt;tag-name&amp;gt;&lt;/code&gt; cannot contain &lt;code&gt;:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The link will reference the current Org Mode paragraph. If you want to reference more paragraphs, you can set the number of paragraphs like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[org-journal:&amp;lt;tag-name&amp;gt;::&amp;lt;number-of-paragraphs&amp;gt;][&amp;lt;tag-description&amp;gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run &lt;code&gt;M-x org-journal-tags-link-get-region-at-point&lt;/code&gt; to select the referenced region of the buffer.&lt;/p&gt;
&lt;p&gt;To add a tag to the entire section, run &lt;code&gt;M-x org-journal-tags-prop-set&lt;/code&gt;, which will create or update the &lt;code&gt;Tags&lt;/code&gt; property in the property drawer of the current time section. This command features a notmuch-like UI, i.e. completing read for multiple entries, where &lt;code&gt;+&amp;lt;tag&amp;gt;&lt;/code&gt; adds a tag and &lt;code&gt;-&amp;lt;tag&amp;gt;&lt;/code&gt; deletes a tag.&lt;/p&gt;
&lt;p&gt;If you decide to rename a tag, there&amp;rsquo;s &lt;code&gt;M-x org-journal-tags-refactor&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;tag-kinds&#34;&gt;Tag kinds&lt;/h3&gt;
&lt;p&gt;Tag kind is a predefined class of tag with some extra functionality. The link format fo such tags is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[org-journal:&amp;lt;kind&amp;gt;:&amp;lt;tag-name&amp;gt;][&amp;lt;tag-description&amp;gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[org-journal:&amp;lt;kind&amp;gt;:&amp;lt;tag-name&amp;gt;::&amp;lt;number-of-paragraphs&amp;gt;][&amp;lt;tag-description&amp;gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;&amp;lt;kind&amp;gt;&lt;/code&gt; is omitted, a tag is considered &amp;ldquo;normal&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Running &lt;code&gt;C-u M-x org-journal-tags-insert-tag&lt;/code&gt; will first prompt for the tag kind and then for the tag itself from the set of already used tags of that kind.&lt;/p&gt;
&lt;p&gt;Running &lt;code&gt;C-u C-u M-x org-journal-tags-insert-tag&lt;/code&gt; will also first prompt for the tag kind, but then will try to invoke the kind-specific tag selection logic, if such is available. For instance, the &lt;code&gt;contact&lt;/code&gt; kind will prompt the &lt;code&gt;org-contacts&lt;/code&gt; database.&lt;/p&gt;
&lt;p&gt;For now, the only available tag kind is &lt;a href=&#34;https://repo.or.cz/org-contacts.git&#34;&gt;org-contacts&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;adding-timestamps&#34;&gt;Adding timestamps&lt;/h3&gt;
&lt;p&gt;In addition to tags, the package also aggregates inline timestamps, i.e. timestamps that are left in the text like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;This is a text. This is a text with &amp;lt;2022-04-07 Thu&amp;gt; a timestamp. This is a text again.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A timestamp will reference just the current paragraph.&lt;/p&gt;
&lt;p&gt;Other forms of timestamps (&lt;code&gt;SCHEDULED&lt;/code&gt;, &lt;code&gt;DEADLINE&lt;/code&gt;, etc.) are not supported at the moment, because this functionality is implemented well enough by &lt;a href=&#34;https://orgmode.org/manual/Agenda-Views.html&#34;&gt;org-agenda&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The envisioned use case for this functionality to leave references for the future to be seen at a particular date.&lt;/p&gt;
&lt;h3 id=&#34;database&#34;&gt;Database&lt;/h3&gt;
&lt;p&gt;The package stores tags and references to these tags in a database.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;org-journal-tags-autosync-mode&lt;/code&gt; enables synchronizing the database at the moment of saving of the org-journal buffer. You can also run the synchronization manually:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-x org-journal-tags-process-buffer&lt;/code&gt; to process the current buffer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x org-journal-tags-db-sync&lt;/code&gt; to sync changed org-journal files in the filesystem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The same mode enables saving the database on killing Emacs, but you can always run &lt;code&gt;M-x org-journal-tags-db-save&lt;/code&gt; manually.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;M-x org-journal-tags-db-unload&lt;/code&gt; saves and unloads the database from the memory, &lt;code&gt;M-x org-journal-tags-db-reset&lt;/code&gt; creates a new database.&lt;/p&gt;
&lt;h3 id=&#34;status-buffer&#34;&gt;Status buffer&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/org-journal-tags-img/status.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;(I replaced tag names with &amp;ldquo;X&amp;rdquo; just for the screenshot)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;M-x org-journal-tags-status&lt;/code&gt; opens the status buffer with some statistics about the journal and tags. Press &lt;code&gt;?&lt;/code&gt; to see the available keybindings.&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;RET&lt;/code&gt; on a tag name in the &amp;ldquo;All tags&amp;rdquo; section should open a query buffer set to return all references for this tag.&lt;/p&gt;
&lt;h3 id=&#34;query-constructor&#34;&gt;Query constructor&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/org-journal-tags-img/query.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Pressing &lt;code&gt;s&lt;/code&gt; in the status buffer or running &lt;code&gt;M-x org-journal-tags-transient-query&lt;/code&gt; opens a &lt;a href=&#34;https://magit.vc/manual/transient/&#34;&gt;transient.el&lt;/a&gt; buffer with query settings.&lt;/p&gt;
&lt;p&gt;The options are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Include tags&lt;/strong&gt; filters the references so that each reference had at least one of these tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exclude tags&lt;/strong&gt; filters the references so that each reference didn&amp;rsquo;t have any of these tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Include children&lt;/strong&gt; includes child tags to the previous two lists.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag location&lt;/strong&gt; can filter only section tags on inline tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start date&lt;/strong&gt; and &lt;strong&gt;End date&lt;/strong&gt; filter the references by date.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filter timestamps&lt;/strong&gt; filters the references so that they include a timestamp.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timestamp start date&lt;/strong&gt; and &lt;strong&gt;Timestamp end date&lt;/strong&gt; filter
timestamps by their date.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regex&lt;/strong&gt; filter the references by a regular expression. It can be a string or &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Rx-Notation.html&#34;&gt;rx&lt;/a&gt; expression (it just has to start with &lt;code&gt;(rx&lt;/code&gt; in this case).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Narrow to regex&lt;/strong&gt; makes it so that each reference had only paragraphs that have a regex match.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sort&lt;/strong&gt; sorts the result in ascending order. It&amp;rsquo;s descending by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pressing &lt;code&gt;RET&lt;/code&gt; or &lt;code&gt;e&lt;/code&gt; executes the query. Journal files are cached, so subsequent queries within one session are much faster.&lt;/p&gt;
&lt;h3 id=&#34;query-results&#34;&gt;Query results&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/org-journal-tags-img/query-results.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;After the query completes, the package opens the results buffer. Press &lt;code&gt;?&lt;/code&gt; to see the available keybindings there.&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;RET&lt;/code&gt; opens the corresponding org-journal entry.&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;s&lt;/code&gt; opens the query constructor buffer. If opened from inside the query results, the query constructor has 4 additional options:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Set operation&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Union&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old new&lt;/td&gt;
&lt;td&gt;Add records of the new query to the displayed records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Intersection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old ∩ new&lt;/td&gt;
&lt;td&gt;Leave only those records that are both displayed and in the new query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Difference from current&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old \ new&lt;/td&gt;
&lt;td&gt;Exclude records of the new query from the displayed records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Difference to current&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;new \ old&lt;/td&gt;
&lt;td&gt;Exclude displayed records from ones of the new query&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Thus it is possible to make any query that can be described as a sequence of such set operations.&lt;/p&gt;
&lt;h2 id=&#34;advanced-usage&#34;&gt;Advanced usage&lt;/h2&gt;
&lt;h3 id=&#34;automatic-tagging&#34;&gt;Automatic tagging&lt;/h3&gt;
&lt;p&gt;org-journal provides a hook to automatically add information to the journal entries.&lt;/p&gt;
&lt;p&gt;It can be used to automatically assign tags, for instance, based on hostname. Here&amp;rsquo;s an excerpt from my configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/set-journal-header&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-prop-apply-delta&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:add&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;host.%s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;system-name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;boundp&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;my/loc-tag&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-prop-apply-delta&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:add&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/loc-tag&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;org-journal-after-entry-create-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/set-journal-header&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;encryption&#34;&gt;Encryption&lt;/h3&gt;
&lt;p&gt;There are two ways how org-journal can be encrypted:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;a href=&#34;https://orgmode.org/manual/Org-Crypt.html&#34;&gt;org-crypt&lt;/a&gt;, by setting &lt;code&gt;org-journal-enable-encryption&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;With &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/epa/Encrypting_002fdecrypting-gpg-files.html&#34;&gt;epa&lt;/a&gt;, by setting &lt;code&gt;org-journal-encrypt-journal&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both ways are supported by this package (I use the first). The decryption of entries takes some time, but this is alleviated by caching.&lt;/p&gt;
&lt;p&gt;The cache is stored in the &lt;code&gt;org-journal-tags--files-cache&lt;/code&gt; variable, so in principle, someone could come to your computer and inspect the value of this variable (who would ever do that?). If that&amp;rsquo;s an issue, you can do something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;run-with-idle-timer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;15&lt;/span&gt;) &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-cache-reset&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To clear the cache on Emacs being idle after 15 minutes.&lt;/p&gt;
&lt;p&gt;Also, as said above, &lt;code&gt;org-journal-tags&lt;/code&gt; uses its own database, which is more like persistent cache for tags and references. You can encrypt it as well with &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/epa/Encrypting_002fdecrypting-gpg-files.html&#34;&gt;epa&lt;/a&gt; by adding &lt;code&gt;.gpg&lt;/code&gt; to the &lt;code&gt;org-journal-tags-db-file&lt;/code&gt; variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-db-file&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;user-emacs-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;var/org-journal-tags/index.gpg&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The database is also stored in memory in &lt;code&gt;org-journal-tags-db&lt;/code&gt; variable, so once again, someone could inspect the value of the variable or just run &lt;code&gt;M-x org-journal-tags-status&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To avoid that, you can manually run &lt;code&gt;M-x org-journal-tags-db-unload&lt;/code&gt; or add it to &lt;code&gt;run-with-idle-timer&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;run-with-idle-timer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;15&lt;/span&gt;) &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-db-unload&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you have everything set up correctly, encrypting a file shouldn&amp;rsquo;t ask for a passphrase, so this function can be run automatically.&lt;/p&gt;
&lt;h3 id=&#34;advanced-querying&#34;&gt;Advanced querying&lt;/h3&gt;
&lt;p&gt;This package provides an API for doing queries from the Lisp code.&lt;/p&gt;
&lt;p&gt;The central function there &lt;code&gt;org-journal-tags-query&lt;/code&gt;, which has an interface corresponding to the flags in the query constructor. Take a look at its docstring for more info.&lt;/p&gt;
&lt;p&gt;Also, you can use some of the following operations on the set of journal references:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-union-refs&lt;/code&gt; - union&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-diff-refs&lt;/code&gt; - difference&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-intersect-refs&lt;/code&gt; - intersection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-merge-refs&lt;/code&gt; - merge intersecting references within one set&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-sort-refs&lt;/code&gt; - order references by date&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--string-extract-refs&lt;/code&gt; - collect strings corresponding to references&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;final-notes&#34;&gt;Final notes&lt;/h2&gt;
&lt;p&gt;This package turned out to be almost as long and complex as &lt;a href=&#34;https://github.com/bastibe/org-journal&#34;&gt;org-journal&lt;/a&gt; itself, and it also introduces some new dependencies. Hence I decided it would be better off as a separate package.&lt;/p&gt;
&lt;p&gt;Also, I want to list some sources of inspiration. The database logic is heavily inspired by &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt;. The UI with &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_mono/widget.html&#34;&gt;Emacs widgets&lt;/a&gt; for tags &amp;amp; &lt;code&gt;completing-read-multiple&lt;/code&gt; and the tagging system in general is inspired by &lt;a href=&#34;https://notmuchmail.org/&#34;&gt;notmuch&lt;/a&gt;. Finally, &lt;a href=&#34;https://github.com/magit/transient&#34;&gt;transient.el&lt;/a&gt; and &lt;a href=&#34;https://magit.vc/manual/magit-section.html&#34;&gt;magit-section&lt;/a&gt; are the UI packages that made this one possible, or at least much easier to implement.&lt;/p&gt;
</content>
</item>
<item>
<title>Using EXWM and perspective.el on multi-monitor setup</title>
<link>https://sqrtminusone.xyz/posts/2022-01-03-exwm/</link>
<pubDate>Mon, 03 Jan 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2022-01-03-exwm/</guid>
<content type="html">
&lt;p&gt;I wrote about &lt;a href=&#34;https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/&#34;&gt;Emacs and i3&lt;/a&gt; integration around two months ago. Shortly after however, I decided to give EXWM another try, mainly because my largest reservation - lack of performance - seems to have been resolved by updates to the native compilation since my first attempt. Or I may have lost some sensitivity to that issue. Regardless, the second dive into EXWM thus far feels successful, and I think it&amp;rsquo;s the right time to share some of my thoughts on the subject.&lt;/p&gt;
&lt;p&gt;Before we start though, I&amp;rsquo;ll point out that I won&amp;rsquo;t go into detail about the initial setup. I think David Wilson&amp;rsquo;s &amp;ldquo;&lt;a href=&#34;https://systemcrafters.net/emacs-desktop-environment/&#34;&gt;Emacs Desktop Environment&lt;/a&gt;&amp;rdquo; series describes this part pretty well, so I don&amp;rsquo;t feel the need to repeat much of that.&lt;/p&gt;
&lt;p&gt;This post is a sort of a snapshot of the path from the baseline of &lt;a href=&#34;https://github.com/daviwil/emacs-from-scratch/blob/master/Desktop.org&#34;&gt;Emacs From Scratch&lt;/a&gt; to my image of a perfect window manager, and it may or may not be coincidental that the latter resembles i3 in many aspects.&lt;/p&gt;
&lt;p&gt;After all, I was using i3 for more than two years, so it&amp;rsquo;s not something I can easily let go of. But I think (or would like to think) that&amp;rsquo;s because the ideas are good, not because I&amp;rsquo;m overly conservative in my workflow choices.&lt;/p&gt;
&lt;h2 id=&#34;perspective-dot-el&#34;&gt;perspective.el&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/nex3/perspective-el&#34;&gt;perspective.el&lt;/a&gt; is one package I like that provides workspaces for Emacs, called &amp;ldquo;perspectives&amp;rdquo;. Each perspective has a separate buffer list, window layout, and a few other things that make it easier to separate things within Emacs.&lt;/p&gt;
&lt;p&gt;One feature I&amp;rsquo;d like to highlight is integration between perspective.el and &lt;a href=&#34;https://github.com/Alexander-Miller/treemacs&#34;&gt;treemacs&lt;/a&gt;, where one perspective can have a separate treemacs tree. Although now tab-bar.el seems to be getting into shape to compete with perspective.el, as of the time of this writing, there&amp;rsquo;s no such integration, at least not out of the box.&lt;/p&gt;
&lt;p&gt;perspective.el works with EXWM more or less as one would expect - each EXWM workspace has its own set of perspectives. That way it feels somewhat like having multiple Emacs frames in a tiling window manager, although, of course, much more integrated with Emacs.&lt;/p&gt;
&lt;p&gt;However, there are still some issues. For instance, I was having strange behaviors with floating windows, EXWM buffers in perspectives, etc. So I&amp;rsquo;ve made a package called &lt;a href=&#34;https://github.com/SqrtMinusOne/perspective-exwm.el&#34;&gt;perspective-exwm.el&lt;/a&gt; that does two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fixes issues I found with some advises and hooks. Take a look at the package homepage for more detail on that.&lt;/li&gt;
&lt;li&gt;Provides some additional functionality that makes use of both perspective.el and EXWM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, you can install the package however you normally do so. E.g. I do that with straight.el &amp;amp; use-package:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then load the provided minor mode before &lt;code&gt;exwm-init&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm-init&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;initial-perspective-names&#34;&gt;Initial perspective names&lt;/h3&gt;
&lt;p&gt;One nice thing this package can do is set up the initial perspective names for different workspaces. By default, enabling &lt;code&gt;perspective-exwm-mode&lt;/code&gt; sets names like &lt;code&gt;main-1&lt;/code&gt; for workspace with index 1 and so on, because otherwise different perspectives will share the same &lt;code&gt;*scratch*&lt;/code&gt; buffer.&lt;/p&gt;
&lt;p&gt;But names can be overridden like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-override-initial-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;misc&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;core&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;browser&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;comms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;dev&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;assigning-apps-to-workspaces-and-perspectives&#34;&gt;Assigning apps to workspaces and perspectives&lt;/h3&gt;
&lt;p&gt;By default, a new Emacs buffer opens in the current perspective in the current workspace, but sure enough, it&amp;rsquo;s possible to change that.&lt;/p&gt;
&lt;p&gt;For EXWM windows, the &lt;code&gt;perspective-exwm&lt;/code&gt; package provides a function called &lt;code&gt;perspective-exwm-assign-window&lt;/code&gt;, which is intended to be used in &lt;code&gt;exwm-manage-finish-hook&lt;/code&gt;, for instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-configure-window&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-class-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Firefox&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Nightly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-assign-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:workspace-index&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:persp-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;browser&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Alacritty&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-assign-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:persp-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;term&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-manage-finish-hook&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-configure-window&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This hook is run after a new EXWM buffer is created and configured in the context of this buffer, so it seems customary to do such settings there. With this snippet, Firefox will always open in workspace 2 in the perspective named &amp;ldquo;browser&amp;rdquo;, and Alacritty will always open in the current workspace in the perspective named &amp;ldquo;term&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;To pull this off for various Emacs apps, it is necessary to open the right EXWM workspace and perspective before opening the app. As I use &lt;a href=&#34;https://github.com/noctuid/general.el&#34;&gt;general.el&lt;/a&gt;, I made a macro to automate that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/command-in-persp&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;command-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;persp-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;workspace-index&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;workspace-index&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;fboundp&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace-switch-create&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace-switch-create&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;workspace-index&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;persp-switch&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;persp-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;delete-other-windows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:wk&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;command-name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;fboundp&lt;/code&gt; is meant to provide compatibility with running Emacs without EXWM. Usage of the macro is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;my-leader-def&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:infix&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;as&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;:which-key&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;emms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/command-in-persp&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;emms&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;EMMS&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms-smart-browse&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;my-leader-def&lt;/code&gt; is a &lt;a href=&#34;https://github.com/noctuid/general.el#creating-new-key-definers&#34;&gt;custom definer&lt;/a&gt;. That way the defined keybinding opens &lt;a href=&#34;https://www.gnu.org/software/emms/&#34;&gt;EMMS&lt;/a&gt; in the workspace 0 in the perspective &amp;ldquo;EMMS&amp;rdquo;. I have this for several other apps, like elfeed, notmuch, dired &lt;code&gt;$HOME&lt;/code&gt; and so on.&lt;/p&gt;
&lt;h3 id=&#34;some-workflow-notes&#34;&gt;Some workflow notes&lt;/h3&gt;
&lt;p&gt;As I said above, using perspectives in EXWM makes a lot of sense. Because all the EXWM workspace share the same buffer list (sans X windows), and because Emacs becomes the central program (for instance, it can&amp;rsquo;t be easily closed), it is only natural to split the buffer list.&lt;/p&gt;
&lt;p&gt;Another aspect of using EXWM is that it becomes very easy to work with code on multiple monitors. While it may signify issues with the code in question if such need arises, having that possibility is still handy and it&amp;rsquo;s not something easily replicable on other tiling WMs. &lt;code&gt;perspective-exwm&lt;/code&gt; also presents some features here, for instance, &lt;code&gt;M-x perspective-exwm-copy-to-workspace&lt;/code&gt; can be used to copy the current perspective to the adjacent monitor.&lt;/p&gt;
&lt;p&gt;Also, in my opinion, Emacs apps like &lt;a href=&#34;https://www.gnu.org/software/emms/&#34;&gt;EMMS&lt;/a&gt; and &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt; deserve to be on the same &amp;ldquo;level&amp;rdquo; as &amp;ldquo;proper&amp;rdquo; apps like a browser. On other tiling WMs, something like that can be done with Emacs daemon and multiple Emacs frames, but with EXWM and perspectives this seems natural without much extra work.&lt;/p&gt;
&lt;p&gt;As for switching between X windows and perspectives, I ended up preferring to have one perspective for all X windows in the workspace, at least if these windows are full-fledged apps. For instance, all my messengers go to the workspace 3 to the perspective &amp;ldquo;comms&amp;rdquo;, and I switch between them with &lt;code&gt;M-x perspective-exwm-cycle-exwm-buffers-&amp;lt;forward|backward&amp;gt;&lt;/code&gt;, bound to &lt;code&gt;s-[&lt;/code&gt; and &lt;code&gt;s-]&lt;/code&gt;. For switching perspectives, I&amp;rsquo;ve bound &lt;code&gt;s-,&lt;/code&gt; and &lt;code&gt;s-.&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-input-global-keys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Switch perspectives&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-,&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;persp-prev&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-.&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;persp-next&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; EXWM buffers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-[&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-cycle-exwm-buffers-backward&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-]&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-cycle-exwm-buffers-forward&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;workspaces-on-multiple-monitors&#34;&gt;Workspaces on multiple monitors&lt;/h2&gt;
&lt;p&gt;Here, &lt;code&gt;exwm-randr&lt;/code&gt; provides basic functionality for running EXWM on multiple monitors. For instance, with configuration like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-randr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-enable&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; The script is generated by ARandR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;start-process-shell-command&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;xrandr&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/bin/scripts/screen-layout&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string=&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;system-name&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;indigo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-monitor-plist&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;DVI-D-0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;DVI-D-0&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;exwm-init&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;workspaces 2 and 3 on the machine with hostname &amp;ldquo;indigo&amp;rdquo; will be displayed on the monitor &lt;code&gt;DVI-D-0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, some features, common in other tiling WMs, are missing in EXWM out of the box, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a command to &lt;a href=&#34;https://i3wm.org/docs/userguide.html#_focusing_moving_containers&#34;&gt;switch to another monitor&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;a command to &lt;a href=&#34;https://i3wm.org/docs/userguide.html#move_to_outputs&#34;&gt;move the current workspace to another monitor&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;using the same commands to switch between windows and monitors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s my take on implementing them.&lt;/p&gt;
&lt;h3 id=&#34;tracking-recently-used-workspaces&#34;&gt;Tracking recently used workspaces&lt;/h3&gt;
&lt;p&gt;First up though, we need to track the workspaces in the usage order. I&amp;rsquo;m not sure if there&amp;rsquo;s some built-in functionality in EXWM for that, but it seems simple enough to implement.&lt;/p&gt;
&lt;p&gt;Here is a snippet of code that does it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-last-workspaces&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-store-last-workspace&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Save the last workspace to &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/exwm-last-workspaces&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-last-workspaces&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-uniq&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace-current-index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-last-workspaces&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-workspace-switch-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-store-last-workspace&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The variable &lt;code&gt;my/exwm-last-workspaces&lt;/code&gt; stores the workspace indices; the first item is the index of the current workspace, the second item is the index of the previous workspace, and so on.&lt;/p&gt;
&lt;p&gt;One note here is that workspaces may also disappear (e.g. after &lt;code&gt;M-x exwm-workspace-delete&lt;/code&gt;), so we also need a function to clean the list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-last-workspaces-clear&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Clean &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/exwm-last-workspaces&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; from deleted workspaces.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-last-workspaces&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace--list&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-last-workspaces&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-monitor-list&#34;&gt;The monitor list&lt;/h3&gt;
&lt;p&gt;The second piece of the puzzle is getting the monitor list in the right order.&lt;/p&gt;
&lt;p&gt;While it is possible to retrieve the monitor list from &lt;code&gt;exwm-randr-workspace-output-plist&lt;/code&gt;, this won&amp;rsquo;t scale well beyond two monitors, mainly because changing this variable may screw up the order.&lt;/p&gt;
&lt;p&gt;So the easiest way is to just define the variable like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-monitor-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;system-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;indigo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;DVI-D-0&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are changing the RandR configuration on the fly, this variable will also need to be changed, but for now, I don&amp;rsquo;t have such a necessity.&lt;/p&gt;
&lt;p&gt;A function to get the current monitor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-get-current-monitor&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Return the current monitor name or nil.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-output-plist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-position&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;selected-frame&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace--list&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a function to cycle the monitor list in either direction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-get-other-monitor&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Cycle the monitor list in the direction DIR.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;DIR is either &amp;#39;left or &amp;#39;right.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;%&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-position&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-get-current-monitor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-monitor-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:test&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-equal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-monitor-list&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;left&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;-1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-monitor-list&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-monitor-list&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;switch-to-another-monitor&#34;&gt;Switch to another monitor&lt;/h3&gt;
&lt;p&gt;With the functions from the previous two sections, we can implement switching to another monitor by switching to the most recently used workspace on that monitor.&lt;/p&gt;
&lt;video controls width=&#34;100%&#34;&gt;
&lt;source src=&#34;https://sqrtminusone.xyz/videos/exwm-workspace-switch.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;
&lt;p&gt;One caveat here is that on the startup the &lt;code&gt;my/exwm-last-workspaces&lt;/code&gt; variable won&amp;rsquo;t have any values from other monitor(s), so this list is concatenated with the list of available workspace indices.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-switch-to-other-monitor&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Switch to another monitor.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-last-workspaces-clear&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace-switch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-monitor&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-get-other-monitor&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-last-workspaces&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace--list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;collect&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-monitor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-output-plist&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-monitor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-output-plist&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I bind this function to &lt;code&gt;s-q&lt;/code&gt;, as I&amp;rsquo;m used from i3.&lt;/p&gt;
&lt;h3 id=&#34;move-the-workspace-to-another-monitor&#34;&gt;Move the workspace to another monitor&lt;/h3&gt;
&lt;p&gt;Now, moving the workspace to another monitor.&lt;/p&gt;
&lt;video controls width=&#34;100%&#34;&gt;
&lt;source src=&#34;https://sqrtminusone.xyz/videos/exwm-workspace-move.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;
&lt;p&gt;This is actually quite easy to pull off - one just has to update &lt;code&gt;exwm-randr-workspace-monitor-plist&lt;/code&gt; accordingly and run &lt;code&gt;exwm-randr-refresh&lt;/code&gt;. I just add another check there because I don&amp;rsquo;t want some monitor to remain without workspaces at all.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-workspace-switch-monitor&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Move the current workspace to another monitor.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;new-monitor&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-get-other-monitor&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;current-monitor&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-get-current-monitor&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-monitor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-monitor-plist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;by&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;cddr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;current-monitor&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#d2413a;font-weight:bold&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Can&amp;#39;t remove the last workspace on the monitor!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-monitor-plist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;map-delete&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-monitor-plist&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace-current-index&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;new-monitor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-monitor-plist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;plist-put&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-workspace-monitor-plist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace-current-index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;new-monitor&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm-randr-refresh&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my configuration this is bound to &lt;code&gt;s-&amp;lt;tab&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;windmove-between-monitors&#34;&gt;Windmove between monitors&lt;/h3&gt;
&lt;p&gt;And the final (for now) piece of the puzzle is using the same command to switch between windows and monitors. E.g. when the focus is on the right-most window on one monitor, I want the command to switch to the left-most window on the monitor to the right instead of saying &amp;ldquo;No window right from the selected window&amp;rdquo;, as &lt;code&gt;windmove-right&lt;/code&gt; does.&lt;/p&gt;
&lt;p&gt;So here is my implementation of that. It always does &lt;code&gt;windmove-do-select-window&lt;/code&gt; for &lt;code&gt;&#39;down&lt;/code&gt; and &lt;code&gt;&#39;up&lt;/code&gt;. For &lt;code&gt;&#39;right&lt;/code&gt; and &lt;code&gt;&#39;left&lt;/code&gt; though, the function calls the previously defined function to switch to other monitor if &lt;code&gt;windmove-find-other-window&lt;/code&gt; doesn&amp;rsquo;t return anything.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Move to window or monitor in the direction DIR.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;down&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;up&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-do-window-select&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-find-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-monitor&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-get-other-monitor&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;opposite-dir&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;left&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;left&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-do-window-select&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-switch-to-other-monitor&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-find-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;opposite-dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;do&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-do-window-select&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;opposite-dir&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I bind it to the corresponding keys like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-input-global-keys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Switch windows&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-&amp;lt;left&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;left&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-&amp;lt;right&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-&amp;lt;up&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;up&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-&amp;lt;down&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;down&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-h&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;left&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-l&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-k&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;up&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-j&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;down&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;managing-windows&#34;&gt;Managing windows&lt;/h2&gt;
&lt;p&gt;Another thing I want to tackle here is managing windows.&lt;/p&gt;
&lt;p&gt;This section of the post depends on &lt;a href=&#34;https://github.com/emacs-evil/evil&#34;&gt;evil-mode&lt;/a&gt;, which provides a reasonable set of vim-like commands to manage windows. But a few points to improve upon remain.&lt;/p&gt;
&lt;h3 id=&#34;moving-windows&#34;&gt;Moving windows&lt;/h3&gt;
&lt;p&gt;As I wrote in my &lt;a href=&#34;https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/&#34;&gt;Emacs and i3&lt;/a&gt; post, I want to have a rather specific behavior when moving windows (which does resemble i3 in some way):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if there is space in the required direction, move the Emacs window there;&lt;/li&gt;
&lt;li&gt;if there is no space in the required direction, but space in two orthogonal directions, move the Emacs window so that there is no more space in the orthogonal directions;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can&amp;rsquo;t say it&amp;rsquo;s better or worse than the built-in functionality or one provided by evil, but I&amp;rsquo;m used to it and I think it fits better for managing a lot of windows.&lt;/p&gt;
&lt;p&gt;So, first, we need a predicate that checks whether there is space in the given direction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-direction-exists-p&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Check if there is space in the direction DIR.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;Does not take the minibuffer into account.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-some&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;win&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-find-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;win&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;window-minibuffer-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;win&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;left&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;right&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;up&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;down&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a function to implement that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-move-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Move the current window in the direction DIR.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-find-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-direction&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-direction-exists-p&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;up&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;down&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;left&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;window-minibuffer-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;window-swap-states&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;selected-window&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-direction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-move-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My preferred keybindings for this part are, of course, &lt;code&gt;s-&amp;lt;H|J|K|L&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-input-global-keys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Moving windows&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-H&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-move-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;left&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-L&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-move-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-K&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-move-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;up&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;kbd&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;s-J&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-move-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;down&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;resizing-windows&#34;&gt;Resizing windows&lt;/h3&gt;
&lt;p&gt;I find this odd that there are different commands to resize tiling and floating windows.&lt;/p&gt;
&lt;video controls width=&#34;100%&#34;&gt;
&lt;source src=&#34;https://sqrtminusone.xyz/videos/exwm-resize-hydra.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;
&lt;p&gt;So let&amp;rsquo;s define one command to perform both resizes depending on the context:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-resize-value&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-resize-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Resize the current window in the direction DIR.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;DIR is either &amp;#39;height or &amp;#39;width, KIND is either &amp;#39;shrink or
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; &amp;#39;grow. VALUE is &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;`my/exwm-resize-value&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; by default.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;If the window is an EXWM floating window, execute the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;corresponding command from the exwm-layout group, execute the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;command from the evil-window group.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-resize-value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;is-exwm-floating&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;derived-mode-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm--floating-frame&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;is-exwm-floating&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;intern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;exwm-layout-&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;shrink&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;shrink&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;grow&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;enlarge&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-window&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-horizontally&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;intern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;evil-window&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;shrink&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-decrease-&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;grow&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;-increase-&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;is-exwm-floating&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function will call &lt;code&gt;exwm-layout-&amp;lt;shrink|grow&amp;gt;[-horizontally]&lt;/code&gt; for EXWM floating window and &lt;code&gt;evil-window-&amp;lt;decrease|increase&amp;gt;-&amp;lt;width|height&amp;gt;&lt;/code&gt; otherwise.&lt;/p&gt;
&lt;p&gt;This function can be bound to the required keybindings directly, but I prefer a hydra to emulate the i3 submode:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;defhydra&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-resize-hydra&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:color&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;pink&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:hint&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:foreign-keys&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;run&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;^Resize^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;_l_: Increase width _h_: Decrease width _j_: Increase height _k_: Decrease height
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;_=_: Balance &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;h&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-resize-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;shrink&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;j&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-resize-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;grow&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;k&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-resize-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;shrink&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;l&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-resize-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;grow&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;balance-windows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;quit&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:color&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;blue&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;splitting-windows&#34;&gt;Splitting windows&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;M-x evil-window-[v]split&lt;/code&gt; (bound to &lt;code&gt;C-w v&lt;/code&gt; and &lt;code&gt;C-w s&lt;/code&gt; by default) are the default evil command to do splits.&lt;/p&gt;
&lt;p&gt;One EXWM-related issue though is that by default doing such a split &amp;ldquo;copies&amp;rdquo; the current buffer to the new window. But as EXWM buffer cannot be &amp;ldquo;copied&amp;rdquo; like that, some other buffer is displayed in the split, and generally, that&amp;rsquo;s not a buffer I want.&lt;/p&gt;
&lt;p&gt;For instance, I prefer to have Chrome DevTools as a separate window. When I click &amp;ldquo;Inspect&amp;rdquo; on something, the DevTools window replaces my Ungoogled Chromium window. I press &lt;code&gt;C-w v&lt;/code&gt;, and most often I have something like &lt;code&gt;*scratch*&lt;/code&gt; buffer in the opened split instead of the previous Chromium window.&lt;/p&gt;
&lt;p&gt;To implement better behavior, I define the following advice:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-fill-other-window&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;_&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Open the most recently used buffer in the next window.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;major-mode&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-mode&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;next-window&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;get-buffer-window&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;other-exwm-buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cl-loop&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;other-buffer&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;persp-other-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;sort&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;persp-current-buffers&lt;/span&gt;) (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;_&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;other-buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;current-buffer&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;current-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;current-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buf&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;buffer-live-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;persp--make-ignore-buffer-rx&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;buffer-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buf&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;get-buffer-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buf&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;buf&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-exwm-buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;with-selected-window&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;next-window&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;switch-to-buffer&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-exwm-buffer&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is meant to be called after doing an either vertical or horizontal split, so it&amp;rsquo;s advised like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;evil-window-split&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-fill-other-window&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;evil-window-vsplit&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-fill-other-window&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works as follows. If the current buffer is an EXWM buffer and there are other windows open (that is, &lt;code&gt;(next-window)&lt;/code&gt; is not the current window), the function tries to find another suitable buffer to be opened in the split. And that also takes the perspectives into account, so buffers are searched only within the current perspective, and the buffer returned by &lt;code&gt;persp-other-buffer&lt;/code&gt; will be the top candidate.&lt;/p&gt;
&lt;h2 id=&#34;notes-on-floating-windows&#34;&gt;Notes on floating windows&lt;/h2&gt;
&lt;p&gt;Floating windows are not the most stable feature of EXWM.&lt;/p&gt;
&lt;p&gt;One story is that closing a floating window often screws up the current perspective, but that&amp;rsquo;s advised away by my &lt;code&gt;perspective-exwm-mode&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another is that these three settings (which are reasonably &lt;a href=&#34;https://github.com/daviwil/emacs-from-scratch/blob/5ebd390119a48cac6258843c7d5e570f4591fdd4/show-notes/Emacs-Desktop-04.org#mouse-warping&#34;&gt;recommended&lt;/a&gt; in the Emacs Desktop series) seem to increase chances of breaking the current EXWM session:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace-warp-cursor&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mouse-autoselect-window&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;focus-follows-mouse&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Occasionally they create a loop of mouse warps and focus changes. I found that disabling them just for the floating windows greatly stabilized that part:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/fix-exwm-floating-windows&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-workspace-warp-cursor&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;mouse-autoselect-window&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;focus-follows-mouse&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-floating-setup-hook&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/fix-exwm-floating-windows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, one particularly unfriendly app is the &lt;a href=&#34;https://zoom.us/&#34;&gt;Zoom app&lt;/a&gt;, which proudly creates a million various popups and still manages to break the EXWM sesssion. Fortunately, it can be used from a browser, which is what I advise to do.&lt;/p&gt;
&lt;h2 id=&#34;what-else-not-to-do&#34;&gt;What else not to do&lt;/h2&gt;
&lt;p&gt;A couple of final notes to make using EXWM a somewhat better experience.&lt;/p&gt;
&lt;p&gt;First, &lt;a href=&#34;https://github.com/daviwil/exwm/commit/7b1be884124711af0a02eac740bdb69446bc54cc&#34;&gt;this fix&lt;/a&gt; by David helped with &lt;a href=&#34;https://github.com/ch11ng/exwm/issues/842&#34;&gt;one case&lt;/a&gt; of EXWM freezing, which I managed to get into a few times.&lt;/p&gt;
&lt;p&gt;Second, do not run transients while there&amp;rsquo;s an active EXWM window in the workspace, especially if it&amp;rsquo;s it &lt;code&gt;char-mode&lt;/code&gt;. That seems to break the session quite securely.&lt;/p&gt;
&lt;p&gt;Third, running &lt;code&gt;shutdown&lt;/code&gt; or something like that in the console is not the greatest idea, because things like &lt;code&gt;kill-emacs-hook&lt;/code&gt; are not triggered in this case. For instance, EMMS history &amp;amp; elfeed databases are not saved.&lt;/p&gt;
&lt;h2 id=&#34;p-dot-s-dot&#34;&gt;P.S.&lt;/h2&gt;
&lt;p&gt;The way how characters aligned in my keybinding for EMMS is coincidental and does not carry any semantic value. The &lt;code&gt;a&lt;/code&gt; is for &amp;ldquo;app&amp;rdquo;, &lt;code&gt;s&lt;/code&gt; is because &lt;code&gt;e&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; were already taken by elfeed and notmuch, and the second &lt;code&gt;s&lt;/code&gt; is because it&amp;rsquo;s faster to press the same character twice.&lt;/p&gt;
</content>
</item>
<item>
<title>exwm-modeline</title>
<link>https://sqrtminusone.xyz/packages/exwm-modeline/</link>
<pubDate>Wed, 22 Dec 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/exwm-modeline/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/exwm-modeline&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/exwm-modeline-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A modeline segment to display exwm workspaces.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how it looks near the list of &lt;a href=&#34;https://github.com/nex3/perspective-el&#34;&gt;perspectives&lt;/a&gt; (the segment of the current package is to the left):
&lt;img src=&#34;https://sqrtminusone.xyz/exwm-modeline-img/screenshot.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;workspaces 0 and 5 do not have any X windows&lt;/li&gt;
&lt;li&gt;workspace 1 is the current workspace&lt;/li&gt;
&lt;li&gt;workspace 2 has at least one X window.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Supports &lt;code&gt;exwm-randr&lt;/code&gt; to display only workspaces related to the current monitor.&lt;/li&gt;
&lt;li&gt;Numbers are clickable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you usually install packages, I use &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/raxod502/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-modeline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then put a call to &lt;code&gt;exwm-modeline-mode&lt;/code&gt; somewhere after the moment when EXWM has been initialized, for instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-init-hook&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;exwm-modeline-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;Set &lt;code&gt;exwm-modeline-randr&lt;/code&gt; to nil to turn off filtering of workspaces by monitor.&lt;/p&gt;
&lt;p&gt;Set &lt;code&gt;exwm-modeline-short&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; display only the current workspace in the modeline.&lt;/p&gt;
&lt;p&gt;Set &lt;code&gt;exwm-modeline-display-urgent&lt;/code&gt; to nil to turn off displaying whether a workspace has an urgent window. This will significantly decrease the number of modeline updates, which may help with performance issues.&lt;/p&gt;
&lt;h2 id=&#34;credits&#34;&gt;Credits&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/nex3/perspective-el&#34;&gt;perspective.el&lt;/a&gt; by &lt;a href=&#34;https://github.com/nex3&#34;&gt;@nex3&lt;/a&gt; was extremely instructive on how to make a modeline segment individual to a particular frame and avoid recalculating it too often.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/elken/doom-modeline-exwm&#34;&gt;doom-modeline-exwm&lt;/a&gt; by &lt;a href=&#34;https://github.com/elken&#34;&gt;@elken&lt;/a&gt; also was a source of inspiration.&lt;/p&gt;
</content>
</item>
<item>
<title>perspective-exwm</title>
<link>https://sqrtminusone.xyz/packages/perspective-exwm/</link>
<pubDate>Wed, 01 Dec 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/perspective-exwm/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/perspective-exwm&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/perspective-exwm-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A couple of tricks and fixes to make using &lt;a href=&#34;https://github.com/ch11ng/exwm&#34;&gt;EXWM&lt;/a&gt; and &lt;a href=&#34;https://github.com/nex3/perspective-el&#34;&gt;perspective.el&lt;/a&gt; a better experience.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;This package is available on MELPA. Install it however you usually install packages, I use &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/raxod502/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or clone the repository, add the package to the &lt;code&gt;load-path&lt;/code&gt; and load it with &lt;code&gt;require&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The package provides a minor mode, &lt;code&gt;perspective-exwm-mode&lt;/code&gt;, which is meant to be loaded before &lt;code&gt;exwm-init&lt;/code&gt;. For instance, if you use &lt;code&gt;use-package&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm-init&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;usage-and-details&#34;&gt;Usage and details&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;perspective-exwm-mode&lt;/code&gt;&lt;br /&gt;
The mode does a couple of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;advises away a bug with half-killing the current perspective when closing a floating window. &lt;del&gt;I haven&amp;rsquo;t tested this as thoroughly&lt;/del&gt; I haven&amp;rsquo;t run into this issue for nearly a month, so it seems to be fixed. But there&amp;rsquo;s &lt;code&gt;M-x perspective-exwm-revive-perspectives&lt;/code&gt; if the problem arises anyway.&lt;/li&gt;
&lt;li&gt;fixes a bug with running &lt;code&gt;persp-set-buffer&lt;/code&gt; on an EXWM buffer that was moved between workspaces by advising &lt;code&gt;persp-buffer-in-other-p&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;fixes a bug with &lt;code&gt;persp-set-buffer&lt;/code&gt; copying all the perspectives from other workspaces to the current one.&lt;/li&gt;
&lt;li&gt;adjusts the name of the initial perspective in the new workspace. It tries to get the name from the &lt;code&gt;perspective-exwm-override-initial-name&lt;/code&gt; variable and fallbacks to &lt;code&gt;main-&amp;lt;index&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the last point, I have the following in my configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-override-initial-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;misc&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;core&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;browser&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;comms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;dev&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having distinct perspective names between frames also serves a purpose, because otherwise there are issues with multiple perspectives sharing the same scratch buffer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-cycle-exwm-buffers-forward&lt;/code&gt;, &lt;code&gt;perspective-exwm-cycle-exwm-buffers-backward&lt;/code&gt;&lt;br /&gt;
Cycle EXWM buffers in the current perspective.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/perspective-exwm-img/cycle-buffers.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The buffer highlighted in yellow is the current one, the buffer highlighted in blue is shown in another window of the perspective so it will be omitted from the cycle.&lt;/p&gt;
&lt;p&gt;Set &lt;code&gt;perspective-exwm-get-exwm-buffer-name&lt;/code&gt; to customize the displayed name, by default it&amp;rsquo;s &lt;code&gt;exwm-class-name&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-cycle-all-buffers-forward&lt;/code&gt;, &lt;code&gt;perspective-exwm-cycle-exwm-all-backward&lt;/code&gt;&lt;br /&gt;
The same as above, but not restricted to EXWM buffers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-switch-perspective&lt;/code&gt;&lt;br /&gt;
Select a perspective from the list of all perspectives on all workspaces.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/perspective-exwm-img/switch-perspective.png&#34;&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-copy-to-workspace&lt;/code&gt;&lt;br /&gt;
Copy the current perspective to another EXWM workspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-move-to-workspace&lt;/code&gt;&lt;br /&gt;
Move the current perspective to another EXWM workspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;perspective-exwm-assign-windows&lt;/code&gt;&lt;br /&gt;
A handy function to move the current window to a given workspace and/or perspective. Example usage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-configure-window&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-class-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Firefox&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Nightly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-assign-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:workspace-index&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:persp-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;browser&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Alacritty&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-assign-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:persp-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;term&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;VK&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Slack&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Discord&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;TelegramDesktop&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-assign-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:workspace-index&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:persp-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;comms&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-manage-finish-hook&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-configure-window&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;known-issues&#34;&gt;Known issues&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;perspective-exwm-move-to-workspace&lt;/code&gt; kills X windows in the perspective it tries to move. Have no idea how to fix this at the moment.&lt;/li&gt;
&lt;/ul&gt;
</content>
</item>
<item>
<title>pomm.el</title>
<link>https://sqrtminusone.xyz/packages/pomm/</link>
<pubDate>Fri, 05 Nov 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/pomm/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/pomm&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/pomm-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Implementation of &lt;a href=&#34;https://en.wikipedia.org/wiki/Pomodoro_Technique&#34;&gt;Pomodoro&lt;/a&gt; and &lt;a href=&#34;https://www.lesswrong.com/posts/RWu8eZqbwgB9zaerh/third-time-a-better-way-to-work&#34;&gt;Third Time&lt;/a&gt; techniques for Emacs.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/pomm-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Managing the timer with the excellent &lt;a href=&#34;https://github.com/magit/transient/blob/master/lisp/transient.el&#34;&gt;transient.el&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Persistent state between Emacs sessions.
The timer state isn&amp;rsquo;t reset if you close Emacs. If necessary, the state file can be synchronized between machines.&lt;/li&gt;
&lt;li&gt;History.
History of the timer can be stored in a CSV file. Eventually, I want to join this with &lt;a href=&#34;https://activitywatch.net/&#34;&gt;other activity data&lt;/a&gt; to see if the state of the timer changes how I use the computer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you usually install Emacs packages, e.g.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;M-x package-install pomm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My preferred way is &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight.el&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;pomm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;pomm&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;pomm-third-time&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or you can clone the repository, add the package to the &lt;code&gt;load-path&lt;/code&gt; and load it with &lt;code&gt;require&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The package requires Emacs 27.1 because the time API of the previous versions is kinda crazy and 27.1 has &lt;code&gt;time-convert&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;h3 id=&#34;pomodoro&#34;&gt;Pomodoro&lt;/h3&gt;
&lt;p&gt;Run &lt;code&gt;M-x pomm&lt;/code&gt; to open the transient buffer.&lt;/p&gt;
&lt;p&gt;The listed commands are rather self-descriptive and match the Pomodoro ideology.&lt;/p&gt;
&lt;p&gt;The timer can have 3 states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stopped&lt;/strong&gt;. Can be started with &amp;ldquo;s&amp;rdquo; or &lt;code&gt;M-x pomm-start&lt;/code&gt;. A new iteration of the timer will be started.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paused&lt;/strong&gt;. Can be continuted with &amp;ldquo;s&amp;rdquo; / &lt;code&gt;M-x pomm-start&lt;/code&gt; or stopped competely with &amp;ldquo;S&amp;rdquo; / &lt;code&gt;M-x pomm-stop&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Running&lt;/strong&gt;. Can be paused with &amp;ldquo;p&amp;rdquo; / &lt;code&gt;M-x pomm-pause&lt;/code&gt; or stopped with &amp;ldquo;S&amp;rdquo; / &lt;code&gt;M-x pomm-stop&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The state of the timer can be reset with &amp;ldquo;R&amp;rdquo; or &lt;code&gt;M-x pomm-reset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;u&amp;rdquo; updates the transient buffer. The update is manual because I didn&amp;rsquo;t figure out how to automate this, and I think this is not &lt;em&gt;really&lt;/em&gt; necessary.&lt;/p&gt;
&lt;p&gt;With &amp;ldquo;r&amp;rdquo; or &lt;code&gt;M-x pomm-set-context&lt;/code&gt; you can set the current &amp;ldquo;context&amp;rdquo;, that is some description of the task you are currently working on. This description will show up in history and in the csv file. Also, &lt;code&gt;M-x pomm-start-with-context&lt;/code&gt; will prompt for the context and then start the timer.&lt;/p&gt;
&lt;h3 id=&#34;third-time&#34;&gt;Third Time&lt;/h3&gt;
&lt;p&gt;Run &lt;code&gt;M-x pomm-third-time&lt;/code&gt; to open the transient buffer for the Third Time technique.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/pomm-img/screenshot-tt.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Essentially, the techique is designed aroud the formula:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time of break = 1/3 x Time of work.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I.e. you work as long as you want or need, and then take a break with the maximum duration &lt;code&gt;1/3&lt;/code&gt; of the time worked. If you take a shorter break, the remaining break time is saved and added to the next break within the same session. &lt;a href=&#34;https://www.lesswrong.com/posts/RWu8eZqbwgB9zaerh/third-time-a-better-way-to-work&#34;&gt;Here is a more detailed explanation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Third Time timer can have 2 states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stopped&lt;/strong&gt;. Can be started with &amp;ldquo;s&amp;rdquo; or &lt;code&gt;M-x pomm-third-time-start&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Running&lt;/strong&gt;. Can be stopped with &amp;ldquo;S&amp;rdquo; or &lt;code&gt;M-x pomm-third-time-stop&lt;/code&gt;. This resets the accumulated break time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use &amp;ldquo;b&amp;rdquo; or &lt;code&gt;M-x pomm-third-time-switch&lt;/code&gt; to switch the current period type (work or break). If the break time runs out, the timer automatically switches to work.&lt;/p&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;Some settings are available in the transient buffer, but you can customize the relevant variables to make them permanent. Check &lt;code&gt;M-x customize-group&lt;/code&gt; &lt;code&gt;pomm&lt;/code&gt; and &lt;code&gt;M-x customize-group pomm-third-time&lt;/code&gt; for more information.&lt;/p&gt;
&lt;h3 id=&#34;alerts&#34;&gt;Alerts&lt;/h3&gt;
&lt;p&gt;The package sends alerts via &lt;code&gt;alert.el&lt;/code&gt;. The default style of alert is a plain &lt;code&gt;message&lt;/code&gt;, but if you want an actual notification, set &lt;code&gt;alert-default-style&lt;/code&gt; accordingly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;alert-default-style&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;libnotify&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sounds&#34;&gt;Sounds&lt;/h3&gt;
&lt;p&gt;By default sounds are disabled. Set &lt;code&gt;pomm-audio-enabled&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; to toggle them. Set &lt;code&gt;pomm-audio-tick-enabled&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; if you want the ticking sound.&lt;/p&gt;
&lt;p&gt;This functionality needs &lt;code&gt;pomm-audio-player-executable&lt;/code&gt; to be set so that the program could be invoked like: &lt;code&gt;&amp;lt;executable&amp;gt; /path/to/sound.wav&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The package ships with some built-it sounds, which you can replace by customizing the &lt;code&gt;pomm-audio-files&lt;/code&gt; variable.&lt;/p&gt;
&lt;h3 id=&#34;modeline&#34;&gt;Modeline&lt;/h3&gt;
&lt;p&gt;If you want the timer to display in the modeline, activate the &lt;code&gt;pomm-mode-line-mode&lt;/code&gt; minor mode.&lt;/p&gt;
&lt;h3 id=&#34;polybar-module&#34;&gt;Polybar module&lt;/h3&gt;
&lt;p&gt;If you want to display the Pomodoro status in something like polybar, you can add the following lines to your config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-on-tick-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-update-mode-line-string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-on-status-changed-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-update-mode-line-string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create a script like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; ps -e | grep emacs &amp;gt;&amp;gt; /dev/null; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; emacsclient --eval &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(if (boundp &amp;#39;pomm-current-mode-line-string) pomm-current-mode-line-string \&amp;#34;\&amp;#34;) &amp;#34;&lt;/span&gt; | xargs &lt;span style=&#34;color:#008000&#34;&gt;echo&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And add a polybar module definition to your polybar config:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf-windows&#34; data-lang=&#34;conf-windows&#34;&gt;[module/pomm]
type = custom/script
exec = /home/pavel/bin/polybar/pomm.sh
interval = 1
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;state-file-location&#34;&gt;State file location&lt;/h3&gt;
&lt;p&gt;To implement pesistence between Emacs sessions, the package stores its state in the following files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pomm-state-file-location&lt;/code&gt;, &lt;code&gt;.emacs.d/pomm&lt;/code&gt; by default&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pomm-third-time-state-file-location&lt;/code&gt;, &lt;code&gt;/.emacs.d/pomm-third-time&lt;/code&gt; by default&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Set these paths however like.&lt;/p&gt;
&lt;h3 id=&#34;history&#34;&gt;History&lt;/h3&gt;
&lt;p&gt;If you set the &lt;code&gt;pomm-csv-history-file&lt;/code&gt; (and/or &lt;code&gt;pomm-third-time-csv-history-file&lt;/code&gt;) variable, the package will log its history in CSV format. Just keep in mind that the parent directory has to exist.&lt;/p&gt;
&lt;p&gt;The file for the Pomodoro technique has the following columns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status&lt;/code&gt; (&lt;code&gt;stopped&lt;/code&gt;, &lt;code&gt;paused&lt;/code&gt; or &lt;code&gt;running&lt;/code&gt;, according to the &lt;a href=&#34;#usage-1&#34;&gt;usage&lt;/a&gt; section)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kind&lt;/code&gt; (&lt;code&gt;work&lt;/code&gt;, &lt;code&gt;short-break&lt;/code&gt;, &lt;code&gt;long-break&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iteration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;context&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One for the Third Time technique has an extra column called &lt;code&gt;break-time-remaining&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A new entry is written after a particular state of the timer comes into being.&lt;/p&gt;
&lt;p&gt;To customize timestamp, set the &lt;code&gt;pomm-csv-history-file-timestamp-format&lt;/code&gt; variable. For example, for traditional &lt;code&gt;YYYY-MM-DD HH:mm:ss&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;pomm-csv-history-file-timestamp-format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%F %T&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The format is the same as in &lt;code&gt;format-time-string&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;alternatives&#34;&gt;Alternatives&lt;/h2&gt;
&lt;p&gt;There is a number of packages with a similar purpose, here is a rough comparison of features:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;3rd party integrations&lt;/th&gt;
&lt;th&gt;Control method (1)&lt;/th&gt;
&lt;th&gt;Persistent history&lt;/th&gt;
&lt;th&gt;Persistent state&lt;/th&gt;
&lt;th&gt;Notifications&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/SqrtMinusOne/pomm.el&#34;&gt;pomm.el&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;transient.el&lt;/td&gt;
&lt;td&gt;CSV&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;alert.el + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/marcinkoziej/org-pomodoro/tree/master&#34;&gt;org-pomodoro&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Org Mode!&lt;/td&gt;
&lt;td&gt;via Org commands&lt;/td&gt;
&lt;td&gt;via Org mode&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;alert.el + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/TatriX/pomidor/&#34;&gt;pomidor&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;self-cooked interactive buffer&lt;/td&gt;
&lt;td&gt;custom delimited format?&lt;/td&gt;
&lt;td&gt;+, but saving on-demand&lt;/td&gt;
&lt;td&gt;alert.el + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/baudtack/pomodoro.el/&#34;&gt;pomodoro.el&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;notifications.el + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/konr/tomatinho/&#34;&gt;tomatinho&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;self-cooked interactive buffer&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;message + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/ferfebles/redtick&#34;&gt;redtick&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;mode-line icon&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/abo-abo/gtk-pomodoro-indicator&#34;&gt;gtk-pomodoro-indicator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;GTK panel&lt;/td&gt;
&lt;td&gt;CLI&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-, but the program is independent from Emacs&lt;/td&gt;
&lt;td&gt;GTK notifications&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Be sure to check those out if this one doesn&amp;rsquo;t quite fit your workflow!&lt;/p&gt;
&lt;p&gt;(1) Means of timer control with exception of Emacs interactive commands&lt;/p&gt;
&lt;p&gt;Also take a look at &lt;a href=&#34;https://github.com/telotortium/org-pomodoro-third-time&#34;&gt;org-pomodoro-third-time&lt;/a&gt;, which adapts &lt;code&gt;org-pomodoro&lt;/code&gt; for the Third Time technique.&lt;/p&gt;
&lt;h2 id=&#34;p-dot-s-dot&#34;&gt;P.S.&lt;/h2&gt;
&lt;p&gt;The package name is not an abbreviation. I just hope it doesn&amp;rsquo;t mean something horrible in some language I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;The sounds are made by Mike Koening under &lt;a href=&#34;https://creativecommons.org/licenses/by/3.0/legalcode&#34;&gt;CC BY 3.0&lt;/a&gt;.&lt;/p&gt;
</content>
</item>
<item>
<title>Getting a consistent set of keybindings between i3 and Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</link>
<pubDate>Wed, 06 Oct 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</guid>
<content type="html">
&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;
&lt;p&gt;One advantage of EXWM for an Emacs user is that EXWM gives one set of keybindings to manage both Emacs windows and X windows. In every other WM, like my preferred &lt;a href=&#34;https://i3wm.org&#34;&gt;i3wm&lt;/a&gt;, two orthogonal keymaps seem to be necessary. But, as both programs are quite customizable, I want to see whether I can replicate at least some part of the EXWM goodness in i3.&lt;/p&gt;
&lt;p&gt;But why not just use EXWM? One key reason is that to my taste (and perhaps on my hardware) EXWM didn&amp;rsquo;t feel snappy enough. Also, I really like i3&amp;rsquo;s tree-based layout structure; I feel like it fits my workflow much better than anything else I tried, including the master/stack paradigm of &lt;a href=&#34;https://xmonad.org/&#34;&gt;XMonad&lt;/a&gt;, for instance.&lt;/p&gt;
&lt;p&gt;One common point of criticism of i3 is that it is not extensible enough, especially compared to WMs that are configured in an actual programing language, like the mentioned XMonad, &lt;a href=&#34;http://www.qtile.org/&#34;&gt;Qtile&lt;/a&gt;, &lt;a href=&#34;https://awesomewm.org/&#34;&gt;Awesome&lt;/a&gt;, etc. But I think i3&amp;rsquo;s extensibility is underappreciated, although the contents of this article may lie closer to the limits of how far one can go there.&lt;/p&gt;
&lt;p&gt;Here is a small demo of how it currently works:&lt;/p&gt;
&lt;video controls width=&#34;100%&#34;&gt;
&lt;source src=&#34;https://sqrtminusone.xyz/videos/i3-emacs-demo.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;
&lt;h2 id=&#34;emacs-integration&#34;&gt;Emacs integration&lt;/h2&gt;
&lt;p&gt;What I&amp;rsquo;m trying to do is actually quite simple, so I&amp;rsquo;m somewhat surprised I didn&amp;rsquo;t find anything similar on the Internet. But I didn&amp;rsquo;t look too hard.&lt;/p&gt;
&lt;p&gt;The basic idea is to launch a normal i3 command with &lt;code&gt;i3-msg&lt;/code&gt; in case the current window is not Emacs, otherwise pass that command to Emacs with &lt;code&gt;emacsclient&lt;/code&gt;. In Emacs, execute the command if possible, otherwise pass the command back to i3.&lt;/p&gt;
&lt;p&gt;This may seem like a lot of overhead, but I didn&amp;rsquo;t feel it even in the worst case (i3 -&amp;gt; Emacs -&amp;gt; i3), so at least in that regard, the interaction feels seamless. The only concern is that this command flow is vulnerable to Emacs getting stuck, but it is still much less of a problem than with EXWM.&lt;/p&gt;
&lt;p&gt;One interesting observation here is that Emacs windows and X windows are sort of one-level entities, so I can talk just about &amp;ldquo;windows&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;At any rate, we need a script to do the i3 -&amp;gt; Emacs part:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;[[&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;xdotool getactivewindow getwindowname&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;~ ^emacs&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;:.*&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;?@.* &lt;span style=&#34;color:#666&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(my/emacs-i3-integration \&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$@&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;\&amp;#34;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; emacsclient -e &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$command&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i3-msg &lt;span style=&#34;color:#19177c&#34;&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My &lt;a href=&#34;https://sqrtminusone.xyz/configs/emacs/#custom-frame-title&#34;&gt;Emacs frame title is set&lt;/a&gt; to &lt;code&gt;emacs[:&amp;lt;projectile-project-name&amp;gt;]@&amp;lt;hostname&amp;gt;&lt;/code&gt;, hence the regex. The script is saved to an executable called &lt;code&gt;emacs-i3-integration&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For this to work, we need to make sure that Emacs starts a server, so here is an expression to do just that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;after-init-hook&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;server-start&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function &lt;code&gt;my/emacs-i3-integration&lt;/code&gt;, which is an entrypoint for the i3 integration, will be defined a bit later.&lt;/p&gt;
&lt;p&gt;And here is a simple macro to do the Emacs -&amp;gt; i3 part:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;i3-msg&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;emacs-i3-windmove&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;i3-msg&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;handling-i3-commands&#34;&gt;Handling i3 commands&lt;/h2&gt;
&lt;p&gt;Now we have to handle the required set of i3 commands. It is worth noting here that I&amp;rsquo;m not trying to implement a general mechanism to apply i3 commands to Emacs, rather I&amp;rsquo;m implementing a small subset that I use in my i3 configuration and that maps reasonably to the Emacs concepts.&lt;/p&gt;
&lt;p&gt;Also, I use &lt;a href=&#34;https://github.com/emacs-evil/evil&#34;&gt;evil-mode&lt;/a&gt; and generally configure the software to have vim-style bindings where possible. So if you don&amp;rsquo;t use evil-mode you&amp;rsquo;d have to detangle the given functions from evil, but then, I guess, you do not use super+hjkl to manage windows either.&lt;/p&gt;
&lt;h3 id=&#34;focus&#34;&gt;&lt;code&gt;focus&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;First, for the &lt;code&gt;focus&lt;/code&gt; command I want to move to an Emacs window in the given direction if there is one, otherwise move to an X window in the same direction. Fortunately, i3 and &lt;code&gt;windmove&lt;/code&gt; have the same names for directions, so the function is rather straightforward.&lt;/p&gt;
&lt;p&gt;One caveat here is that the minibuffer is always the bottom-most Emacs window, so it is necessary to check for that as well.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-windmove&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-find-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;window-minibuffer-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;i3-msg&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;focus&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-do-window-select&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The relevant section of the i3 config looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+h &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration focus left
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+j &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration focus down
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+k &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration focus up
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+l &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration focus right
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Left &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration focus left
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Down &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration focus down
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Up &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration focus up
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Right &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration focus right
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Emacs function has to be called like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-windmove&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;move&#34;&gt;&lt;code&gt;move&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;For the &lt;code&gt;move&lt;/code&gt; command I want the following behavior:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if there is space in the required direction, move the Emacs window there;&lt;/li&gt;
&lt;li&gt;if there is no space in the required direction, but space in the orthogonal directions, move the Emacs window so that there is no more space in the orthogonal directions;&lt;/li&gt;
&lt;li&gt;otherwise, move an X window (which has to be an Emacs frame).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the first part, &lt;code&gt;window-swap-states&lt;/code&gt; with &lt;code&gt;windmove-find-other-window&lt;/code&gt; do well enough.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;evil-move-window&lt;/code&gt; works well for the second part. By itself it doesn&amp;rsquo;t behave quite like i3, for instance, &lt;code&gt;(evil-move-window &#39;right)&lt;/code&gt; in a three-column split would move the window from the far left side to the far right side (bypassing center). Hence the combination as described here.&lt;/p&gt;
&lt;p&gt;So here is a simple predicate which checks whether there is space in the given direction.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-direction-exists-p&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;some&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;win&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-find-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;win&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;window-minibuffer-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;win&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;left&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;right&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;up&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;down&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the implementation of the move command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-move-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;windmove-find-other-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-direction&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-direction-exists-p&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;up&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;down&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;left&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;right&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;window-minibuffer-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;window-swap-states&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;selected-window&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;other-window&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;other-direction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-move-window&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;i3-msg&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;move&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The relevant section of the i3 config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+h &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration move left
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+j &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration move down
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+k &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration move up
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+l &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration move right
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+Left &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration move left
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+Down &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration move down
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+Up &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration move up
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+Right &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration move right
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;resize-and-balance-windows&#34;&gt;&lt;code&gt;resize&lt;/code&gt; and balance windows&lt;/h3&gt;
&lt;p&gt;Next on the line are &lt;code&gt;resize grow&lt;/code&gt; and &lt;code&gt;resize shrink&lt;/code&gt;. &lt;code&gt;evil-window-&lt;/code&gt; functions do nicely for this task.&lt;/p&gt;
&lt;p&gt;This function also checks whether there is space to resize in the given direction with the help of the predicate defined above. The command is forwarded back to i3 if there is not.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-resize-window&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;one-window-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-direction-exists-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;i3-msg&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;resize&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%s px or %s ppt&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;kind&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;shrink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-window-decrease-width&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-window-decrease-height&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;grow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;width&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-window-increase-width&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;height&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-window-increase-height&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here I&amp;rsquo;m following the default configuration of i3, which creates a &amp;ldquo;submode&amp;rdquo; to resize windows.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mode &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;resize&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym h &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize shrink width &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym j &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize grow height &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym k &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize shrink height &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym l &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize grow width &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Shift+h &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize shrink width &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Shift+j &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize grow height &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Shift+k &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize shrink height &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Shift+l &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize grow width &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# same bindings, but for the arrow keys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Left &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize shrink width &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Down &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize grow height &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Up &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize shrink height &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Right &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize grow width &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;10&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Shift+Left &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize shrink width &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Shift+Down &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize grow height &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Shift+Up &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize shrink height &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Shift+Right &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration resize grow width &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; px or &lt;span style=&#34;color:#666&#34;&gt;100&lt;/span&gt; ppt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym equal &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; i3-emacs-balance-windows
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# back to normal: Enter or Escape&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Return mode &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bindsym Escape mode &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, Emacs has a built-in function called &lt;code&gt;balance-windows&lt;/code&gt;, but i3 doesn&amp;rsquo;t. Fortunately, there is a Python package called &lt;a href=&#34;https://github.com/atreyasha/i3-balance-workspace&#34;&gt;i3-balance-workspace&lt;/a&gt;, which performs a similar operation with i3&amp;rsquo;s IPC. If you use Guix as I do, I&amp;rsquo;ve written a &lt;a href=&#34;https://github.com/SqrtMinusOne/channel-q/blob/master/i3-balance-workspace.scm&#34;&gt;package definition&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So here is a small wrapper which calls &lt;code&gt;i3_balance_workspace&lt;/code&gt; and &lt;code&gt;M-x balance-windows&lt;/code&gt; if the current window is Emacs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;[[&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;xdotool getactivewindow getwindowname&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;~ ^emacs&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;:.*&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;?@.* &lt;span style=&#34;color:#666&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; emacsclient -e &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(balance-windows)&amp;#34;&lt;/span&gt; &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;i3_balance_workspace
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;layout-toggle-split&#34;&gt;&lt;code&gt;layout toggle split&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/emacsorphanage/transpose-frame&#34;&gt;transpose-frame&lt;/a&gt; is a package to &amp;ldquo;transpose&amp;rdquo; the current Emacs windows layout, which behaves somewhat similar to the &lt;code&gt;layout toggle split&lt;/code&gt; command in i3, so I&amp;rsquo;ll use it as well.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;transpose-frame&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;transpose-frame&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The i3 config for this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+e &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration layout toggle split
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-entrypoint&#34;&gt;The entrypoint&lt;/h3&gt;
&lt;p&gt;Finally, the entrypoint for the Emacs integration. In addition to the commands defined above, it processes &lt;code&gt;split&lt;/code&gt; and &lt;code&gt;kill&lt;/code&gt; commands and passes every other command back to i3.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-integration&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;bos&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;focus&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-windmove&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;elt&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;bos&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;move&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-move-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;elt&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;bos&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;resize&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/emacs-i3-resize-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;elt&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;elt&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-to-number&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;elt&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;layout toggle split&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;transpose-frame&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;split h&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-window-split&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;split v&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-window-vsplit&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;kill&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;evil-quit&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;-&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;i3-msg&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The rest of the relevant i3 config to do the splits:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+s &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration split h
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+v &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration split v
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And to kill the window:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+Shift+q &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; emacs-i3-integration &lt;span style=&#34;color:#008000&#34;&gt;kill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;switching-i3-tabs&#34;&gt;Switching i3 tabs&lt;/h3&gt;
&lt;p&gt;As I use i3&amp;rsquo;s tabbed layout quite extensively, occasionally I want to switch out of the Emacs tab with one button, and that&amp;rsquo;s where my integration may interfere.&lt;/p&gt;
&lt;p&gt;As a workaround, I found a small Rust program called &lt;a href=&#34;https://github.com/nikola-kocic/i3-switch-tabs&#34;&gt;i3-switch-tabs&lt;/a&gt;, which also communicates with i3 via its IPC to switch the top-level tab. I&amp;rsquo;ve written a &lt;a href=&#34;https://github.com/SqrtMinusOne/channel-q/blob/master/i3-switch-tabs.scm&#34;&gt;Guix package definition&lt;/a&gt; for that as well.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+period &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; i3-switch-tabs right
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bindsym &lt;span style=&#34;color:#19177c&#34;&gt;$mod&lt;/span&gt;+comma &lt;span style=&#34;color:#008000&#34;&gt;exec&lt;/span&gt; i3-switch-tabs left
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;So, how does all of that feel? Actually, I got used to that setup pretty quickly. Using &lt;code&gt;&amp;lt;s-Q&amp;gt;&lt;/code&gt; to quit windows and the &lt;code&gt;&amp;lt;s-r&amp;gt;&lt;/code&gt; submode to resize them is particularly nice. I&amp;rsquo;ve seen people making hydras in Emacs to do the latter.&lt;/p&gt;
&lt;p&gt;All of that would probably be easier to do in a WM which is configured in a programming language rather than in a self-cooked DSL, so I may try to replicate that somewhere else in an unknown time in the future. Meanwhile, it&amp;rsquo;s pretty good.&lt;/p&gt;
</content>
</item>
<item>
<title>My EMMS and elfeed setup</title>
<link>https://sqrtminusone.xyz/posts/2021-09-07-emms/</link>
<pubDate>Wed, 08 Sep 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-09-07-emms/</guid>
<content type="html">
&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/images/emms/emms-screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;This is the current state of my quest to live in Emacs, at least in part of reading RSS and music.&lt;/p&gt;
&lt;p&gt;Even before I lost my mind about customizing obscure keyboard-driven software, I tried Inoreader, self-hosted FreshRSS, and then newsboat from the RSS side and ncmpcpp+MPD from the audio player side. At some point, I got curious about whether I can do the same in Emacs.&lt;/p&gt;
&lt;p&gt;The respective emacs packages, elfeed and EMMS, proved somewhat tricky to set up, i.e. I had to figure out the source code in both cases. I even submitted a small patch to EMMS to make it parse my MPD library correctly.&lt;/p&gt;
&lt;p&gt;But in the end, only extensive customization capacities of Emacs enabled me to make a setup where these parts nicely come together and do more or less exactly what I want. However, this means there are a lot of degrees of freedom involved, so Ill try to cover the important parts and link to the original sources wherever possible.&lt;/p&gt;
&lt;p&gt;Id call it “workflow”, but the “work” part does not quite catch the point here.&lt;/p&gt;
&lt;h2 id=&#34;mpd&#34;&gt;MPD&lt;/h2&gt;
&lt;p&gt;So, we have to start somewhere.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.musicpd.org/&#34;&gt;MPD&lt;/a&gt; is a server for playing music, although it is usually hosted on the local machine, i.e. the one on which you intend to listen to music. There is &lt;a href=&#34;https://www.musicpd.org/clients/&#34;&gt;bunch of clients&lt;/a&gt; available (take a look at &lt;a href=&#34;https://github.com/ncmpcpp/ncmpcpp&#34;&gt;ncmpcpp&lt;/a&gt; is you like terminal-based apps), but here our point of interest is its integration with EMMS.&lt;/p&gt;
&lt;p&gt;While EMMS is capable of playing music without it, MPD has the advantage of being independent of Emacs. That means it won&amp;rsquo;t close if Emacs crashes and it can be controlled more easily with other means.&lt;/p&gt;
&lt;p&gt;MPD configuration is a pretty easy process. First, install MPD and &lt;a href=&#34;https://www.musicpd.org/clients/mpc/&#34;&gt;mpc&lt;/a&gt; (a minimal MPD CLI client) from your distribution&amp;rsquo;s package repository. After doing that, you&amp;rsquo;d have to create a config file at the location &lt;code&gt;~/.config/mpd/mpd.conf&lt;/code&gt;. Mine looks something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-vim&#34; data-lang=&#34;vim&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;music_directory &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/Music&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;playlist_directory &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.mpd/playlists&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;db_file &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.mpd/database&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;log_file &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.mpd/log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pid_file &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.mpd/pid&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;state_file &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.mpd/state&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sticker_file &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.mpd/sticker.sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;audio_output {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; type &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;pulse&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; name &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;My Pulse Output&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here &lt;code&gt;music_directory&lt;/code&gt; is, well, a directory in which MPD will look for music files. Take a look at &lt;a href=&#34;https://linux.die.net/man/5/mpd.conf&#34;&gt;man mpd.conf&lt;/a&gt; and &lt;a href=&#34;https://github.com/MusicPlayerDaemon/MPD/blob/master/doc/mpdconf.example&#34;&gt;the default config example&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;Because MPD is a daemon, it has to be started in order to work. The easiest way is to add &lt;code&gt;mpd&lt;/code&gt; to your init system, e.g. with GNU Shepherd:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scheme&#34; data-lang=&#34;scheme&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;define &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;mpd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;make&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;lt;service&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;:provides&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;mpd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;:respawn?&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;#t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;:start&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;make-forkexec-constructor&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mpd&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--no-daemon&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;:stop&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;make-kill-destructor&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also launch &lt;code&gt;mpd&lt;/code&gt; manually, as it will daemonize itself by default. To check if MPD is working, run &lt;code&gt;mpc status&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mpc status
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Take a look at &lt;a href=&#34;https://mpd.readthedocs.io/en/stable/user.html#configuration&#34;&gt;the official documentation&lt;/a&gt; for more information on this subject.&lt;/p&gt;
&lt;h3 id=&#34;music-directory&#34;&gt;Music directory&lt;/h3&gt;
&lt;p&gt;The next question after we&amp;rsquo;ve set up MPD is how to organize the music directory.&lt;/p&gt;
&lt;p&gt;MPD itself is not too concerned about the structure of your &lt;code&gt;music_directory&lt;/code&gt;, because it uses audio tags to classify the files. However, if you want to have album covers in EMMS, you need to have one folder per one album. Otherwise and in other respects, the structure can be arbitrary.&lt;/p&gt;
&lt;p&gt;So we need to tag the audio files. My favorite audio-tagging software is &lt;a href=&#34;https://picard.musicbrainz.org/&#34;&gt;MusicBrainz Picard&lt;/a&gt;, which can set tags automatically even if the file has no metadata at all, and move the file automatically according to the configuration. The aforementioned ncmpcpp also has a decent tag editor; finally, there is a simple &lt;a href=&#34;https://mutagen.readthedocs.io/en/latest/man/mid3v2.html&#34;&gt;mutagen-based CLI tool&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;emms&#34;&gt;EMMS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://www.gnu.org/software/emms/&#34;&gt;EMMS&lt;/a&gt; is the Emacs Multimedia System, a package that can get play stuff from various sources using various players. It is a part of Emacs, which means you can use the built-in version, but the git version has a few useful patches, so I advise using the latter.&lt;/p&gt;
&lt;p&gt;Install it however you usually install packages in Emacs; I use use-package + straight:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;setup-and-mpd-integration&#34;&gt;Setup &amp;amp; MPD integration&lt;/h3&gt;
&lt;p&gt;Now we have to configure EMMS. The following expressions have to be executed after EMMS is loaded, which means we can add them to the &lt;code&gt;:config&lt;/code&gt; section of the &lt;code&gt;use-package&lt;/code&gt; expression above.&lt;/p&gt;
&lt;p&gt;First, EMMS exposes a handy function that loads all the stable EMMS features. You can take a look at its source and pick the features you need or load everything like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-setup&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;emms-all&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we need to set up a directory for EMMS files and the required parameters for &lt;code&gt;emms-player-mpd&lt;/code&gt;. Note that &lt;code&gt;emms-player-mpd-music-directory&lt;/code&gt; should be set to the same value as &lt;code&gt;music_directory&lt;/code&gt; in &lt;code&gt;mpd.conf&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-source-file-default-directory&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/Music/&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-player-mpd-server-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-player-mpd-server-port&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;6600&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-player-mpd-music-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/Music&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the required functions to EMMS lists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-info-functions&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-info-mpd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-player-list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-player-mpd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can connect EMMS to MPD. For some reason, executing this function stops the MPD playback, but it is not a big issue because it has to be executed only once.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;emms-player-mpd-connect&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The last thing we may want is to link EMMS playlist clearing to MPD playlist clearing. I&amp;rsquo;m not sure how this interacts with MPD&amp;rsquo;s own playlists because I don&amp;rsquo;t use them, so you may need to watch out here if you do.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-playlist-cleared-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-player-mpd-clear&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;usage&#34;&gt;Usage&lt;/h3&gt;
&lt;p&gt;One rough edge of EMMS &amp;amp; MPD integration is that EMMS and MPD have separate libraries and playlists.&lt;/p&gt;
&lt;p&gt;So, first we have to populate the MPD library with &lt;code&gt;M-x emms-player-mpd-update-all&lt;/code&gt;. This operation is executed asynchronously by MPD and may take a few minutes for the first run. The subsequent runs are much faster. You can do the same by invoking &lt;code&gt;mpc update&lt;/code&gt; from the command line.&lt;/p&gt;
&lt;p&gt;Second, we have to populate the EMMS library (cache) from the MPD library. To do that, run &lt;code&gt;M-x emms-cache-set-all-from-mpd&lt;/code&gt;. If something went wrong with the EMMS cache, you always can clean it with &lt;code&gt;M-x emms-cache-reset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After this is done, we can finally play music! To do that, run &lt;code&gt;M-x emms-browser&lt;/code&gt;. The left window should have the EMMS browser buffer with the loaded library, the right one should contain (as for now empty) playlist.&lt;/p&gt;
&lt;p&gt;In the browser we can use the following commands to add elements to the playlist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-x emms-browser-toggle-subitems&lt;/code&gt; (&lt;code&gt;&amp;lt;tab&amp;gt;&lt;/code&gt; in evil, &lt;code&gt;SPC&lt;/code&gt; in vanilla) to open/close the element under cursor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x emms-browser-add-tracks&lt;/code&gt; (&lt;code&gt;RET&lt;/code&gt; in both styles) to add the element under the cursor to the playlist&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, we have a few tracks in the EMMS playlist, but they are not in the MPD playlist yet.&lt;/p&gt;
&lt;p&gt;In the EMMS playlist buffer, &lt;code&gt;M-x emms-playlist-mode-play-smart&lt;/code&gt; (&lt;code&gt;RET&lt;/code&gt;) will sync the playlists and start playing the song under the cursor. Also, use&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-x emms-playlist-mode-kill-track&lt;/code&gt; (&lt;code&gt;D&lt;/code&gt;) to remove the element under cursor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x emms-playlist-clear&lt;/code&gt; (&lt;code&gt;C&lt;/code&gt;) to clear the playlist. With the hook from the previous section this should also clear the MPD playlist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take a look at the &lt;a href=&#34;https://www.gnu.org/software/emms/manual/&#34;&gt;EMMS manual&lt;/a&gt; for more information, including sections about &lt;a href=&#34;https://www.gnu.org/software/emms/manual/#Interactive-Playlists&#34;&gt;playlist&lt;/a&gt; and &lt;a href=&#34;https://www.gnu.org/software/emms/manual/#The-Browser&#34;&gt;browser.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;fetching-lyrics&#34;&gt;Fetching lyrics&lt;/h3&gt;
&lt;p&gt;One feature of ncmpcpp I was missing here is fetching lyrics, so I&amp;rsquo;ve written a small package to do just that.&lt;/p&gt;
&lt;p&gt;Debugging the package turned out to be quite funny because apparently, there is no way around parsing HTML with this task. So I&amp;rsquo;ve chosen genius.com as the source, but the site turned out to provide different versions of itself (with different DOMs!) to different users.&lt;/p&gt;
&lt;p&gt;At any rate, I&amp;rsquo;ve processed the cases I found, and it seems to be working, at least for me. To use the package, &lt;a href=&#34;https://genius.com/api-clients/new&#34;&gt;get the API key&lt;/a&gt; from Genius and install it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;lyrics-fetcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;lyrics-fetcher-genius-access-token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;password-store-get&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;My_Online/APIs/genius.com&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To fetch lyrics for the current playing EMMS song, run &lt;code&gt;M-x lyrics-fetcher-show-lyrics&lt;/code&gt;. Or run &lt;code&gt;M-x lyrics-fetcher-emms-browser-show-at-point&lt;/code&gt; to fetch data for the current point in the EMMS browser. See &lt;a href=&#34;https://github.com/SqrtMinusOne/lyrics-fetcher.el&#34;&gt;the package homepage&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3 id=&#34;album-covers&#34;&gt;Album covers&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve mentioned above that EMMS supports displaying album covers.&lt;/p&gt;
&lt;p&gt;For this to work, it is necessary to have one album per one folder. By default the cover image should be saved to images named &lt;code&gt;cover_small&lt;/code&gt; (100x100 recommended), &lt;code&gt;cover_medium&lt;/code&gt; (200x200 recommended) and &lt;code&gt;cover_large&lt;/code&gt;. The small version is to be displayed in the EMMS browser, the medium one in the playlist.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not required for images to be exactly of these sizes, but they definitely should be of one size across different albums to look nice in the interface.&lt;/p&gt;
&lt;p&gt;You can resize images with ImageMagick with commands like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;convert cover.jpg -resize 100x100^ -gravity Center -extent 100x100 cover_small.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;convert cover.jpg -resize 200x200^ -gravity Center -extent 200x200 cover_medium.jpg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;lyrics-fetcher&lt;/code&gt; can (try to) do this automatically by downloading the cover from genius.com with &lt;code&gt;M-x lyrics-fetcher-emms-browser-fetch-covers-at-point&lt;/code&gt; in EMMS browser.&lt;/p&gt;
&lt;h2 id=&#34;mpv-and-youtube&#34;&gt;MPV and YouTube&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://mpv.io/&#34;&gt;MPV&lt;/a&gt; is an extensible media player, which integrates with &lt;a href=&#34;https://github.com/ytdl-org/youtube-dl&#34;&gt;youtube-dl&lt;/a&gt; and is controllable by EMMS, thus quite fitting for this setup.&lt;/p&gt;
&lt;h3 id=&#34;mpv-and-youtube-dl&#34;&gt;MPV and youtube-dl&lt;/h3&gt;
&lt;p&gt;First, install both &lt;code&gt;mpv&lt;/code&gt; and &lt;code&gt;youtube-dl&lt;/code&gt; from your distribution&amp;rsquo;s package repository.&lt;/p&gt;
&lt;p&gt;Then we can add another player to the list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-player-list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;emms-player-mpv&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;EMMS determines which player to use by a regexp. &lt;code&gt;emms-player-mpd&lt;/code&gt; sets the default regexp from MPD&amp;rsquo;s diagnostic output so that regex opens basically everything, including videos, HTTPS links, etc. That is fine if MPD is the only player in EMMS, but as we want to use MPV as well, we need to override the regexes.&lt;/p&gt;
&lt;p&gt;MPD regexp can look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;emms-player-set&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-player-mpd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;regex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms-player-simple-regexp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;m3u&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;ogg&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;flac&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mp3&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;wav&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mod&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;au&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;aiff&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a regexp for MPV to open videos and youtube URLs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;emms-player-set&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-player-mpv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;regex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#666&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;https://&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nonl&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;youtube.com&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nonl&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;? &lt;/span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;https://&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;http://&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;nonl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;regexp&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eval&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms-player-simple-regexp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mp4&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mov&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;wmv&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;webm&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;flv&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;avi&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mkv&amp;#34;&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, by default youtube-dl plays the video in the best possible quality, which may be pretty high. To have some control over it, we can modify the &lt;code&gt;--ytdl-format&lt;/code&gt; key in the &lt;code&gt;emms-player-mpv-parameters&lt;/code&gt; variable. I&amp;rsquo;ve come up with the following solution:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/youtube-dl-quality-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;bestvideo[height&amp;lt;=720]+bestaudio/best[height&amp;lt;=720]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;bestvideo[height&amp;lt;=480]+bestaudio/best[height&amp;lt;=480]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;bestvideo[height&amp;lt;=1080]+bestaudio/best[height&amp;lt;=1080]&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/default-emms-player-mpv-parameters&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--quiet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--really-quiet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--no-audio-display&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/set-emms-mpd-youtube-quality&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;quality&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;P&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;quality&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;quality&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;completing-read&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Quality: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/youtube-dl-quality-list&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-player-mpv-parameters&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/default-emms-player-mpv-parameters&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--ytdl-format=%s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;quality&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;my/set-emms-mpd-youtube-quality&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/youtube-dl-quality-list&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run &lt;code&gt;M-x my/set-emms-mpd-youtube-quality&lt;/code&gt; to pick the required quality. Take a look at &lt;a href=&#34;https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection&#34;&gt;youtube-dl docs&lt;/a&gt; for more information about the format selection.&lt;/p&gt;
&lt;p&gt;Now &lt;code&gt;M-x emms-add-url&lt;/code&gt; should work on YouTube URLs just fine. Just keep in mind that it will only add the URL to the playlist, not play it right away.&lt;/p&gt;
&lt;h3 id=&#34;cleanup-emms-cache&#34;&gt;Cleanup EMMS cache&lt;/h3&gt;
&lt;p&gt;All the added URLs stay in the EMMS cache after being played. We probably don&amp;rsquo;t want them to remain there, so here is a function to remove URLs from the EMMS cache.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/emms-cleanup-urls&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;keys-to-delete&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;()))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;maphash&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;assoc&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;type&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value&lt;/span&gt;)) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;keys-to-delete&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-cache-db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;keys-to-delete&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;remhash&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-cache-db&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emms-cache-dirty&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;youtube-rss&#34;&gt;YouTube RSS&lt;/h2&gt;
&lt;h3 id=&#34;where-to-get-urls&#34;&gt;Where to get URLs?&lt;/h3&gt;
&lt;p&gt;So, we are able to watch YouTube videos by URLs, but where to get URLs from? A natural solution is to use &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt; and RSS feeds.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tried a bunch of options to get feeds for YouTube channels. The first one is &lt;a href=&#34;https://api.invidious.io/&#34;&gt;Invidious&lt;/a&gt;, a FOSS YouTube frontend. The problem here is that various instances I tried weren&amp;rsquo;t particularly stable (at least when I was using them) and hosting the thing by myself would be overkill. And switching instances is causing duplicate entries in the Elfeed DB.&lt;/p&gt;
&lt;p&gt;The second option is to use YouTube&amp;rsquo;s own RSS. The feed URL looks like &lt;code&gt;https://www.youtube.com/feeds/videos.xml?channel_id=&amp;lt;CHANNEL_ID&amp;gt;=&lt;/code&gt;. &lt;a href=&#34;https://stackoverflow.com/questions/14366648/how-can-i-get-a-channel-id-from-youtube&#34;&gt;Here are&lt;/a&gt; a couple of options of figuring out &lt;code&gt;CHANNEL_ID&lt;/code&gt; in case it&amp;rsquo;s not easily available. The problem with YouTube RSS is that it uses fields that are not supported by elfeed, so the feed entry lacks a preview and description.&lt;/p&gt;
&lt;p&gt;As my workaround, I&amp;rsquo;ve written a small &lt;a href=&#34;https://github.com/SqrtMinusOne/yt-rss&#34;&gt;web-server&lt;/a&gt; which converts an RSS feed from YouTube to an elfeed-compatible Atom feed. It doesn&amp;rsquo;t do much, so you can just download the thing and launch it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/SqrtMinusOne/yt-rss.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ./yt-rss
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gunicorn main:app
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A feed for a particular channel will be available at&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;http://localhost:8000/&amp;lt;channel_id&amp;gt;?token=&amp;lt;token&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where &lt;code&gt;&amp;lt;token&amp;gt;&lt;/code&gt; is set in &lt;code&gt;.env&lt;/code&gt; file to the default value of &lt;code&gt;12345&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;elfeed&#34;&gt;Elfeed&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;Elfeed&lt;/a&gt; is an Emacs Atom &amp;amp; RSS reader. It&amp;rsquo;s a pretty popular package with lots of information written over the years, so I&amp;rsquo;ll cover just my particular setup.&lt;/p&gt;
&lt;p&gt;My elfeed config, sans keybindings, looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-db-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.elfeed&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-enclosure-default-dir&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/Downloads&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-insert-html&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:around&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;shr-use-fonts&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;r&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The advice there forces elfeed to use monospace fonts in the show buffer.&lt;/p&gt;
&lt;p&gt;I also use &lt;a href=&#34;https://github.com/remyhonig/elfeed-org&#34;&gt;elfeed-org&lt;/a&gt;, which gives an option to store the feed config in an &lt;code&gt;.org&lt;/code&gt; file instead of a variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-org&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;rmh-elfeed-org-files&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.emacs.d/elfeed.org&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-org&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, however you&amp;rsquo;ve got URLs for YouTube channels, put them into elfeed.&lt;/p&gt;
&lt;p&gt;To fetch the feeds, open elfeed with &lt;code&gt;M-x elfeed&lt;/code&gt; and run &lt;code&gt;M-x elfeed-search-fetch&lt;/code&gt; in the search buffer. And as usual, take a look at &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;the package documentation&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;To help with navigating through the long list of entries, I&amp;rsquo;ve made the following function to narrow the search buffer to the feed of the entry under cursor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-search-filter-source&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Filter elfeed search buffer by the feed under cursor.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-search-selected&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:ignore-region&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-search-set-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;@6-months-ago &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;+unread &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;?&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;not-newline&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-feed-url&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-feed&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So I mostly alternate between &lt;code&gt;M-x my/elfeed-search-filter-source&lt;/code&gt; and &lt;code&gt;M-x elfeed-search-clear-filter&lt;/code&gt;. I tag the entries which I want to watch later with &lt;code&gt;+later&lt;/code&gt;, and add the ones I want to watch right now to the playlist.&lt;/p&gt;
&lt;h3 id=&#34;integrating-with-emms&#34;&gt;Integrating with EMMS&lt;/h3&gt;
&lt;p&gt;Finally, here&amp;rsquo;s the solution I came up with to add an entry from elfeed to the EMMS playlist. First, we&amp;rsquo;ve got to get a URL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/get-youtube-url&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;link&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;watch-id&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cadr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;assoc&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;watch?v&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url-parse-query-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;substring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url-generic-parse-url&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;link&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;https://www.youtube.com/watch?v=&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;watch-id&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function is intended to work with both Invidious and YouTube RSS feeds. Of course, it will require some adaptation if you want to watch channels from something like PeerTube or Odysee.&lt;/p&gt;
&lt;p&gt;The easiest way to put the URL to the playlist is to define a new source for EMMS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;define-emms-source&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;track&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms-track&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;url&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/get-youtube-url&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-link&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms-track-set&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;track&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;info-title&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-title&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms-playlist-insert-track&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;track&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because &lt;code&gt;define-emms-source&lt;/code&gt; is an EMMS macro, the code block above has to be evaluated with EMMS loaded. E.g. you can wrap it into &lt;code&gt;(with-eval-after-load &#39;emms ...)&lt;/code&gt; or put in the &lt;code&gt;:config&lt;/code&gt; section.&lt;/p&gt;
&lt;p&gt;The macro defines a bunch of functions to work with the source, which we can use in another function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-add-emms-youtube&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms-add-elfeed&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-tag&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-entry&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;watched&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-show-refresh&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, calling &lt;code&gt;M-x my/elfeed-add-emms-youtube&lt;/code&gt; in the &lt;code&gt;*elfeed-show*&lt;/code&gt; buffer will add the correct URL to the playlist and tag the entry with &lt;code&gt;+watched&lt;/code&gt;. I&amp;rsquo;ve bound the function to &lt;code&gt;gm&lt;/code&gt;.&lt;/p&gt;
</content>
</item>
<item>
<title>lyrics-fetcher.el</title>
<link>https://sqrtminusone.xyz/packages/lyrics-fetcher/</link>
<pubDate>Sat, 14 Aug 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/lyrics-fetcher/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/lyrics-fetcher&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/lyrics-fetcher-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A package to fetch song lyrics and album covers. Integrates with EMMS.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/lyrics-fetcher-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The available backends are &lt;a href=&#34;https://genius.com&#34;&gt;genius.com&lt;/a&gt; and &lt;a href=&#34;https://music.163.com/&#34;&gt;music.163.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, I prefer &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;lyrics-fetcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Install &lt;a href=&#34;https://imagemagick.org/index.php&#34;&gt;imagemagick&lt;/a&gt; if you want to download covers.&lt;/p&gt;
&lt;p&gt;If you want to use the genius backend, you have to set &lt;a href=&#34;https://docs.genius.com/&#34;&gt;genius.com&lt;/a&gt; client access token. To do that, &lt;a href=&#34;https://genius.com/api-clients/new&#34;&gt;create a new client,&lt;/a&gt; click &amp;ldquo;Generate Access Token&amp;rdquo; and put the result to the &lt;code&gt;lyrics-fetcher-genius-access-token&lt;/code&gt; variable. I do this with password-store:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;lyrics-fetcher-genius-access-token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;password-store-get&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;My_Online/APIs/genius.com&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But of course, you can just hardcode the string.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Available commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-show-lyrics&lt;/code&gt; - show lyrics for the current playing track.&lt;/p&gt;
&lt;p&gt;The resulting lyric files are saved to the &lt;code&gt;lyrics-fetcher-lyrics-folder&lt;/code&gt; and have the &lt;code&gt;lyrics-fetcher-lyrics-file-extension&lt;/code&gt; extension. The folder will be created if it doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;p&gt;By default, the function opens an already saved lyrics file if one exists, otherwise tries to fetch the lyrics.&lt;/p&gt;
&lt;p&gt;If called with &lt;code&gt;C-u&lt;/code&gt;, then tries to fetch the text regardless of the latter.&lt;/p&gt;
&lt;p&gt;If called with &lt;code&gt;C-u C-u&lt;/code&gt;, prompts the user to select a matching song. That is helpful when there are multiple songs with similar names, and the top one isn&amp;rsquo;t the right one.&lt;/p&gt;
&lt;p&gt;If called with &lt;code&gt;C-u C-u C-u&lt;/code&gt;, edit the search query in minibuffer before sending. This is helpful when there is extra information in the song title which prevents the API from finding the song.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-show-lyrics-query&lt;/code&gt; - fetch lyrics by a text query.&lt;/p&gt;
&lt;p&gt;Modified by &lt;code&gt;C-u&lt;/code&gt; the same way as &lt;code&gt;lyrics-fetcher-show-lyrics&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-use-backend&lt;/code&gt; - select a backend to use.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;EMMS integration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-emms-browser-show-at-point&lt;/code&gt; - fetch data for the current point in EMMS browser.&lt;/p&gt;
&lt;p&gt;If the point contains just one song, it will be fetched the usual way and lyrics will be shown upon successful completion.&lt;/p&gt;
&lt;p&gt;If the point contains many songs (e.g. it&amp;rsquo;s an album), the lyrics will be fetched consequentially for every song. The process then will stop at the first failure.&lt;/p&gt;
&lt;p&gt;Modified by &lt;code&gt;C-u&lt;/code&gt; the same way as &lt;code&gt;lyrics-fetcher-show-lyrics&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-emms-browser-fetch-covers-at-point&lt;/code&gt; - fetch album covers for the current point in the EMMS browser.&lt;/p&gt;
&lt;p&gt;This functionality requires songs&amp;rsquo; directories to be grouped by albums, i.e. one album per one folder.&lt;/p&gt;
&lt;p&gt;The files will be saved to the folder with names like &amp;ldquo;cover_small.jpg&amp;rdquo;, &amp;ldquo;cover_med.jpg&amp;rdquo;, &amp;ldquo;cover_large.jpg&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;You can customize the sizes via the &lt;code&gt;lyrics-fetcher-small-cover-size&lt;/code&gt; and &lt;code&gt;lyrics-fetcher-medium-cover-size&lt;/code&gt; variables.&lt;/p&gt;
&lt;p&gt;Modified by &lt;code&gt;C-u&lt;/code&gt; the same way as &lt;code&gt;lyrics-fetcher-show-lyrics&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-emms-browser-open-large-cover-at-point&lt;/code&gt; - open large_cover for the current point in EMMS browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-lyrics-catchup&lt;/code&gt; - feed the LRC file for the current track to EMMS.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lyric view mode keybindings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;q&lt;/code&gt; - close the lyrics buffer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt; - refetch the lyrics in the buffer&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;available-backends&#34;&gt;Available backends&lt;/h2&gt;
&lt;p&gt;As of now, the available backends are &lt;code&gt;genius&lt;/code&gt; and &lt;code&gt;neteasecloud&lt;/code&gt; (thanks &lt;a href=&#34;https://github.com/Elilif&#34;&gt;@Elilif&lt;/a&gt;). Backends can be switched with &lt;code&gt;M-x lyrics-fetcher-use-backend&lt;/code&gt;, or from the Lisp code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;lyrics-fetcher-use-backend&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;neteasecloud&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;genius&lt;/code&gt; backend fetches lyrics in a simple text format.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;neteasecloud&lt;/code&gt; fetches in the &lt;a href=&#34;https://en.wikipedia.org/wiki/LRC_(file_format)&#34;&gt;LRC&lt;/a&gt; format, which contains timestamps for each line of the lyrics text.&lt;/p&gt;
&lt;p&gt;LRC files can also be read by &lt;code&gt;emms-lyrics&lt;/code&gt;. &lt;code&gt;lyrics-fetcher-use-backend&lt;/code&gt; sets up &lt;code&gt;lyrics-fetcher&lt;/code&gt; and EMMS variables so that EMMS could see the lyrics, downloaded by &lt;code&gt;lyrics-fetcher&lt;/code&gt;. Running &lt;code&gt;M-x emms-lyrics&lt;/code&gt; then should enable lyric display for newly played tracks, or you can run &lt;code&gt;M-x lyrics-fetcher-lyrics-catchup&lt;/code&gt; to manually feed the current LRC file to EMMS.&lt;/p&gt;
&lt;h2 id=&#34;customization-and-extension&#34;&gt;Customization and extension&lt;/h2&gt;
&lt;h3 id=&#34;lyrics-file-naming-and-location&#34;&gt;Lyrics file naming and location&lt;/h3&gt;
&lt;p&gt;As was outlined above, lyrics files are saved to &lt;code&gt;lyrics-fetcher-lyrics-folder&lt;/code&gt; and have an extension set in &lt;code&gt;lyrics-fetcher-lyrics-file-extension&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Take a look at the &lt;code&gt;lyrics-fetcher-format-song-name-method&lt;/code&gt; and &lt;code&gt;lyrics-fetcher-format-file-name-method&lt;/code&gt; variables if you want to customize the lyrics buffer and file naming.&lt;/p&gt;
&lt;p&gt;Also note that integration with &lt;code&gt;emms-lyrics&lt;/code&gt; requires these variables to be set with &lt;code&gt;lyrics-fetcher-use-backend&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;using-other-player-than-emms&#34;&gt;Using other player than EMMS&lt;/h3&gt;
&lt;p&gt;To use another player, customize &lt;code&gt;lyrics-fetcher-current-track-method&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This variable contains a function that returns the current playing track. The return format has to be either a string or (recommended) an EMMS-like alist, which has to have the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;info-artist&lt;/code&gt; or &lt;code&gt;info-albumartist&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;info-title&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;adding-another-backend&#34;&gt;Adding another backend&lt;/h3&gt;
&lt;p&gt;A function to perform the lyric fetching is set in &lt;code&gt;lyrics-fetcher-fetch-method&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The function has to receive 3 arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;track&lt;/code&gt; - a string or alist, as outlined &lt;a href=&#34;#using-other-player-than-emms-1&#34;&gt;above&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; - the function which has to be called with the resulting lyrics string&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sync&lt;/code&gt; - if non-nil, inquire the user about the possible choices. This is called &lt;code&gt;sync&lt;/code&gt; because then it is reasonable to perform the request synchronously, as otherwise, it won&amp;rsquo;t be nice to suddenly throw a prompt at the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The album cover fetching is similar. The corresponding function is set in &lt;code&gt;lyrics-fetcher-download-cover-method&lt;/code&gt; and has to receive the following parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;track&lt;/code&gt; - as above&lt;/li&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; - has to be called with the path to the resulting file. This file should be named &lt;code&gt;cover_large.&amp;lt;extension&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;folder&lt;/code&gt; - where the file has to be put&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sync&lt;/code&gt; - as above.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first argument is &lt;code&gt;track&lt;/code&gt; because in EMMS all the required information is stored in tracks, and album data is deduced from tracks. So this package just takes a sample track in the album.&lt;/p&gt;
&lt;h2 id=&#34;troubleshooting&#34;&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve noticed that Genius can give pages with different DOMs to different people. If you have an empty buffer instead of lyrics, please attach the &lt;code&gt;curl-cookie-jar&lt;/code&gt; file to the issue. It usually resides in &lt;code&gt;.emacs.d/request&lt;/code&gt;.&lt;/p&gt;
</content>
</item>
<item>
<title>Replacing Jupyter Notebook with Org Mode</title>
<link>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</link>
<pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-05-01-org-python/</guid>
<content type="html">
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/images/org-python/org-python-screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;why&#34;&gt;Why?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://jupyter-notebook.readthedocs.io/en/stable/&#34;&gt;Jupyter Notebook&lt;/a&gt; and its successor &lt;a href=&#34;https://jupyterlab.readthedocs.io/en/stable/&#34;&gt;Jupyter Lab&lt;/a&gt; providing an interactive development environment for many programming languages are in lots of ways great pieces of software.&lt;/p&gt;
&lt;p&gt;But while I was using the former, and then the latter, I was also an as-full-time-as-one-can-get NeoVim user. &amp;ldquo;As one can get&amp;rdquo; is because, of course, there is no sensible way to extend the NeoVim editing experience to the Jupyter ecosystem.&lt;/p&gt;
&lt;p&gt;A possibility for change appeared with my discovery of Emacs not so long ago. Emacs, a substantially more extensible piece of software, potentially can be used for the mentioned kind of programming. So I decided to try.&lt;/p&gt;
&lt;p&gt;Sometime past that decision, it&amp;rsquo;s time to wrap up the results. To start with, I&amp;rsquo;ll briefly discuss the pros &amp;amp; cons of using Org mode rather than Jupyter Notebook/Lab. Here is my list of advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Emacs, at least for me, is way more comfortable to use than a browser&lt;/li&gt;
&lt;li&gt;Org mode allows using multiple programming languages in one file or multiple sessions with one programming language&lt;/li&gt;
&lt;li&gt;Richer &amp;amp; way more flexible export &amp;amp; tangle capacities&lt;/li&gt;
&lt;li&gt;More reasonable version control because org mode is just plain text, contrary to Jupyter&amp;rsquo;s JSONs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first point deserves to be spelled out with more detail. To start with, Emacs is an objectively better text editor than Jupyter, as Emacs offers a considerable superset of Jupyter&amp;rsquo;s features concerning just writing and editing text. The farthest one can go with Jupyter Lab is to install a vim emulation plugin, which still isn&amp;rsquo;t as good as Evil mode.&lt;/p&gt;
&lt;p&gt;The fact that Emacs can be used for different purposes also helps. For instance, I often write LaTeX documents, which are loosely based on the nearby code, e.g. using some generated charts or tables. Switching an Emacs buffer is easier than switching between Emacs and browser, not to mention that Emacs buffers usually have the same set of keybindings.&lt;/p&gt;
&lt;p&gt;Emacs&amp;rsquo; buffer management system, which is good enough for a window manager, is barely comparable to the tabs of Jupyter Lab. And so on.&lt;/p&gt;
&lt;p&gt;As for why one may want to use Jupyter instead, here is my take on cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Potential performance issues&lt;/li&gt;
&lt;li&gt;The output is not as rich as in the browser&lt;/li&gt;
&lt;li&gt;Collaboration with non-Emacs users is somewhat complicated&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Separation of kernels, server, and client together with non-blocking JavaScript-based UI is a good argument for using Jupyter. And it certainly won&amp;rsquo;t be a problem for a browser to suddenly print a line a million characters long.&lt;/p&gt;
&lt;p&gt;As for the richness of the output, while there are ways to work around the limitations of Emacs there, in some cases the best thing one can do is open the output in question with a browser. I&amp;rsquo;ll discuss doing that further below.&lt;/p&gt;
&lt;p&gt;The collaboration issue can be alleviated with rich export capabilities, but if someone wants to change something in your Org file, execute it and send it back to you, they have to use Emacs.&lt;/p&gt;
&lt;h2 id=&#34;basic-setup&#34;&gt;Basic setup&lt;/h2&gt;
&lt;p&gt;The core package to this whole venture is &lt;a href=&#34;https://github.com/nnicandro/emacs-jupyter&#34;&gt;emacs-jupyter&lt;/a&gt; (another notable alternative &lt;a href=&#34;https://github.com/millejoh/emacs-ipython-notebook&#34;&gt;ein&lt;/a&gt;, using which can help with the collaboration problem).&lt;/p&gt;
&lt;p&gt;Install it however you install packages in Emacs, here is my preferred way with &lt;code&gt;use-package&lt;/code&gt; and &lt;code&gt;straight.el&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;jupyter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, we have to enable languages for &lt;code&gt;org-babel&lt;/code&gt;. Put the following in your org mode config section:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;org-babel-do-load-languages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;org-babel-load-languages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;emacs-lisp&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;) &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Other languages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;shell&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Python &amp;amp; Jupyter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;python&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;jupyter&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, you should be able to use source blocks with names like &lt;code&gt;jupyter-LANG&lt;/code&gt;, e.g. &lt;code&gt;jupyter-python&lt;/code&gt;. To use just &lt;code&gt;LANG&lt;/code&gt; src blocks, call the following function after &lt;code&gt;org-babel-do-load-languages&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;org-babel-jupyter-override-src-block&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;python&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That overrides the built-in &lt;code&gt;python&lt;/code&gt; block with &lt;code&gt;jupyter-python&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you use &lt;a href=&#34;https://github.com/astahlman/ob-async&#34;&gt;ob-async&lt;/a&gt;, you have to set &lt;code&gt;jupyter-LANG&lt;/code&gt; blocks as ignored by this package, because emacs-jupyter has async execution of its own.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;ob-async-no-async-languages-alist&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;python&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;jupyter-python&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;environments&#34;&gt;Environments&lt;/h2&gt;
&lt;p&gt;So, we&amp;rsquo;ve set up a basic emacs-jupyter configuration.&lt;/p&gt;
&lt;p&gt;The catch here is that Jupyter should be available on Emacs startup (at the time of evaluation of the &lt;code&gt;emacs-jupyter&lt;/code&gt; package, to be precise). That means, if you are launching Emacs with something like an application launcher, global Python &amp;amp; Jupyter will be used.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;sys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sys&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;executable
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/usr/bin/python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which is probably not what we want. To resolve that, we have to make the right Python available at the required time.&lt;/p&gt;
&lt;h3 id=&#34;anaconda&#34;&gt;Anaconda&lt;/h3&gt;
&lt;p&gt;If you were using Jupyter Lab or Notebook before, there is a good chance you install it via &lt;a href=&#34;https://anaconda.org/&#34;&gt;Anaconda&lt;/a&gt;. If not, in a nutshell, it is a package &amp;amp; environment manager, which specializes in Python &amp;amp; R, but also supports a whole lot of stuff like Node.js. In my opinion, it is the easiest way to manage multiple Python installations if you don&amp;rsquo;t use some advanced package manager like Guix.&lt;/p&gt;
&lt;p&gt;As one may expect, there is an Emacs package called &lt;a href=&#34;https://github.com/necaris/conda.el&#34;&gt;conda.el&lt;/a&gt; to help working with conda environments in Emacs. We have to put it somewhere before the &lt;code&gt;emacs-jupyter&lt;/code&gt; package and call &lt;code&gt;conda-env-activate&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;conda&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;conda-anaconda-home&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/Programs/miniconda3/&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;conda-env-home-directory&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/Programs/miniconda3/&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;conda-env-subdirectory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;envs&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;getenv&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;CONDA_DEFAULT_ENV&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;conda-env-activate&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;base&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you have Anaconda installed on a custom path, as I do, you&amp;rsquo;d have to add these &lt;code&gt;setq&lt;/code&gt; lines in the &lt;code&gt;:config&lt;/code&gt; section. Also, there is no point in activating the environment if Emacs is somehow already launched in an environment.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;ll give us Jupyter from a base conda environment.&lt;/p&gt;
&lt;p&gt;If you use a plain virtual environment, you can use &lt;a href=&#34;https://github.com/porterjamesj/virtualenvwrapper.el&#34;&gt;virtualenvwrapper.el&lt;/a&gt;, which is similar in its design to conda.el (or, rather, the other way round).&lt;/p&gt;
&lt;h3 id=&#34;switching-an-environment&#34;&gt;Switching an environment&lt;/h3&gt;
&lt;p&gt;However, as you will notice rather soon, &lt;code&gt;emacs-jupyter&lt;/code&gt; will always use the Python kernel found on startup. So if you switch to a new environment, the code will still be running in the old one, which is not too convenient.&lt;/p&gt;
&lt;p&gt;Fortunately, to fix that we have only to force the refresh of Jupyter kernelspecs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/jupyter-refresh-kernelspecs&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Refresh Jupyter kernelspecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;jupyter-available-kernelspecs&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Calling &lt;code&gt;M-x my/jupyter-refresh-kernelspecs&lt;/code&gt; after an environment switch will give you a new kernel. Just keep in mind that a kernelspec seems to be attached to a session, so you&amp;rsquo;d also have to change the session name to get a new kernel.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;sys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sys&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;executable
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/home/pavel/Programs/miniconda3/bin/python
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;conda-env-activate&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;ann&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;sys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sys&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;executable
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/home/pavel/Programs/miniconda3/bin/python
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;my/jupyter-refresh-kernelspecs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;sys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sys&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;executable
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/home/pavel/Programs/miniconda3/envs/ann/bin/python
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;programming&#34;&gt;Programming&lt;/h2&gt;
&lt;p&gt;To test if everything is working correctly, run &lt;code&gt;M-x jupyter-run-repl&lt;/code&gt;, which should give you a REPL with a chosen kernel. If so, we can finally start using Python in org mode.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src python :session hello :async yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&amp;#39;Hello, world!&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+RESULTS:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: Hello, world!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To avoid repeating similar arguments for the src block, we can set the &lt;code&gt;header-args&lt;/code&gt; property at the start of the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+PROPERTY: header-args:python :session hello
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+PROPERTY: header-args:python+ :async yes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When a kernel is initialized, an associated REPL buffer is also created with a name like &lt;code&gt;*jupyter-repl[python 3.9.2]-hello*&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One advantage of emacs-jupyter over the standard Org source execution is that kernel requests for input are queried through the minibuffer. So, you can run a code like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = input(&amp;#39;Name: &amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(f&amp;#39;Hello, {name}!&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+RESULTS:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: Hello, Pavel!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;without any additional setup.&lt;/p&gt;
&lt;h2 id=&#34;code-output&#34;&gt;Code output&lt;/h2&gt;
&lt;h3 id=&#34;images&#34;&gt;Images&lt;/h3&gt;
&lt;p&gt;Image output should work out of the box. Run &lt;code&gt;M-x org-toggle-inline-images&lt;/code&gt; (&lt;code&gt;C-c C-x C-v&lt;/code&gt;) after the execution to see the image inline.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import matplotlib.pyplot as plt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fig, ax = plt.subplots()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pass
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+RESULTS:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[file:./.ob-jupyter/86b3c5e1bbaee95d62610e1fb9c7e755bf165190.png]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is some room for improvement though. First, you can add the following hook if you don&amp;rsquo;t want to press this awkward keybinding every time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;org-babel-after-execute-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;org-redisplay-inline-images&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Second, we may override the image save path like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src python :file img/hello.png
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import matplotlib.pyplot as plt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fig, ax = plt.subplots()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pass
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+RESULTS:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[file:img/hello.png]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That can save you a &lt;code&gt;savefig&lt;/code&gt; call if the image has to be used somewhere further.&lt;/p&gt;
&lt;p&gt;Finally, by default, the image has a transparent background and a ridiculously small size. That can be fixed with some matplotlib settings:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;matplotlib&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;mpl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mpl&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;rcParams[&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;figure.dpi&amp;#39;&lt;/span&gt;] &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mpl&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;rcParams[&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;figure.facecolor&amp;#39;&lt;/span&gt;] &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At the same time, we can set the image width to prevent images from becoming too large. I prefer to do it inside a &lt;code&gt;emacs-lisp&lt;/code&gt; code block in the same org file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-image-actual-width&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;1024&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;basic-tables&#34;&gt;Basic tables&lt;/h3&gt;
&lt;p&gt;If you are evaluating something like pandas DataFrame, it will be outputted in the HTML format, wrapped in the &lt;code&gt;begin_export&lt;/code&gt; block. To view the data in text format, you can set &lt;code&gt;:display plain&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src python :display plain
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import pandas as pd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pd.DataFrame({&amp;#34;a&amp;#34;: [1, 2], &amp;#34;b&amp;#34;: [3, 4]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+RESULTS:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: a b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: 0 1 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: 1 2 4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another solution is to use something like the &lt;a href=&#34;https://pypi.org/project/tabulate/&#34;&gt;tabulate&lt;/a&gt; package:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import pandas as pd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import tabulate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;df = pd.DataFrame({&amp;#34;a&amp;#34;: [1, 2], &amp;#34;b&amp;#34;: [3, 4]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(tabulate.tabulate(df, headers=df.columns, tablefmt=&amp;#34;orgtbl&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+RESULTS:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: | | a | b |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: |----+-----+-----|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: | 0 | 1 | 3 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: | 1 | 2 | 4 |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;html-and-other-rich-output&#34;&gt;HTML &amp;amp; other rich output&lt;/h3&gt;
&lt;p&gt;Yet another solution is to use emacs-jupyter&amp;rsquo;s option &lt;code&gt;:pandoc t&lt;/code&gt;, which invokes pandoc to convert HTML, LaTeX, and Markdown to Org. Predictably, this is slower than the options above.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+begin_src python :pandoc t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import pandas as pd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;df = pd.DataFrame({&amp;#34;a&amp;#34;: [1, 2], &amp;#34;b&amp;#34;: [3, 4]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;df
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+end_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+RESULTS:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:RESULTS:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| | a | b |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|---+---+---|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 0 | 1 | 3 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 1 | 2 | 4 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:END:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also, every once in a while I have to view an actual, unconverted HTML in a browser, e.g. when using &lt;a href=&#34;https://python-visualization.github.io/folium/&#34;&gt;folium&lt;/a&gt; or &lt;a href=&#34;https://spacy.io/usage/visualizers&#34;&gt;displaCy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To do that, I&amp;rsquo;ve written a small function, which performs &lt;code&gt;xdg-open&lt;/code&gt; on the HTML export block under the cursor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/org-view-html-tmp-dir&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/tmp/org-html-preview/&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/org-view-html&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-at-point&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;temp-file-path&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/org-view-html-tmp-dir&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;number-to-string&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;random&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expt&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;32&lt;/span&gt;))) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.html&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;cond&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;export-block&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Not in an export block!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;string-equal&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;plist-get&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)) &lt;span style=&#34;color:#008000&#34;&gt;:type&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;HTML&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Export block is not HTML!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;progn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f-mkdir&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/org-view-html-tmp-dir&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f-write&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;plist-get&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)) &lt;span style=&#34;color:#008000&#34;&gt;:value&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;utf-8&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;temp-file-path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;org-html-preview&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;xdg-open&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;temp-file-path&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;f.el&lt;/code&gt; is used by a lot of packages, including the above-mentioned &lt;code&gt;conda.el&lt;/code&gt;, so you probably already have it installed.&lt;/p&gt;
&lt;p&gt;Put a cursor on the &lt;code&gt;begin_export html&lt;/code&gt; block and run &lt;code&gt;M-x my/org-view-html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There also &lt;a href=&#34;https://github.com/nnicandro/emacs-jupyter#building-the-widget-support-experimental&#34;&gt;seems to be widgets support&lt;/a&gt; in emacs-jupyter, but I wasn&amp;rsquo;t able to make it work.&lt;/p&gt;
&lt;h3 id=&#34;dataframes&#34;&gt;DataFrames&lt;/h3&gt;
&lt;p&gt;Last but not least option I want to mention here is specifically about pandas&amp;rsquo; DataFrames. There aren&amp;rsquo;t many good options to view the full dataframe inside Emacs. One way I can think of is to save the dataframe in CSV and view it with &lt;code&gt;csv-mode&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, there are standalone packages to view dataframes. One I can point out is &lt;a href=&#34;https://github.com/man-group/dtale&#34;&gt;dtale&lt;/a&gt;, which is a Flask + React app designed just for that purpose. It has a rather extensive list of features, including charting, basic statistical instruments, filters, etc. &lt;a href=&#34;http://alphatechadmin.pythonanywhere.com/dtale/main/1&#34;&gt;Here&lt;/a&gt; is an online demo.&lt;/p&gt;
&lt;p&gt;The problem here is that it&amp;rsquo;s a browser app, which means it defies one of the purposes of using Org Mode in the first place. What&amp;rsquo;s more, this application is a rather huge one with lots of dependencies, and they have to be installed in the same environment as your project.&lt;/p&gt;
&lt;p&gt;So this approach has its pros and cons as well. Example usage is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;dtale&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; dtale&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;show(df)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;open_browser() &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Or get an URL from d._url&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another notable alternative is &lt;a href=&#34;https://github.com/adamerose/pandasgui&#34;&gt;PandasGUI&lt;/a&gt;, which, as one can guess, is a GUI (PyQt5) application, although it uses QtWebEngine inside.&lt;/p&gt;
&lt;h2 id=&#34;remote-kernels&#34;&gt;Remote kernels&lt;/h2&gt;
&lt;p&gt;There are yet some problems in the current configuration.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Input/output handling is far from perfect. For instance, (at least in my configuration) Emacs tends to get slow for log-like outputs, e.g. Keras with &lt;code&gt;verbose=2&lt;/code&gt;. It may even hang if the output is one long line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ipdb&lt;/code&gt; behaves awkwardly if called from an &lt;code&gt;src&lt;/code&gt; block, although it at least will let you type &lt;code&gt;quit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Whenever you close Emacs, kernels are stopped, so you&amp;rsquo;d have to execute the code again on the next start.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;using-a-remote-kernel&#34;&gt;Using a &amp;ldquo;remote&amp;rdquo; kernel&lt;/h3&gt;
&lt;p&gt;For the reasons above I sometimes prefer to use a standalone kernel. To start a Jupyter kernel, run the following command in the environment and path you need:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jupyter kernel --kernel&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;python
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After the kernel is launched, write the path to the connection file into the &lt;code&gt;:session&lt;/code&gt; header and press &lt;code&gt;C-c C-c&lt;/code&gt; to refresh the setup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+PROPERTY: header-args:python :session /home/pavel/.local/share/jupyter/runtime/kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now python source blocks should be executed in the kernel.&lt;/p&gt;
&lt;p&gt;To open a REPL, run &lt;code&gt;M-x jupyter-connect-repl&lt;/code&gt; and select the given JSON. Or launch a standalone REPL like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jupyter qtconsole --existing kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Executing a piece of code in the REPL allows proper debugging, for instance with &lt;code&gt;%pdb&lt;/code&gt; magic. Also, Jupyter QtConsole generally handles large outputs better and even allows certain kinds of rich output in the REPL.&lt;/p&gt;
&lt;h3 id=&#34;some-automation&#34;&gt;Some automation&lt;/h3&gt;
&lt;p&gt;Now, I wouldn&amp;rsquo;t use Emacs if it wasn&amp;rsquo;t possible to automate at least some of the listed steps. So here are the functions I&amp;rsquo;ve written for that.&lt;/p&gt;
&lt;p&gt;First, we need to get open ports on the system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/get-open-ports&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;string-to-number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;split-string&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;shell-command-to-string&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;ss -tulpnH | awk &amp;#39;{print $5}&amp;#39; | sed -e &amp;#39;s/.*://&amp;#39;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, list the available kernel JSONs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/jupyter-runtime-folder&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;~/.local/share/jupyter/runtime&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/list-jupyter-kernel-files&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;mapcar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;cons&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;assq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;shell_port&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;json-read-file&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;sort&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;directory-files-and-attributes&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/jupyter-runtime-folder&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.*kernel.*json$&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;y&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;time-less-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;y&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And query the user for a running kernel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/select-jupyter-kernel&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;ports&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/get-open-ports&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;files&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/list-jupyter-kernel-files&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;completing-read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Jupyter kernels: &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;member&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;ports&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;files&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After which we can use the &lt;code&gt;my/select-jupyter-kernel&lt;/code&gt; function however we want:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/insert-jupyter-kernel&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Insert a path to an active Jupyter kernel into the buffer&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;insert&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/select-jupyter-kernel&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/jupyter-connect-repl&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Open emacs-jupyter REPL, connected to a Jupyter kernel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;jupyter-connect-repl&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/select-jupyter-kernel&lt;/span&gt;) &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/jupyter-qtconsole&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Open Jupyter QtConsole, connected to a Jupyter kernel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;jupyter-qtconsole&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;setsid&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;jupyter&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;qtconsole&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--existing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;file-name-nondirectory&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/select-jupyter-kernel&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first function, which simply inserts the path to the kernel, is meant to be used on the &lt;code&gt;:session&lt;/code&gt; header. One can go even further and locate the header automatically, but that&amp;rsquo;s an idea for next time.&lt;/p&gt;
&lt;p&gt;The second one opens a REPL provided by emacs-jupyter. The &lt;code&gt;t&lt;/code&gt; argument is necessary to pop up the REPL immediately.&lt;/p&gt;
&lt;p&gt;The last one launches Jupyter QtConsole. &lt;code&gt;setsid&lt;/code&gt; is required to run the program in a new session, so it won&amp;rsquo;t close together with Emacs.&lt;/p&gt;
&lt;h3 id=&#34;cleaning-up&#34;&gt;Cleaning up&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve also noticed that there are JSON files left in the runtime folder whenever the kernel isn&amp;rsquo;t stopped correctly. So here is a cleanup function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/jupyter-cleanup-kernels&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;ports&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/get-open-ports&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;files&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/list-jupyter-kernel-files&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;to-delete&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;member&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;cdr&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;ports&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;files&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;length&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;to-delete&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;y-or-n-p&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Delete %d files?&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;to-delete&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;to-delete&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;delete-file&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;file&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;export&#34;&gt;Export&lt;/h2&gt;
&lt;p&gt;An uncountable number of articles have been written already on the subject of Org Mode export, so I will just cover my particular setup.&lt;/p&gt;
&lt;h3 id=&#34;html&#34;&gt;HTML&lt;/h3&gt;
&lt;p&gt;Export to a standalone HTML is an easy way to share the code with someone who doesn&amp;rsquo;t use Emacs, just remember that HTML may not be the only file you&amp;rsquo;d have to share if you have images in the document. Although you may use something like &lt;a href=&#34;https://github.com/BitLooter/htmlark&#34;&gt;htmlark&lt;/a&gt; later to get a proper self-contained HTML.&lt;/p&gt;
&lt;p&gt;To do the export, run &lt;code&gt;M-x org-html-export-to-html&lt;/code&gt;. It should work out of the box, however, we can improve the output a bit.&lt;/p&gt;
&lt;p&gt;First, we can add a custom CSS to the file. I like this one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+HTML_HEAD: &amp;lt;link rel=&amp;#34;stylesheet&amp;#34; type=&amp;#34;text/css&amp;#34; href=&amp;#34;https://gongzhitaao.org/orgcss/org.css&amp;#34;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To get a syntax highlighting, we need the &lt;code&gt;htmlize&lt;/code&gt; package:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;htmlize&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;ox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-html-htmlize-output-type&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;css&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you use the &lt;a href=&#34;https://github.com/Fanael/rainbow-delimiters&#34;&gt;rainbow-delimeters&lt;/a&gt; package, as I do, default colors for delimiters may not look good with the light theme. To fix such issues, put an HTML snippet like this in a &lt;code&gt;begin_export html&lt;/code&gt; block or a CSS file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;style&lt;/span&gt; &lt;span style=&#34;color:#7d9029&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;org-rainbow-delimiters-depth-1&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt; .&lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;org-rainbow-delimiters-depth-2&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt; .&lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;org-rainbow-delimiters-depth-3&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt; .&lt;span style=&#34;color:#00f;font-weight:bold&#34;&gt;org-rainbow-delimiters-depth-4&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;black&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;latex-pdf&#34;&gt;LaTeX -&amp;gt; pdf&lt;/h3&gt;
&lt;p&gt;Even though I use LaTeX quite extensively, I don&amp;rsquo;t like to add another layer of complexity here and 98% of the time write plain &lt;code&gt;.tex&lt;/code&gt; files. LaTeX by itself provides many good options whenever you need to write a document together with some data or source code, contrary to &amp;ldquo;traditional&amp;rdquo; text processors.&lt;/p&gt;
&lt;p&gt;Nevertheless, I want to get at least a tolerable pdf from Org, so here is a piece of my config with some inline comments.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/setup-org-latex&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-latex-compiler&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;xelatex&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Probably not necessary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-latex-pdf-process&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;latexmk -outdir=%o %f&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Use latexmk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-latex-listings&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;minted&lt;/span&gt;) &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Use minted to highlight source code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-latex-minted-options&lt;/span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Some minted options I like&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;breaklines&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tabsize&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;autogobble&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;linenos&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;numbersep&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;0.5cm&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;xleftmargin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;1cm&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;frame&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;single&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Use extarticle without the default packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;org-latex-classes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;org-plain-extarticle&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\documentclass{extarticle}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;[NO-DEFAULT-PACKAGES]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;[PACKAGES]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;[EXTRA]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\section{%s}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\section*{%s}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\subsection{%s}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\subsection*{%s}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\subsubsection{%s}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\subsubsection*{%s}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\paragraph{%s}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\paragraph*{%s}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\subparagraph{%s}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;\\subparagraph*{%s}&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; Make sure to eval the function when org-latex-classes list already exists&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;with-eval-after-load&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;ox-latex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;my/setup-org-latex&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the document itself, add the following headers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+LATEX_CLASS: org-plain-extarticle
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+LATEX_CLASS_OPTIONS: [a4paper, 14pt]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;14pt size is required by certain state standards of ours for some reason.&lt;/p&gt;
&lt;p&gt;After which you can put whatever you want in the preamble with &lt;code&gt;LATEX_HEADER&lt;/code&gt;. My workflow with LaTeX is to write a bunch of &lt;code&gt;.sty&lt;/code&gt; files beforehand and import the necessary ones in the preamble. &lt;a href=&#34;https://github.com/SqrtMinusOne/LaTeX_templates&#34;&gt;Here&lt;/a&gt; is the repo with these files, although quite predictably, it&amp;rsquo;s a mess. At any rate, I have to write something like the following in the target Org file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+LATEX_HEADER: \usepackage{styles/generalPreamble}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+LATEX_HEADER: \usepackage{styles/reportFormat}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+LATEX_HEADER: \usepackage{styles/mintedSourceCode}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#+LATEX_HEADER: \usepackage{styles/russianLocale}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;M-x org-latex-export-to-latex&lt;/code&gt; should export the document to the .tex file. As an alternative, run &lt;code&gt;M-x org-export-dispatch&lt;/code&gt; (by default should be on &lt;code&gt;C-c C-e&lt;/code&gt;) an pick the required option there.&lt;/p&gt;
&lt;h3 id=&#34;ipynb&#34;&gt;ipynb&lt;/h3&gt;
&lt;p&gt;One last export backend I want to mention is &lt;a href=&#34;https://github.com/jkitchin/ox-ipynb&#34;&gt;ox-ipynb&lt;/a&gt;, which allows exporting Org documents to Jupyter notebooks. Sometimes it works, sometimes it doesn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Also, the package isn&amp;rsquo;t on MELPA, so you have to install it from the repo directly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;ox-ipynb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;jkitchin/ox-ipynb&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;ox&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To (try to) do export, run &lt;code&gt;M-x ox-ipynb-export-org-file-ipynb-file&lt;/code&gt;.&lt;/p&gt;
</content>
</item>
<item>
<title>Multiple Gmail accounts &amp; labels with Emacs</title>
<link>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</link>
<pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/2021-02-27-gmail/</guid>
<content type="html">
&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;
&lt;p&gt;For quite some time, e-mail seemed like an anomaly in my workflow. I am a long time Gmail user, and my decade-old account has a somewhat formidable quantity of labels and filters. My messages are often assigned multiple labels, and I also like to keep only a bunch of messages in the inbox.&lt;/p&gt;
&lt;p&gt;Although, in my opinion, Gmail web UI was and still is leagues ahead of many of its competitors and even allows keyboard-centric workflow, it&amp;rsquo;s awkward to use with a keyboard-driven browser, and for no money on Earth I would enable browser notifications.&lt;/p&gt;
&lt;p&gt;Any classical IMAP/SMTP client is hard to use in my case, because a message with multiple labels is copied to IMAP folders for each of the label plus the inbox folder, and the copies look like different messages from the client-side. For example, a message can be read in one label and unread in another.&lt;/p&gt;
&lt;p&gt;For a few years, my solution was &lt;a href=&#34;https://getmailspring.com/&#34;&gt;Mailspring&lt;/a&gt;, which provides first-class support for labels. However, it has a feature to deploy &lt;a href=&#34;https://www.bbc.com/news/technology-56071437&#34;&gt;spy pixels&lt;/a&gt; on emails (and offers no protection from them, obviously), the client is Electron-based with a mouse-driven interface, and the sync engine was closed-source at the time.&lt;/p&gt;
&lt;p&gt;So, I found an alternative in Emacs+notmuch+lieer and ditched one more proprietary app (the last big one I can&amp;rsquo;t let go of is DataGrip).&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/images/gmail/main.png&#34;&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/images/gmail/mail.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Notmuch&amp;rsquo;s tags are just as advanced as Gmail&amp;rsquo;s labels, so I have basically the same mail structure accessible from Emacs, Gmail Android client and even the web UI when I don&amp;rsquo;t have access to the first two.&lt;/p&gt;
&lt;p&gt;Also, I think the setup I describe here is pretty straightforward and less complex than many I encountered, but my impression is not the most reliable source of such knowledge.&lt;/p&gt;
&lt;p&gt;In any case, what follows is a description of my current workflow with instructions of varying levels of precision of how to get there.&lt;/p&gt;
&lt;h2 id=&#34;setting-up&#34;&gt;Setting up&lt;/h2&gt;
&lt;h3 id=&#34;gmail&#34;&gt;Gmail&lt;/h3&gt;
&lt;p&gt;Before we start, some setup is required for the Gmail account.&lt;/p&gt;
&lt;p&gt;First, as there is no way to enable SMTP without IMAP on Gmail, you have to set &amp;ldquo;Enable IMAP&amp;rdquo; in the &amp;ldquo;Forwarding and POP/IMAP&amp;rdquo; tab in the settings. If you use two-factor auth, generate an &lt;a href=&#34;https://support.google.com/accounts/answer/185833?hl=en&#34;&gt;app password&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, make sure your labels do not contain whitespaces because if they do, you will have to type them in quotes all the time.&lt;/p&gt;
&lt;h3 id=&#34;lieer&#34;&gt;lieer&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/gauteh/lieer&#34;&gt;lieer&lt;/a&gt; (formerly gmailieer) is a program that uses Gmail API to download email and synchronize Gmail labels with notmuch tags. Because of its usage of Gmail API instead of IMAP, there are no problems with duplicating emails in different labels, etc.&lt;/p&gt;
&lt;p&gt;As I need to use multiple versions of Python &amp;amp; Node.js for other reasons, I manage my installations of them with &lt;a href=&#34;https://anaconda.org&#34;&gt;Anaconda&lt;/a&gt; (Miniconda, to be precise). You may instead use &lt;a href=&#34;https://docs.python.org/3/library/venv.html&#34;&gt;venv&lt;/a&gt; or even the system-wide installation of Python and omit the &lt;code&gt;conda&lt;/code&gt; clauses, but in my experience Anaconda makes life easier in that regard.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Create an environment with the name &amp;#34;mail&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conda create --name mail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Activate the environment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conda activate mail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Install Python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conda install python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Download and install lieer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/gauteh/lieer.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; lieer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After which we may check if the &lt;code&gt;gmi&lt;/code&gt; executable is available:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;which gmi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/home/pavel/Programs/miniconda3/envs/mail/bin/gmi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;notmuch&#34;&gt;Notmuch&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://notmuchmail.org/&#34;&gt;Notmuch&lt;/a&gt; is present in most of the package repositories, so you can install it with your package manager, which is &lt;code&gt;pacman&lt;/code&gt; in my case.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo pacman -S notmuch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After the installation, run &lt;code&gt;notmuch setup&lt;/code&gt;. That will inquire the parameters and create the &lt;code&gt;.notmuch-config&lt;/code&gt; file with the answers.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Your full name &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;Pavel&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;: Pavel Korytov
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Your primary email address &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;pavel@pdsk.&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;none&lt;span style=&#34;color:#666&#34;&gt;)]&lt;/span&gt;: thexcloud@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Additional email address &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;Press &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;Enter&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; none&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Top-level directory of your email archive &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;/home/pavel/mail&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;: /home/pavel/Mail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Tags to apply to all new messages &lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;separated by spaces&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;unread inbox&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;: new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Tags to exclude when searching messages &lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;separated by spaces&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;deleted spam&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is important to set the &lt;code&gt;new&lt;/code&gt; tag for the new messages instead of the default &lt;code&gt;unread&lt;/code&gt; and &lt;code&gt;inbox&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, add the rule to ignore JSON files to the &lt;code&gt;[new]&lt;/code&gt; section of the &lt;code&gt;.notmuch-config&lt;/code&gt; file, so it would look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;new&lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;tags&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;ignore&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;/.*&lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt;.&lt;span style=&#34;color:#666&#34;&gt;](&lt;/span&gt;json|lock|bak&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;$/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That is needed to ignore the lieer config files. Although, as I have noticed, notmuch is generally pretty good at detecting wrong files in its directories, an explicit ignore rule won&amp;rsquo;t hurt.&lt;/p&gt;
&lt;p&gt;Now, create the mail directory and run the &lt;a href=&#34;https://notmuchmail.org/manpages/notmuch-new-1/&#34;&gt;notmuch new&lt;/a&gt; command. As notmuch has probably already noticed you, it uses the &lt;a href=&#34;https://en.wikipedia.org/wiki/Maildir&#34;&gt;maildir&lt;/a&gt; format, which basically means that one message is stored in one file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# The same directory mentioned in the 4th question&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir ~/Mail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Initialize notmuch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;notmuch new
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;add-an-account&#34;&gt;Add an account&lt;/h3&gt;
&lt;p&gt;After that, we can create a directory for a mail account and initialize lieer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ~/Mail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Use whatever name you want&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir thexcloud
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; thexcloud
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Intialize lieer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gmi init thexcloud@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running &lt;code&gt;gmi init&lt;/code&gt; will run an OAuth authentication to your Gmail account. The credentials will be stored in &lt;code&gt;.credentials.gmailieer.json&lt;/code&gt; file, so make sure not to expose it somewhere.&lt;/p&gt;
&lt;p&gt;We also can add a few settings for lieer, which will make life easier. First, dots seem to be less awkward to type than slashes for the nested tags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gmi &lt;span style=&#34;color:#008000&#34;&gt;set&lt;/span&gt; --replace-slash-with-dot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, we don&amp;rsquo;t want the &lt;code&gt;new&lt;/code&gt; tag to be pushed back to Gmail&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gmi &lt;span style=&#34;color:#008000&#34;&gt;set&lt;/span&gt; --ignore-tags-local new
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can finally download the mail directory. To initiate the download, run&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gmi sync
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first download can easily take several hours, depending on the size of your email and the speed of your internet connection, but subsequent runs will be much faster.&lt;/p&gt;
&lt;p&gt;The last thing to do here is to add the &lt;code&gt;gmi sync&lt;/code&gt; command to notmuch&amp;rsquo;s &lt;a href=&#34;https://notmuchmail.org/manpages/notmuch-hooks-5/&#34;&gt;pre-new hook&lt;/a&gt;, so that the email will be synchronized on the &lt;code&gt;notmuch new&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Create the hooks folder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/Mail/.notmuch/hooks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Create the file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ~/Mail/.notmuch/hooks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;gt; pre-new &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;eval &amp;#34;$(conda shell.bash hook)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;conda activate mail
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;(cd /home/pavel/Mail/thexcloud/ &amp;amp;&amp;amp; gmi sync)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x pre-new
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Side note: as a hook for &lt;code&gt;conda&lt;/code&gt; tends to be rather slow, I run the &lt;code&gt;gmi&lt;/code&gt; command with system-wide Python as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bc7a00&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bc7a00&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;GMI&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Programs/miniconda3/envs/mail/bin/gmi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; /home/pavel/Mail/thexcloud/ &lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;$GMI&lt;/span&gt; sync&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which doesn&amp;rsquo;t seem to cause any particular trouble in that case.&lt;/p&gt;
&lt;h3 id=&#34;emacs&#34;&gt;Emacs&lt;/h3&gt;
&lt;p&gt;There are plenty of different &lt;a href=&#34;https://notmuchmail.org/frontends/&#34;&gt;frontends&lt;/a&gt; for notmuch (even GUI apps), but the one I&amp;rsquo;m sticking with the Emacs.&lt;/p&gt;
&lt;p&gt;Configuration for Emacs is pretty straightforward, but you probably want to use the notmuch package which came with the system package, because otherwise, you may end up with different versions of frontend and backend.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s how it can be done with &lt;code&gt;use-package&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;notmuch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:ensure&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;notmuch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;notmuch-hello-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#19177c&#34;&gt;display-line-numbers-mode&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The only notable observation here is that &lt;code&gt;display-line-numbers-mode&lt;/code&gt; seems to break formatting of the &lt;code&gt;notmuch-hello&lt;/code&gt; page.&lt;/p&gt;
&lt;p&gt;If you use evil-mode, you also should enable the &lt;a href=&#34;https://github.com/emacs-evil/evil-collection/blob/master/modes/notmuch/evil-collection-notmuch.el&#34;&gt;evil-collection mode for notmuch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now run &lt;code&gt;M-x notmuch&lt;/code&gt; and the &lt;code&gt;notmuch-hello&lt;/code&gt; page should appear. Running &lt;code&gt;notmuch-poll-and-refresh-this-buffer&lt;/code&gt; (&lt;code&gt;gR&lt;/code&gt; with evil bindings) will run the &lt;code&gt;notmuch new&lt;/code&gt; command and refresh the buffer. All the syncronized messages should be present.&lt;/p&gt;
&lt;p&gt;I should note that &lt;a href=&#34;https://notmuchmail.org/notmuch-emacs/&#34;&gt;notmuch frontend for Emacs&lt;/a&gt; is the most user-friendly Emacs app I have seen so far. UI, commands and keybindings are self-descriptive, all the options can be configured with the build-in &lt;code&gt;customize&lt;/code&gt; interface. It may be useful to look through &lt;a href=&#34;https://notmuchmail.org/emacstips/&#34;&gt;emacs tips&lt;/a&gt; at the official site and &lt;a href=&#34;https://notmuchmail.org/manpages/&#34;&gt;notmuch man pages&lt;/a&gt;, in particular &lt;a href=&#34;https://notmuchmail.org/manpages/notmuch-search-terms-7/&#34;&gt;syntax for notmuch queries&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;reading-mail&#34;&gt;Reading mail&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;notmuch-search-show-thread&lt;/code&gt; (&lt;code&gt;RET&lt;/code&gt;) opens the thread under the cursor.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;notmuch-show-view-part&lt;/code&gt; (&lt;code&gt;. v&lt;/code&gt; with evil) opens an attachment with associations defined in &lt;a href=&#34;https://linux.die.net/man/4/mailcap&#34;&gt;.mailcap&lt;/a&gt; file. Mine looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;audio/*; mpc add %s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;image/*; feh %s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;application/msword; /usr/bin/xdg-open %s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;application/pdf; zathura %s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;application/postscript ; zathura %s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;text/html; /usr/bin/xdg-open %s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here watch out for the last line, default version of which may be set as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;text/html; /usr/bin/xdg-open %s ; copiousoutput
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which causes a temporary file to be deleted before it could be opened because recent versions of &lt;code&gt;xdg-open&lt;/code&gt; do not block the input.&lt;/p&gt;
&lt;p&gt;As expected, Emacs mail reader does not trigger any &lt;a href=&#34;https://www.emailprivacytester.com/&#34;&gt;spy pixels or other tracking contents of email&lt;/a&gt; (not any I know of, at least). However, opening an HTML email in a browser will even run embedded JavaScript. Therefore, &lt;strong&gt;in no case open emails you do not trust with &lt;code&gt;xdg-open&lt;/code&gt;&lt;/strong&gt;. Even if you use NoScript, the browser will still load all the CSS, videos and even iframes, which can be used to track you.&lt;/p&gt;
&lt;p&gt;Even Gmail web UI is preferable to view the message in a browser, because the former blocks most of the malicious stuff and does not seem to leak your IP to the sender, for what it&amp;rsquo;s worth.&lt;/p&gt;
&lt;h3 id=&#34;sending-mail&#34;&gt;Sending mail&lt;/h3&gt;
&lt;p&gt;To start composing a message, run &lt;code&gt;notmuch-mua-new-mail&lt;/code&gt; (&lt;code&gt;C&lt;/code&gt; with evil bindings).&lt;/p&gt;
&lt;p&gt;After doing so, &lt;code&gt;C-c C-c&lt;/code&gt; will run &lt;code&gt;notmuch-mua-send-and-exit&lt;/code&gt;, which will invoke the function stated in the &lt;code&gt;message-send-mail-function&lt;/code&gt; variable. The default value of the variable is &lt;code&gt;sendmail-query-once&lt;/code&gt;, which will inquire the parameters and save them as custom variables.&lt;/p&gt;
&lt;p&gt;If SMTP is used, &lt;code&gt;send-mail-function&lt;/code&gt; will be set to the one from the built-it &lt;a href=&#34;https://www.emacswiki.org/emacs/SendingMail&#34;&gt;smtpmail&lt;/a&gt; package. SMTP parameters for Gmail are listed &lt;a href=&#34;https://support.google.com/mail/answer/7126229?hl=en&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Authorization parameters will be saved to your &lt;a href=&#34;https://www.emacswiki.org/emacs/GnusAuthinfo&#34;&gt;authinfo&lt;/a&gt; file. If you didn&amp;rsquo;t have one, the plaintext &lt;code&gt;.authinfo&lt;/code&gt; will be created, so it&amp;rsquo;s reasonable to encrypt it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg -o .authinfo.gpg -c --cipher-algo AES256 .authinfo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, if you plan to use multiple accounts with different SMTP servers, it makes more sense to use something like &lt;a href=&#34;https://marlam.de/msmtp/msmtp.html&#34;&gt;MSMTP&lt;/a&gt; to manage multiple accounts. Here are a couple of examples (&lt;a href=&#34;https://www.reddit.com/r/emacs/comments/9piml5/a_few_quick_emacsnotmuch_questions/e83zcck?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://www.reddit.com/r/emacs/comments/9piml5/a_few_quick_emacsnotmuch_questions/e84otah?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&#34;&gt;2&lt;/a&gt;) how to do that.&lt;/p&gt;
&lt;p&gt;Another alternative for Gmail is to use &lt;a href=&#34;https://github.com/gauteh/lieer/wiki/GNU-Emacs-and-Lieer&#34;&gt;lieer as sendmail program&lt;/a&gt;. That may make sense if you don&amp;rsquo;t want to enable IMAP and SMTP on your account.&lt;/p&gt;
&lt;p&gt;There are also &lt;a href=&#34;https://notmuchmail.org/emacstips/#index13h2&#34;&gt;a bunch of ways&lt;/a&gt; to set up address completion if the built-in completion based on notmuch database does not suffice.&lt;/p&gt;
&lt;p&gt;I also use &lt;a href=&#34;https://github.com/mhayashi1120/Emacs-langtool&#34;&gt;LanguageTool for Emacs&lt;/a&gt; to do a spell checking of important emails (integrations like that really make Emacs shine). For some reason, developers don&amp;rsquo;t give a link to download the server on the frontpage, so &lt;a href=&#34;https://dev.languagetool.org/http-server&#34;&gt;here it is&lt;/a&gt;. And here is the relevant part of my Emacs config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;langtool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;langtool-check&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;langtool-language-tool-server-jar&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Programs/LanguageTool-5.1/languagetool-server.jar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;langtool-mother-tongue&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;ru&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As a last note here, to set up a signature create the &lt;code&gt;.signature&lt;/code&gt; file in the &lt;code&gt;$HOME&lt;/code&gt; directory. If you need more complex logic here, for instance, different signatures for different accounts, you can put an arbitrary expression to the &lt;code&gt;mail-signature&lt;/code&gt; variable or apply &lt;a href=&#34;https://notmuchmail.org/emacstips/#index16h2&#34;&gt;this gnus-alias tip&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;another-account&#34;&gt;Another account&lt;/h2&gt;
&lt;h3 id=&#34;adding-an-account&#34;&gt;Adding an account&lt;/h3&gt;
&lt;p&gt;Now we can send and receive mail from one account. Adding another account is also pretty easy.&lt;/p&gt;
&lt;p&gt;If another account is Gmail, the process starts the same as before:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Create a directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/Mail/progin6304
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ~/Mail/progin6304
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# OAuth&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gmi init progin6304@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gmi &lt;span style=&#34;color:#008000&#34;&gt;set&lt;/span&gt; --replace-slash-with-dot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, before running &lt;code&gt;gmi sync&lt;/code&gt; for the second account, we want to make sure that we can distinguish the message from different accounts. To do that, I add the &lt;code&gt;main&lt;/code&gt; for the main account and &lt;code&gt;progin&lt;/code&gt; for the second account. We also don&amp;rsquo;t want these labels to be pushed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ~/Mail/thexcloud
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gmi &lt;span style=&#34;color:#008000&#34;&gt;set&lt;/span&gt; --ignore-tags-local new,mail,progin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ~/Mail/progin6304
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gmi &lt;span style=&#34;color:#008000&#34;&gt;set&lt;/span&gt; --ignore-tags-local new,mail,progin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can use notmuch&amp;rsquo;s &lt;code&gt;post-new&lt;/code&gt; hook to tag the messages based on their folder as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ~/Mail/.notmuch/hooks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;gt; post-new &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;notmuch tag +main &amp;#34;path:thexcloud/** AND tag:new&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;notmuch tag +progin &amp;#34;path:progin6304/** AND tag:new&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;notmuch tag -new &amp;#34;tag:new&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x post-new
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now it finally makes sense why we wanted to use the &lt;code&gt;new&lt;/code&gt; tag in the first place. In principle, any kind of tagging logic can be applied here, but for the reasons I stated earlier, I prefer to set up filters in the Gmail web interface.&lt;/p&gt;
&lt;p&gt;The last thing to do is to modify the &lt;code&gt;pre-new&lt;/code&gt; hook:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bc7a00&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bc7a00&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;GMI&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Programs/miniconda3/envs/mail/bin/gmi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; /home/pavel/Mail/thexcloud/ &lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;$GMI&lt;/span&gt; sync&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; /home/pavel/Mail/progin6304/ &lt;span style=&#34;color:#666&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;$GMI&lt;/span&gt; sync&lt;span style=&#34;color:#666&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After which we can finally tag the existing messages and download ones from the new account&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;notmuch tag +main &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;path:thexcloud/**&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;notmuch new
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The obvious problem, however, is that the messages are fetched sequentially, which is rather slow. A solution is to use something like &lt;a href=&#34;http://www.gnu.org/software/parallel/&#34;&gt;GNU Parallel&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bc7a00&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bc7a00&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;GMI&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Programs/miniconda3/envs/mail/bin/gmi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;parallel -j0 &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(cd /home/pavel/Mail/{}/ &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$GMI&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; sync)&amp;#34;&lt;/span&gt; ::: thexcloud progin6304
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I haven&amp;rsquo;t encountered any trouble with that solution so far (and I don&amp;rsquo;t see anything thread-unsafe in the lieer code), but I&amp;rsquo;ll keep an eye on that.&lt;/p&gt;
&lt;p&gt;In principle, it shouldn&amp;rsquo;t be too hard to add a normal IMAP account as well with &lt;a href=&#34;https://isync.sourceforge.io/mbsync.html&#34;&gt;mbsync&lt;/a&gt;, but I expect it would require something like iterating through the directory structure and assigning notmuch labels based on that. I&amp;rsquo;ll probably try that some time in the future.&lt;/p&gt;
&lt;h3 id=&#34;emacs&#34;&gt;Emacs&lt;/h3&gt;
&lt;p&gt;With that done, I also want separate entries on the start page for each of the accounts. Doing that is easy enough, just modify the &lt;code&gt;notmuch-saved-searches&lt;/code&gt; variable with &lt;code&gt;customize-group&lt;/code&gt; or like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;notmuch-saved-searches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;inbox (main)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:inbox AND tag:main&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;unread (main)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:unread AND tag:main&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;sent (main)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:sent AND tag:main&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;all mail (main)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:main&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;inbox (progin)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:inbox AND tag:progin&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;unread (progin)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:unread AND tag:progin&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;sent (progin)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:sent AND tag:progin&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;all main (progin)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:progin&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;drafts&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:draft&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;notification-for-new-messages&#34;&gt;Notification for new messages&lt;/h2&gt;
&lt;p&gt;Now, we can send and receive mail, but we also probably want notifications for new emails. To do that, I wrote a simple script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bc7a00&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bc7a00&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# To run notify-send from cron&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;DISPLAY&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;:0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# A file with last time of sync&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;CHECK_FILE&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/home/pavel/Mail/.last_check&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;QUERY&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:unread&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;ALL_QUERY&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:unread&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# If the file exists, check also the new messages from the last sync&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt; -f &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$CHECK_FILE&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;DATE&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;cat &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$CHECK_FILE&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;QUERY&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$QUERY&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt; and date:@&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$DATE&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;..&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;notmuch new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;NEW_UNREAD&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;notmuch count &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$QUERY&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;ALL_UNREAD&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;notmuch count &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$ALL_QUERY&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# I don&amp;#39;t really care if there are unread messages for which I&amp;#39;ve already seen a notification&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;$NEW_UNREAD&lt;/span&gt; -gt &lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;MAIN_UNREAD&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;notmuch count &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:unread AND tag:main&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;PROGIN_UNREAD&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;notmuch count &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;tag:unread AND tag:progin&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;read&lt;/span&gt; -r -d &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; NOTIFICATION &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;lt;&amp;lt;EOM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$NEW_UNREAD new messages
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$MAIN_UNREAD thexcloud@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$PROGIN_UNREAD progin6304@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;$ALL_UNREAD total
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;EOM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; notify-send &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;New Mail&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;$NOTIFICATION&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;# Save sync timestamp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;$(&lt;/span&gt;date +%s&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#19177c&#34;&gt;$CHECK_FILE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The script is launched with cron every 5 minutes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*/5 * * * * bash /home/pavel/bin/scripts/check-email
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s how the notification looks like:
&lt;img src=&#34;https://sqrtminusone.xyz/images/gmail/notification.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;caveats&#34;&gt;Caveats&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gauteh/lieer#caveats&#34;&gt;lieer&lt;/a&gt; has an extensive list of caveats concerning Gmail API&lt;/li&gt;
&lt;li&gt;Make sure that you understand the &lt;a href=&#34;https://github.com/gauteh/lieer#changing-ignored-tags-and-translation-after-initial-sync&#34;&gt;implications&lt;/a&gt; of lieer&amp;rsquo;s &lt;code&gt;--ignore-tags-locally&lt;/code&gt; and &lt;code&gt;--ignore-tags-remote&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If two of your accounts receive the same email, it will be stored as one email in notmuch, so tags from these accounts will be merged and pushed back on the next sync. To solve that, you can set tags from one account to be ignored on the rest of the accounts&lt;/li&gt;
&lt;li&gt;A sent email is being downloaded again on the next sync. Not a great deal, but it is somewhat annoying to download recently sent attachments.&lt;/li&gt;
&lt;/ul&gt;
</content>
</item>
<item>
<title>Hello, world!</title>
<link>https://sqrtminusone.xyz/posts/hello-world/</link>
<pubDate>Mon, 01 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/posts/hello-world/</guid>
<content type="html">
&lt;h2 id=&#34;hello-world&#34;&gt;Hello, world!&lt;/h2&gt;
&lt;p&gt;Eventually, there will be something interesting here. Or not.&lt;/p&gt;
&lt;p&gt;Regradless, I&amp;rsquo;ll check if I can write some Python here&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Hello, world&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello, world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</content>
</item>
</channel>
</rss>